MSaving

Backend changes

Conventions for API routes, domain code, jobs and errors in msaving/backend.

Where code goes

Layer Folder Holds
core app/core/ Settings, sign-in building blocks, session check, per-request database session, account event log, update check
api app/api/ FastAPI app (web app files, CSP, Origin check), dependencies, error mapping, models, routes/v1/
domain app/domain/ Logic used by routes: transactions, dashboard, export, starter categories
jobs app/jobs/ Migrations runner, scheduler, daily jobs (python -m app.jobs.<name>)
app/launch.py, app/admin.py The container’s start; operator commands

A route should be thin: parse, call domain code or SQL, commit, return.

Route conventions

  • Under /v1. Additive changes only within a version (new fields and routes are fine; removing or renaming isn’t): phones in the stores talk to older and newer servers.
  • Writes call db.commit() in the route before returning.
  • Optimistic concurrency: editable rows take the version the client loaded; mismatch → 409 conflict.
  • Idempotent creates: the client makes the id; saving the same id twice does nothing.
  • Never INSERT ... RETURNING or ON CONFLICT on books: both apply the read policy before the creator is a member.
  • Errors: return {"detail": "<code>"}. Database errors start with a code (owner_required: ...) and app/api/errors.py maps them to a status. A new code needs translations in web/src/i18n/vi.json and en.json. See Error codes.
  • Money: int minor units in Pydantic models. Never float.
  • Timezones: use the Timezone type (app/api/models.py); it maps aliases to names the database knows.
  • Settings: optional, with safe defaults, added to .env.example, both READMEs and Environment variables.
  • Admin-only routes go in routes/v1/admin.py and call a database function that checks require_admin().

Checklist for a new route

  1. Route in app/api/routes/v1/<area>.py, registered with the /v1 router.
  2. Request/response models (ints for money, UUIDs for ids).
  3. Tests in tests/, including another user getting 404/403 (RLS).
  4. A paired PR to the docs (src/content/docs/ in msaving-landing): the route on API routes, and the pages it changes.
  5. If the web app uses it: types in web/src/lib/api.ts, hooks in lib/queries.ts, in the same PR.

Don’t

  • Don’t store balances. They’re sums of entries.
  • Don’t give the API the owner’s login.
  • Don’t log tokens, codes, passwords or transaction contents.

Edit this page · Report a problem