What's Changed
🛡️ Resource not-found handling across all details pages
When a budget, portfolio, account, integration, reminder, or subscription you opened no longer exists (deleted, never existed, or you don't have access), MoneyMatter now shows a clean "resource not found" screen with a way back instead of spinning forever. The query client also stops retrying on 404s, so missing resources fail fast instead of hammering the backend in the background.
🐳 Self-hosting setup overhaul
Self-hosting MoneyMatter is now a documented, supported path. New docs/self-hosting.md walks through every step end-to-end, .env.production.example lists every variable the stack needs, and a dedicated docker-compose.localhost.yml makes it easy to run the full stack on your own machine. The production docker-compose.yml, frontend Dockerfile, nginx config, and entrypoint have all been hardened around real-world self-host usage.
🔐 Streamlined sign-up & auth cleanup
Sign-up is more forgiving when names or usernames collide: duplicates retry automatically with a deterministic suffix, whitespace-only names are rejected cleanly, and orphaned auth records are rolled back when a hook fails so a single bad attempt no longer locks the email out forever. Legacy *@app.migrated accounts and the entire pre-better-auth username login flow have been removed — the login page, recovery dialog, verify-legacy-email route, and /migrate-legacy-email endpoint are all gone. PUT /user/update now validates usernames and returns a proper 422 on collisions instead of a 500.
📝 Validation on the transaction dialog
The "Create / edit transaction" dialog now validates inputs before submitting — required fields, sensible amounts, and matching account/category combinations are checked up front, so you get inline feedback instead of an opaque server error after pressing Save.
📊 Clearer feedback for unsupported securities
When searching for a security to add to a portfolio, types MoneyMatter doesn't yet support (e.g. options, futures) are filtered out at the API level and surfaced clearly in the UI. The "Create portfolio" and "Send feedback" dialogs also call out limited investment types so you know what to expect before saving.
🐛 Bug Fixes & Improvements
- External transfer revert no longer flips the opposite transaction type — reverting an external income→transfer back to income now keeps the system-side expense intact.
- Daily price sync skips weekend-closed and holiday-closed markets instead of churning on them, and still advances
pricingLastSyncedAtfor those symbols so they don't dominate the staleness queue on every run. - Reduced Sentry noise from investment data providers and the combined-balance-history stats path.
- Email sending in dev no longer hits Resend for
@test.localrecipients, preventing Playwright runs from burning real send quota. - Restored backup script's force-drop behavior so DB resets work reliably.
📝 Code Changes
- feat: Improve duplicated usernames handling by @letehaha in #238
- fix: Hide unsupported securities from search by @letehaha in #239
- fix: check holidays for stocks fetching by @letehaha in #241
- fix: Sentry noise by @letehaha in #242
- fix: skip Resend sends to
@test.localrecipients in dev by @letehaha in #245 - feat: Add validation to the tx management form by @letehaha in #246
- fix|feat: Self-hosted setup by @letehaha in #247
- fix: Transaction management dialog by @letehaha in #248
- fix: infinite querying 404 resources by @letehaha in #249
- feat: remove legacy username login flow by @letehaha in #250
- feat: Improve self-hosting guide and setup by @letehaha in #251
Full Changelog: v0.14.3...v0.14.4