7.1 KiB
Senior Developer Report
Project: Föräldraledigplannerare
Sessions: 1 (scaffolding) + 2 (this session — stabilisation & handoff)
Date: 2026-06-01
Status: ✅ Junior handoff gate cleared
Session 2 — What Was Done
1. Fixed FK constraint failures (§2a in handoff doc)
Problem: All test_vacation_days_repository.py tests and all test_analytics_service.py tests failed with sqlite3.IntegrityError: FOREIGN KEY constraint failed. The test helpers (_make()) generated random UUIDs for workspace_id and personal_data_uuid that had no corresponding rows in the DB, but the full schema enforces those as FK constraints.
Fix:
- Added a
SeededIdsdataclass andseeded_idsfixture totests/conftest.py. The fixture pre-creates oneworkspace+ onepersonal_datarow and yields their IDs so any test that inserts rows with FK constraints can pass real parent IDs. - Updated
test_vacation_days_repository.py:_make()now acceptsworkspace_id/personal_data_uuidkwargs; all tests that callcreate()passseeded_ids. - Updated
test_analytics_service.py: replacedws = uuid4()/pd_uuid = uuid4()withseeded_ids.workspace_id/seeded_ids.personal_data_uuidin all fourTestAge4Projectiontests.
2. Created BreakPeriodService
Problem: dependencies.py referenced BreakPeriodService (causing three F821 Undefined name ruff errors), but services/break_period_service.py did not exist.
Fix: Created app/services/break_period_service.py with create, get, list_for_workspace, update, and delete methods, following the VacationDaysService pattern. Added the import to dependencies.py.
3. Fixed ruff lint & format
ruff check --fix .auto-fixed 6 unused imports acrossanalytics_service.py,auth_service.py,fetch_data_service.py,tips_service.py, androuters/fetch_data.py.ruff format .reformatted 37 files.- Both
ruff check .andruff format --check .now pass clean.
4. Expanded analytics service test coverage
Added 6 new tests to push analytics_service.py from 44% → 100%:
| Test | Lines covered |
|---|---|
test_child_not_found_raises (in TestAge4Projection) |
L76 — NotFoundError path in get_days_left_at_age_4 |
TestValidateDubbeldagar.test_child_not_found_raises |
L154–156 — NotFoundError path in validate_dubbeldagar |
TestValidateDubbeldagar.test_outside_window_raises |
L152–164 — outside-15-month window guard |
TestValidateDubbeldagar.test_quota_exceeded_raises |
L166–174 — max dubbeldagar quota guard (inserts 60 rows) |
TestGetOverview.test_overview_single_parent |
L123–136 — happy path of get_overview |
TestGetOverview.test_overview_no_parents_raises |
L124–125 — NotFoundError in get_overview |
5. Updated JUNIOR_ONBOARDING.md
- Updated the "Foundation status" block to reflect Session 2 completion.
- Corrected Task 1 (BreakPeriod): was "build everything"; corrected to "verify + write tests" since all backend layers now exist.
- Added ⚠️ note about
npm install/package-lock.json.
Final State After Session 2
| Check | Result |
|---|---|
uv run pytest |
✅ 29 passed, 0 failed |
uv run ruff check . |
✅ All checks passed |
uv run ruff format --check . |
✅ 77 files already formatted |
analytics_service.py coverage |
✅ 100% |
auth_service.py coverage |
✅ 90% |
vacation_days_service.py coverage |
✅ 92% |
vacation_days_repository (SQLite) coverage |
✅ 100% |
| Junior handoff gate | ✅ Cleared (except npm install below) |
What Remains
One-off manual step (< 1 min, not junior-blocking)
| Task | Who | Notes |
|---|---|---|
cd frontend && npm install → commit package-lock.json |
You (or anyone) | Needed for npm ci in CI. Does not block local dev. Network-blocked inside Claude Code sessions. |
Junior tasks (ordered by dependency)
These were unblocked by this session. Full descriptions in JUNIOR_ONBOARDING.md.
| # | Task | Files to create | Blocks |
|---|---|---|---|
| 1 | BreakPeriod tests | tests/unit/test_break_period_repository.py |
Nothing (standalone) |
| 2 | Child CRUD | services/child_service.py, models/child.py, add routes to routers/settings.py |
Task 3 |
| 3 | PlannedLeaveDay CRUD + PlanningService | services/planning_service.py, models/planned_leave.py, routers/planned_days.py |
Requires Child (Task 2) |
| 4 | PersonalData settings endpoint | Thin service method + PUT /api/settings/parent/{uuid} |
Nothing |
| 5 | Frontend hooks | useParentalLeave.ts, usePlannedDays.ts, useAnalytics.ts, useOptimizationTips.ts + matching *.test.tsx |
Can run in parallel once backend is green |
| 6 | Wire tips rules | services/tips_service.py (9 stub rules) |
Can be done incrementally, each rule is self-contained |
| 7 | Date helpers | app/utils/dates.py + frontend/src/utils/dates.ts |
Needed by planning + calendar UI |
| 8 | Swedish public-holiday helper | Extend app/utils/ |
Needed by red-day tip and calendar UI |
| 9 | Presentational frontend components | components/calendar/, components/analytics/, components/settings/, etc. |
Can start immediately |
Senior-owned tasks (still open)
These were explicitly deferred and must not be picked up by the junior.
| Task | Location | Status | Notes |
|---|---|---|---|
| FK scraper + BankID | scrapers/fk_scraper.py |
NotImplementedError stub |
Legal/ToS gate must clear first (see project_legal_gate.md) |
| Postgres repository impls | repositories_impl/postgres/ |
Only vacation_days skeleton exists |
Copy SQLite impls; replace ? params with $1, $2 (asyncpg style) |
scraper_enabled guard in fetch router |
routers/fetch_data.py |
Guard not yet wired | Add if not settings.scraper_enabled: raise 501 once scraper is real |
TipsContext.workspace_planning_goal |
services/tips_service.py |
Hardcoded "balanced" |
Inject WorkspaceRepository into TipsService or pass planning_goal into get_tips() |
BreakPeriodUpdate required fields |
models/break_period.py |
All fields required (not Optional) | Either make fields Optional (partial update) or document full-replacement semantics |
Sharp Edges to Pass On
Noted in senior_skaffolding_1.md §4; still unresolved:
BreakPeriodUpdaterequired fields — The model uses required fields, so every PUT must supply all fields. Fine for now, but the junior's BreakPeriod tests will need to account for this.TipsContext.workspace_planning_goalhardcoded —TipsService._build_contextalways returns"balanced". The 3 goal-specific rules (skip_fp_first_12_months,wrap_weekend_with_vacation,wrap_red_days_with_vacation) will never be filtered correctly untilWorkspaceRepositoryis injected.- CI coverage gate — The CI runs
--cov-fail-under=90against all ofapp/. Total coverage is currently ~37% (all the router/service stubs are untouched). The gate will fail until the junior has written enough tests. Consider temporarily lowering the threshold inci.ymlor adding a[tool.coverage.run] omitlist for stub/skeleton files.