7.0 KiB
Scaffolding Handoff — for the Senior Developer
Goal: finish the project foundation so the rest of the team (especially the junior — see JUNIOR_ONBOARDING.md) can build features by copying an established pattern rather than inventing one.
Read first: ARCHITECTURE.md (the full design, with section numbers referenced throughout this doc).
1. What's already scaffolded
A backend reference vertical slice is in place under backend/. It implements one entity (VacationDays) end-to-end so every layer and the cross-cutting patterns are demonstrated:
backend/
pyproject.toml # uv project; Python >=3.14; fastapi, pydantic, pydantic-settings, aiosqlite; dev: pytest(+asyncio,+cov), ruff, httpx
app/
config.py # pydantic-settings: app config + nested frozen LeaveRules (480/390/96/60... rule defaults)
dependencies.py # DI factories — pick repo impl by settings.database_type
main.py # FastAPI app, lifespan opens DB connection, CORS locked to frontend origin
db/connection.py # connect() + ensure_schema() (inline DDL is DEV-ONLY; see §3a)
utils/errors.py # DomainError hierarchy (NotFound/Validation/InsufficientDays/...)
entities/vacation_days.py # plain dataclass (domain)
models/vacation_days.py # pydantic API schemas (+ from_entity mapper)
repositories/base.py # abstract Repository[T] (CRUD contract)
repositories/vacation_days_repository.py # abstract, entity-specific queries
repositories_impl/sqlite/vacation_days_repository.py # concrete SQLite impl (REFERENCE)
services/vacation_days_service.py # business logic (upsert/get/list)
routers/vacation_days.py # thin HTTP layer, maps domain errors -> HTTP
tests/
conftest.py # in-memory SQLite fixtures (connection/repo/service)
unit/test_vacation_days_repository.py # repo + service tests
Status / caveat: every .py file compiles, and the tests are written to pass, but they were not executed in the authoring environment (no network to install Python 3.14). Please run them first thing:
cd backend
uv sync
uv run pytest # expect the VacationDays repo+service tests to pass
uv run ruff check .
If anything fails, it's almost certainly an environment/version detail — the logic has been reviewed.
2. Conventions to preserve
The slice encodes these on purpose. Keeping them consistent is what makes the codebase safe to hand to a junior:
- Dependency direction: routers → services → repository interfaces. Nothing above the repo layer imports a concrete DB class.
- Repositories: abstract interface in
repositories/, one concrete impl per backend inrepositories_impl/<backend>/. Map rows ↔ entities explicitly; always parameterize SQL. - Services own business rules; repositories only persist; routers only translate HTTP ↔ domain and map
DomainErrorsubclasses to status codes. - Entities are plain dataclasses; API schemas are pydantic models kept separate from entities.
- Errors: raise
DomainErrorsubclasses (utils/errors.py), never bare exceptions; no silentexcept. - Everything is
asyncand fully type-hinted. Target ≥90% test coverage on new code; lint with ruff. - Rule numbers live only in
config.py::LeaveRules— no magic numbers elsewhere.
3. What remains to finish the foundation
Recommended order (each builds on the last). Items marked (senior) should stay senior-owned; the rest can be delegated once the pattern is set.
a. Database & migrations (senior). Replace the dev-only inline DDL in db/connection.py with Alembic migrations covering the full schema in ARCHITECTURE.md §3.2. Decide connection strategy: SQLite single-connection for dev vs a Postgres pool for prod, and adjust dependencies.get_connection accordingly. Add the postgres/ repo impl skeleton.
b. Auth & security (senior). Registration/login, password hashing (argon2/bcrypt — never SHA), and a token strategy (short-lived JWT + refresh, or server-side sessions) plus password reset / email verification. Implement the PersonalData-vs-User identity model (§3.0) — membership via PersonalData.workspace_id, User linked 1:1. Decide personnummer handling (§11: prefer not storing; HMAC/encrypt if required). Add rate limiting on auth + fetch endpoints.
c. Soft-delete repository extension (senior). Add a soft_delete/hard_delete variant of the base repo for GDPR entities (e.g. PersonalData). Simple entities keep the plain CRUD base.
d. Workspace, membership & invitations. Workspace + parent-profile CRUD, and the single-use invitation flow (§3.0) — store only a token hash, expire/revoke. Token security is senior-owned; the surrounding CRUD can be delegated.
e. Försäkringskassan data access (senior, HIGH RISK). Define the stable FetchDataService contract returning a ParentalLeaveSnapshot so all features depend on the interface, not FK's DOM. Implement the manual-entry path first (it must work standalone), then a stubbed scraper behind the same contract. Do not ship scraping without the legal/ToS + BankID review flagged in §2.3.
f. Core calculation engine (senior). analytics_service implementing days-left-at-age-4 + planned-vs-actual reconciliation (§6.5), including the date/leap-year math and edge cases. This is the headline feature and the trickiest logic — own it, then expose clean helpers.
g. Tips engine skeleton. Define the Tip type and the rule-registry structure from §6, plus the predicate helpers (weekly_intensity, days_left_at_age_4, red_day_cluster_in_plan, etc.). Once the helpers exist, wiring individual rules is good delegated work.
h. Frontend foundation (not started). Stand up the Vite + React + TS project: tsconfig, ESLint, Vitest, types/ (transcribe §7), a typed api client, AuthContext/WorkspaceContext, routing, and one reference hook + component + test that mirrors the backend slice so the junior has a frontend template too.
i. CI. Pipeline running ruff + pytest (coverage gate) and eslint + vitest.
4. Then hand off to the junior
Once a, h (and ideally g's helper stubs) are in place, the junior can start. JUNIOR_ONBOARDING.md already points them at the VacationDays slice as the template and lists their tasks — notably BreakPeriod and Child CRUD (copy the slice), date/holiday utility helpers, and the presentational frontend components/types. Please skim that doc and adjust the "what's ready" note at its top to match reality.
5. Open product questions
ARCHITECTURE.md closes with unresolved questions worth settling early: configurability of tips, audit logging, plan "preview", export, the scraping legal stance (the real launch gate), and special cases (multiples, pre-2014 births, single custody). Resolve or escalate these before they block feature work.