`uv run pytest` reported 26 DeprecationWarnings, 20 of them raised by
code we own. Two independent sources, both already renamed upstream.
Starlette renamed HTTP_422_UNPROCESSABLE_ENTITY to
HTTP_422_UNPROCESSABLE_CONTENT, matching the RFC 9110 name for the
status. Rename all 21 call sites across the twelve routers that raise
it. The numeric value is unchanged at 422, so the wire format and the
frontend's error handling are untouched -- this is forward-compat debt
only. The warnings attributed to fastapi/routing.py were these same
handler frames raising through the dependency call, and go with them.
Alembic >=1.16 supersedes `version_path_separator` with
`path_separator`, which governs both `prepend_sys_path` and
`version_locations`; its absence is what triggered the legacy-splitting
warning on every config load. Swap the key in alembic.ini.
Deliberately not fixing slowapi's `asyncio.iscoroutinefunction` warning
(6 of the 26): it is upstream with no released fix, and no
`filterwarnings` entry is added, so it stays visible as a reminder to
drop the pin once one lands.
Verified from backend/: ruff check and format clean, 893 passed with
coverage at 92%, and the warnings summary is now exactly those 6 slowapi
lines. `alembic upgrade head` runs 001 through 008 without the
path_separator warning.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Security
- Every route now requires a login and refuses ids outside the caller's
workspace with 404: plan, leave-wishes, day-overrides and vacation-days
were fully anonymous; every other router trusted client-supplied
workspace/child/parent ids. Scraper sessions are bound to their owner.
- Invitations can no longer be created for a foreign workspace, and a
redeemer who is already a member (or a full workspace) is refused.
- Production refuses the default JWT secret; API docs are hidden in
production; a failed migration aborts startup instead of serving.
- Login and register no longer reveal whether an email exists; inactive
accounts are rejected; /auth/refresh is rate limited.
- The FK scraper writes debug artefacts only when explicitly enabled,
logs no scraped values or page text, clears the BankID QR as soon as it
is scanned and purges finished sessions after five minutes.
- Real FK page captures are removed from the tree (history rewrite
follows); the parser tests use a synthetic fixture.
Performance and correctness
- Plan apply/sync run inside one locked transaction with batched writes
instead of one commit per row, so a failure mid-batch leaves nothing
half-applied and concurrent syncs no longer corrupt each other.
- SQLite runs in WAL mode with a busy timeout; 14 indexes cover the
filters that were full scans; argon2 hashing runs off the event loop;
responses are gzipped.
- Frontend: a 401 now refreshes the token once and retries, so sessions
no longer die silently after 15 minutes; every data hook discards
stale responses; logout clears state even when the server call fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CsXCCcDfmV4Sps4ZQSvNEY