Files
F-r-ldraledigplannerare/JUNIOR_MVP_TODO.md
T
2026-06-14 09:58:30 +02:00

8.8 KiB

Junior Developer — MVP Happy-Path TODO

Owner: Junior developer Status: Ready to implement Goal: Make the core happy path work end-to-end: register → land logged-in on the overview → log in → land on the overview → register a child → see the overview → fetch the child's data from Försäkringskassan. Date: 2026-06-12

Context: The backend is in good shape and the FK scraper is now implemented (Playwright, real captured selectors). The breakages are almost all in frontend wiring. FK scraping is now legally cleared, so the overview's day numbers should come from the scraper.

Do NOT undo or rewrite the scraper (backend/app/scrapers/fk_scraper.py), its captured selectors, or the FetchDataService contract. Reuse what exists.

Work top-to-bottom; tasks are ordered so each unblocks the next. Run npx tsc --noEmit and npm run lint after each task — keep them green.


J1 — Redirect after login & register (the #1 visible bug)

Problem: pages/Auth.tsx calls login() / register(), which do authenticate you (AuthContext sets isAuthenticated: true), but the page never navigates, and nothing bounces an already-authenticated user off /auth. So you're silently logged in but stuck on the form — this is why "after registering I'm not logged in" and "login doesn't take me anywhere."

Do:

  • In pages/Auth.tsx, after a successful login/register, navigate to / (use useNavigate() from react-router-dom, navigate('/', { replace: true })).
  • Also guard /auth itself: if isAuthenticated is already true, redirect to /. Either inside Auth.tsx (early <Navigate to="/" replace />) or in App.tsx's /auth route. This handles the "I manually went to /auth while logged in" case cleanly.

Acceptance:

  • Registering a brand-new account lands you on the dashboard, logged in, with no manual navigation.
  • Logging in lands you on the dashboard.
  • Visiting /auth while logged in redirects to /.

J2 — Bootstrap the workspace after auth (why the dashboard is empty)

Problem: context/WorkspaceContext.tsx only reads workspaceId from localStorage, which nothing ever sets. So after login there is no workspace → the dashboard shows defaults. The backend already exposes everything you need at GET /api/auth/context (api.getUserContext()), which returns { personal_data_uuid, workspace_id, children[] }.

Do:

  • When the user becomes authenticated, call api.getUserContext() and use its workspace_id to drive WorkspaceContext (set it via the existing setWorkspaceId, and keep persisting to localStorage is fine as a cache — just don't depend on it being pre-populated).
  • Expose the children and a selectedChildId from context (or a small ChildContext). For MVP, auto-select the first child if any exist. Add a selectChild(id) setter for later.
  • Also expose personal_data_uuid (the overview + FK fetch need it).
  • Re-fetch context after creating a child (see J4) so the new child appears and gets selected.

Acceptance:

  • After logging in (fresh browser, empty localStorage), the dashboard loads the user's workspace automatically.
  • If the workspace has a child, it's auto-selected and the overview renders for it.

(Senior will review this context seam — keep the change small and readable.)


J3 — Fix the broken API client paths (several calls 404 today)

Problem: services/api.ts invents /workspaces/{id}/… REST paths that do not exist on the backend. Confirmed mismatches:

api.ts call (wrong) Real backend route
GET /workspaces/{id}/break-periods prefix is /api/break-periods (see routers/break_periods.py + routers/settings.py)
POST /workspaces/{id}/break-periods /api/break-periods
GET /workspaces/{id}/tips /api/tips/{workspace_id} (prefix /api/tips, see routers/settings.py)
GET /workspaces/{id}/planned-days prefix /api/planned-days (see routers/planned_days.py)
POST /workspaces/{id}/planned-days /api/planned-days
GET /workspaces/{id}/parental-leave /api/parental-leave/{personal_data_uuid}/{child_id} — different shape; see note

Do:

  • Open backend/app/routers/*.py, read the actual @router decorators under each prefix, and correct each path + its params/body in api.ts. The analytics overview path (/analytics/{ws}/overview?child_id=…) is already correct — use it as your reference for "right".
  • For parental-leave, the backend route needs personal_data_uuid + child_id, not a workspace id. Don't guess — the senior is adding/clarifying a workspace-friendly read route (Senior task S2). Until that lands, wire getParentalLeave to the contract the senior specifies (likely /api/parental-leave/{personal_data_uuid}/{child_id} using the IDs from context). Coordinate; don't invent a path.

Acceptance:

  • No 404s in the network tab when the dashboard loads.
  • tsc/lint green; existing hook tests updated to the corrected paths and passing.

J4 — Child registration on the overview (empty-state happy path)

Problem: There's no way to add a child from the overview. The pieces exist: api.createChild() → POST /api/children, and the ChildBirthdayInput component.

Do:

  • On the Dashboard, when the selected workspace has no children, render an empty state with an "Lägg till barn" form (reuse ChildBirthdayInput; collect name + birth date).
  • On submit: call api.createChild({ workspace_id, name, birth_date }), then re-fetch context (J2) so the child appears and is auto-selected, and the overview re-renders for it.
  • Show a clear success/error message; disable the submit button while in flight.
  • Keep it simple — one child is enough for MVP. A child switcher can come later.

Acceptance:

  • A freshly registered user sees "no child yet → add one", can add a child, and immediately sees the overview populate for that child.

J5 — "Hämta från Försäkringskassan" on the overview

Problem: The FK fetch flow currently only lives in the dev harness (pages/DevFetch.tsx). The real overview should let the user pull their data for the selected child.

Do:

  • Extract the harness's session logic (start → poll every ~1s → render QR data:image/png;base64,… → show result/error → cancel) out of DevFetch.tsx into a reusable hook (e.g. useScraperFetch) and a small QRCodeModal component. DevFetch should then use these too (don't duplicate).
  • On the Dashboard, add a "Hämta från Försäkringskassan" button (enabled only when a child is selected). Clicking it opens the QRCodeModal, starts a session (the backend auto-resolves IDs from the logged-in user — send an empty body, or pass the selected child_id), shows the live QR, and on done closes the modal and refreshes the overview (re-fetch parental-leave for the selected child).
  • Handle the readable error states the backend can return (e.g. "No child in workspace — add one before fetching"). Show the message; don't crash.

Acceptance:

  • From the overview, clicking the button shows the BankID QR, and after a successful scan the overview updates with the fetched numbers.

Depends on Senior S1 (persist the scraped snapshot) for the refreshed read to actually return data. You can build and demo the modal/QR against the live done result before S1 lands; full overview refresh works once S1 is in.


J6 — Small dev-harness auth fix (stop the bare "Not authenticated")

Problem: npm run login opens /dev/fetch directly. The auth token lives only in memory after an app login, so opening the harness cold makes getUserContext() / start return "Not authenticated" with no guidance.

Do (minimal):

  • In pages/DevFetch.tsx, when getUserContext() (or any scraper call) returns a 401/unauthorized, render a friendly banner with a "Logga in först" link to /auth (use isUnauthorized from services/errors.ts). Optionally auto-redirect to /auth and back.
  • Keep the existing dev-only mount and the "real BankID" warning. This is a small UX fix, not a redesign.

Acceptance:

  • Opening /dev/fetch while logged out shows a clear "log in first" link instead of a raw error. After logging in (J1 now redirects properly), the harness works.

Definition of done (the demo to run)

  1. Register a new account → you land on the dashboard, logged in.
  2. Dashboard shows the empty state → add a child → overview renders for that child.
  3. Click "Hämta från Försäkringskassan" → scan QR → overview updates with FK numbers.
  4. Log out, log back in → you land on the dashboard with the child still there.
  5. npx tsc --noEmit, npm run lint, npm test all green.

Escalate to senior (don't guess): the parental-leave read contract (J3/S2), and anything about how/where scraped data is persisted (S1).