Files
F-r-ldraledigplannerare/SENIOR_REPORT.md
T
2026-06-01 16:48:21 +02:00

7.1 KiB
Raw Blame History

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 SeededIds dataclass and seeded_ids fixture to tests/conftest.py. The fixture pre-creates one workspace + one personal_data row 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 accepts workspace_id / personal_data_uuid kwargs; all tests that call create() pass seeded_ids.
  • Updated test_analytics_service.py: replaced ws = uuid4() / pd_uuid = uuid4() with seeded_ids.workspace_id / seeded_ids.personal_data_uuid in all four TestAge4Projection tests.

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 across analytics_service.py, auth_service.py, fetch_data_service.py, tips_service.py, and routers/fetch_data.py.
  • ruff format . reformatted 37 files.
  • Both ruff check . and ruff 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:

  • BreakPeriodUpdate required 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_goal hardcoded — TipsService._build_context always 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 until WorkspaceRepository is injected.
  • CI coverage gate — The CI runs --cov-fail-under=90 against all of app/. 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 in ci.yml or adding a [tool.coverage.run] omit list for stub/skeleton files.