Rework balances around per-parent days left and deduce the partner from FK
Manual entry now takes one parent's sjukpenningnivå, lägstanivå and dubbeldagar left (plus optional reserved days) and derives the rest in build_snapshot, shared with the scraper. The scraper also reads the family panel and exposes a partner deduction; with two parents it is saved as a 'deduced' snapshot (migration 002). Parent count is the single source of entitlement: one member gets 480 days and 96 savable at age 4, two get 240 and 48 each. Workspaces are capped at two parents. Also lands the in-flight squash of migrations 002–011 into the initial schema and the removal of planning_mode. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+46
-3
@@ -1,8 +1,12 @@
|
||||
# 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.
|
||||
(entities → repositories → services → routers) with dependency injection.
|
||||
**Postgres is a partial stub, not a working swap today:** only
|
||||
`repositories_impl/postgres/vacation_days_repository.py` exists; every other
|
||||
`app/dependencies.py` repository factory raises `ValueError` for any
|
||||
`database_type` other than `"sqlite"`. SQLite is the only usable backend
|
||||
until the remaining Postgres repositories land.
|
||||
|
||||
## Setup
|
||||
|
||||
@@ -13,16 +17,55 @@ uv run pytest # run tests with coverage
|
||||
uv run ruff check . # lint
|
||||
```
|
||||
|
||||
`uv run pytest` alone does not enforce a coverage floor (`pyproject.toml`'s
|
||||
`addopts` only requests a report). CI additionally passes
|
||||
`--cov-fail-under=80` (see the root `CLAUDE.md`) — a locally green run can
|
||||
still fail in CI if coverage dropped.
|
||||
|
||||
## Configuration
|
||||
|
||||
Key env vars (prefix `APP_`, see `.env.example`):
|
||||
Env vars (prefix `APP_`, nested via `__`; see `.env.example`). `Settings`
|
||||
lives in `app/config.py` — that file's module docstring mentions a
|
||||
`HMAC_PEPPER` setting; **no such setting exists**, so do not look for it here
|
||||
or set it expecting an effect.
|
||||
|
||||
- `APP_ENV` — `development` (default) | `test` | `production`. In production,
|
||||
`Settings` refuses to start unless `APP_JWT_SECRET` is a random value of at
|
||||
least 32 characters (the shipped dev default is rejected). Production also
|
||||
disables `/docs`, `/redoc`, and `/openapi.json`.
|
||||
- `APP_DATABASE_TYPE` — `sqlite` (default) | `postgres` (not usable yet — see above).
|
||||
- `APP_SQLITE_PATH` — default `./foraldraledig.db`.
|
||||
- `APP_CORS_ORIGINS` — JSON list; default `["http://localhost:5173"]`.
|
||||
- `APP_JWT_SECRET` — required to be a strong, random secret in production.
|
||||
- `APP_JWT_ALGORITHM` — default `HS256`.
|
||||
- `APP_JWT_ACCESS_TOKEN_EXPIRE_MINUTES` — default `15`.
|
||||
- `APP_JWT_REFRESH_TOKEN_EXPIRE_DAYS` — default `7`.
|
||||
- `APP_LOG_LEVEL` — default `INFO`.
|
||||
- `APP_SCRAPER_ENABLED` — **defaults to `true`.** Legal/ToS review of FK scraping + BankID
|
||||
automation completed 2026-06; the scraper is cleared for use. Set to `false` in any
|
||||
environment without Playwright's Chromium installed (`uv run playwright install chromium`).
|
||||
- `APP_SCRAPER_HEADLESS` — default `true`.
|
||||
- `APP_SCRAPER_SESSION_TTL_SECONDS` — default `180`; auto-cancels a stalled scraper session.
|
||||
- `APP_SCRAPER_DEBUG_ENABLED` — default `false`. **When enabled, writes personal data to disk**
|
||||
(an HTML dump + full-page screenshot of the logged-in FK page — name, balances, payout
|
||||
amounts). Requires `APP_SCRAPER_DEBUG_DIR` to also be set. Local debugging only; never enable
|
||||
in a shared or production environment.
|
||||
- `APP_SCRAPER_DEBUG_DIR` — where debug artifacts are written when the above is enabled.
|
||||
- `APP_SCRAPER_DEBUG_DUMP_ON_SUCCESS` — default `false`. Also writes the same debug artifacts
|
||||
(HTML + full-page screenshot) after a **successful** extraction, not just on error — a capture
|
||||
aid for confirming FK's real DOM (e.g. the family panel structure `app/scrapers/fk_scraper.py`
|
||||
currently assumes). Same personal-data warning as `APP_SCRAPER_DEBUG_ENABLED` applies; only
|
||||
takes effect when both `APP_SCRAPER_DEBUG_ENABLED` and `APP_SCRAPER_DEBUG_DIR` are also set.
|
||||
- `APP_SCRAPER_RESULT_RETENTION_SECONDS` — default `300`; how long a finished scraper session's
|
||||
result stays in memory before being purged.
|
||||
- `APP_RULES__*` — the Swedish parental-leave rule constants (`LeaveRules`, nested under `rules`),
|
||||
overridable per field, e.g. `APP_RULES__MAX_SAVABLE_DAYS_AT_AGE_4=96`. Defaults: 390
|
||||
sjukpenning days, 90 lägstanivå days, 90 reserved days/parent, 60 max dubbeldagar over the
|
||||
first 15 months, 96 max savable at age 4 (48 per parent when the child has two or more
|
||||
parents — see `resolve_age4_savable_cap`), age-12 hard expiry, 6 preschool planning days/year,
|
||||
25 statutory vacation days/year, 20 minimum vacation days/year that must be taken. These are
|
||||
common-case figures only — children born before 2014, multiples, and single custody differ and
|
||||
are not modeled.
|
||||
|
||||
## Layout
|
||||
|
||||
|
||||
Reference in New Issue
Block a user