Entering a parent's Försäkringskassan balances had no tests at all, despite being how every number in the planner originates and despite it becoming the first thing a new user does. The scraper endpoints are pinned per test rather than read from the ambient configuration, because a local .env sets the flag opposite to the shipped default and a test that trusts it would pass here and fail in CI. Also covered: the hard expiry at twelve, whose rejection path nothing reached and whose boundary turns out to be inclusive; and the dubbeldagar count cap, which now drives past the limit and asserts the days beyond it fall back to a single parent. Two weak assertions were strengthened, including one that derived its expectation from the same response it was checking and so could not have failed on a shared error.
Backend — Föräldraledigplannerare
FastAPI + Python 3.14, packages managed with uv. Layered architecture
(entities → repositories → services → routers) with dependency injection so the
database backend (SQLite now, Postgres later) is swappable.
Setup
uv sync # install deps (incl. dev group)
uv run uvicorn app.main:app --reload # run dev server on :8000
uv run pytest # run tests with coverage
uv run ruff check . # lint
Layout
app/
config.py # pydantic-settings (app config + frozen LeaveRules)
dependencies.py # DI factories (pick repo impl by settings.database_type)
entities/ # plain dataclasses (domain)
models/ # pydantic API schemas
repositories/ # abstract interfaces
repositories_impl/ # concrete impls per backend (sqlite/, postgres/)
services/ # business logic
routers/ # FastAPI routes
db/connection.py # connection + (dev) schema bootstrap
utils/ # errors, logger
Demo data (manual/browser testing)
scripts/seed_demo.py seeds a realistic, ready-to-explore workspace through the
normal service/repository layers (no raw SQL) — a couple workspace with a
partner, a child born ~6 months ago, vacation rows for only some years (so the
is_assumed badge is visible), day overrides, and a spread of leave wishes
(fixed, flexible, and one deliberately underfunded to show a shortfall +
remedies + surplus advice). Login credentials are fixed and printed at the end.
uv run python scripts/seed_demo.py # create once; re-running is a no-op
uv run python scripts/seed_demo.py --reset # wipe the demo workspace and rebuild
Then open http://localhost:5173 and log in with the printed demo@example.com
credentials. Safe to re-run: without --reset it detects the existing demo
user and changes nothing; --reset only ever deletes the one demo workspace.
Reference vertical slice
VacationDays is implemented end-to-end (entity → schema → repo interface →
SQLite impl → service → router → tests). Copy this slice when adding a new
entity. See JUNIOR_ONBOARDING.md in the repo root for task-by-task guidance.
The inline schema in
db/connection.pyexists only so dev/tests are self-contained. Production schema is owned by Alembic migrations (a senior task).