# FamilyDashboard departure sound, daily math quiz, and admin quiz settings

Session learning from implementing child-facing departure warnings, daily math tasks, and admin tab organization.

## Trigger
Use this alongside `familydashboard-moving-timeline.md` when the user asks for FamilyDashboard timeline alerts/sounds, math quiz/rechnung des Tages, quiz difficulty settings, or admin portal reorganization.

## Departure warning sound pattern
- Keep sound frontend-first; do not require backend push/cron for MVP.
- Add a hook like `useDepartureWarningSound(childrenData, selectedDate)` that:
  - reads `/api/dashboard` timeline data already loaded on Home;
  - checks every 10–15 seconds, not every minute;
  - finds semantic departure steps by key or label: `leave_home`, `leave_external`, `way_to_school`, `school_walk`, `Loslaufen`, `Schulweg`;
  - fires when `leave_time - 3 <= now < leave_time`;
  - only runs for today;
  - stores one-shot playback in LocalStorage, e.g. `departure-warning:${date}:${childId}:${leaveTime}`.
- Use Web Audio API for a local three-tone `dingdingding`; no external file needed.
- iPad/Safari requires a user gesture. Provide Home controls:
  - `Ton aktivieren` to initialize/resume AudioContext;
  - `Testton` to verify sound;
  - a quiet blocked-audio notice: `Ton ist vom Browser blockiert. Bitte einmal „Ton aktivieren“ tippen.`
- Add an admin setting such as `departure_warning_sound_enabled` and a public read endpoint for the frontend; default may be enabled, but playback must still require activation.

## Robust school-start anchoring
- If visual ranges use minimum widths and push blocks, never position `school_start` from raw time alone.
- Add a helper like `findDepartureRangeForSchoolStart(steps, schoolStartStep, visualRangeByKey)`:
  - candidate must be a range with `endTime`;
  - candidate semantics: `leave_home`, `leave_external`, `way_to_school`, `school_walk`, `Loslaufen`, `Schulweg`;
  - `candidate.endTime` should exactly or nearly match `schoolStartStep.time` (±1–2 minutes is practical);
  - marker X = `visualRange.left + visualRange.width` plus a small offset.
- Place `school_start` above/right of the departure block, with responsive labels: `🏫 Schulbeginn` → `🏫 Schule` → `🏫`.

## Current cursor + manual detail selection
- Determine current step locally as `start <= now < end`; if several match, choose the shorter/specific range.
- If the current step has a visual range, interpolate the now cursor within that visual range.
- Detail card behavior for today:
  - tapping a block should show that detail immediately;
  - after a short timeout (about 8 seconds), return to the real current step so stale manual selection does not hide current status.
- For non-today dates, manual selection can remain persistent.
- Ensure non-content overlays (`now` cursor, sticky labels, far target chips) have `pointer-events: none`; range and marker buttons keep `pointer-events: auto` and `touch-action: manipulation`.

## Zähneputzen/WC icon normalization
- Backend may still emit older icons such as `🪥👟`; normalize in the frontend by semantic key/label before honoring backend icon.
- For teeth/preparation blocks show at least `🪥🚽`; if shoes/packing are relevant and space allows, use `🪥🚽 👟`.
- Do not degrade teeth/preparation to a neutral dot; preserve minimum width and icon-only fallback.

## Daily math quiz pattern
- Prefer snapshot persistence so the daily problem remains stable after level changes:
  - `DailyMathTask` pool/generated task metadata;
  - `DailyMathAssignment(child_id, day)` unique assignment with prompt/options/correct answer snapshot and `level_snapshot`;
  - `DailyMathAttempt` for persisted answer state.
- Endpoints:
  - `GET /api/daily-math?date=YYYY-MM-DD`
  - `GET /api/daily-math/quiz?date=YYYY-MM-DD`
  - `POST /api/daily-math/quiz-answer`
- MVP should have no coin effect unless explicitly requested.
- Generate age/level-appropriate tasks algorithmically if no curated pool exists; seed RNG by child/date/level for deterministic snapshots.
- UI should mirror the language quiz card: child section, prompt, 3 options, feedback, persisted answered state.

## Admin quiz settings + tab organization
- Extend child-scoped settings rather than global settings for per-child quiz controls:
  - `language_quiz_language`
  - `language_quiz_level` (1–4)
  - `math_quiz_level` (1–5)
- Add an idempotent SQLite migration for new columns and child-specific initial defaults.
- Level changes should affect only new not-yet-generated assignments.
- For growing admin portals, add touch-friendly tabs rather than one long form. A good 6-tab split:
  - Tagesbetrieb
  - Aufgaben & Coins
  - Kalender & Schule
  - Benefits
  - Lernen / Quiz
  - Einstellungen
- Update E2E tests to navigate the relevant tab before expecting panel headings.

## Verification checklist
- Backend: add focused tests for daily math stability/attempt persistence and admin child settings/public sound setting.
- Frontend: `npm run build` in container.
- E2E: if task-state tests depend on bonus tasks being open, reset through API (`/api/tasks/{id}/undo`) rather than fragile UI-only reset.
- Smoke:
  - `curl -fsS http://localhost:8000/api/health`
  - `curl -I --retry 5 --retry-delay 1 http://localhost:5173`
  - probe `/api/daily-math/quiz?date=...` and `/api/admin/settings/public`.
