# Local FamilyDashboard: Child status timeline and iPad legibility

Use when polishing the FamilyDashboard Home/Todo child status cards, day-phase logic, lunch mode, or school/free timeline.

## UX lessons from iPad feedback

- Prefer one large, child-readable primary value over several competing status boxes.
  - Lunch with afternoon school: `Noch 42 Min.` + caption `bis Loslaufen`.
  - School running: `Noch 80 Min.` + caption `bis Schulschluss`.
  - Afternoon free: `Nachmittag frei` + caption `heute keine Schule mehr`.
- Do not show stale or irrelevant school hints. If the child is already in school, avoid `Schulbeginn 13:30`; show `Schule läuft bis HH:MM` or `Schule bis HH:MM` instead.
- Avoid long primary text in the big countdown card. `Heute keine Schule mehr` can clip on iPad; use it as caption/secondary text and make the large value `Nachmittag frei`.
- Replace equal-width step pills with a proportional moving progress bar when the user wants children to estimate remaining time visually.
  - Position markers from actual step times: `(step_time - range_start) / (range_end - range_start)`.
  - Use a subtle animated sheen/fill to imply time is moving, not a hectic animation.
  - Model the bar as **time ranges plus milestones**, not only dots. Ranges carry `time` + `endTime`/`kind=range` and render as bands whose width equals duration; milestones remain dots.
  - Keep labels short (`Ankunft`, `Essen`, `Pause`, `Packen`, `Gehen`, `Schule`, `Ende`, `Ritual`, `Schlafen`). Put detailed text in cards above, not under the bar.
  - Avoid ambiguous or generic child-facing labels. Do **not** use `Los` in the timeline; use `Gehen` where a same-day departure marker is truly useful, and omit departure markers in full-day future previews. Do **not** show generic `Termin` when the actual appointment name is known.
  - Use `Hausaufgaben`, not `Aufgaben`, for homework ranges.
- After school is over, rebuild the timeline around the remaining day rather than reusing lunch steps. Good post-school sequence: `Ankunft` milestone -> `Hausaufgaben` range (90 min) -> `Spielen` until 18:00 -> `Essen` 18:00-18:45 -> `Spielen` until 19:45 -> `Ritual` 19:45-20:15 -> `Schlafen` milestone.
- For a selected future day, show the whole planned day from `Aufstehen` to `Schlafen` with high-level ranges (`Schule`, `Mittagessen`, `Hausaufgaben`, `Spielen`, `Essen`, `Ritual`) and milestones. Once that day is current, switch back to phase-specific timelines: morning until school start, lunch until afternoon school start, then after-school return until bedtime.
- External activities remain non-school obligations/hints, but in the current FamilyDashboard status bar they should render as duration ranges with the activity name when start/end are known, e.g. `Mädchenriege` 17:30-19:00 or `Klavier` 15:10-15:35. They must not count as school or produce a leave-for-school warning.
- The status timeline belongs on **Home/Todo only**. Hide it on Calendar, Schedule, Benefits, and Admin. The Calendar is for read-only date/event scanning; the timeline creates clutter there.
- For the child-facing iPad status header, keep the top area calm: do **not** render extra info buckets such as `Gerade / Nächstes`, `Heute`, `Nachmittag frei`, `Heute keine Schule mehr`, or standalone phase badges like `Frei` beside the child identity. Prefer child name + current phase label + the large proportional bar.
- Make the proportional bar visually dominant on iPad:
  - roughly double the former track height,
  - increase range/milestone label size materially (about 40% over the old small labels),
  - place time ranges in the lower half of the track so milestone labels such as `Aufstehen`, `Ablaufen`, `Schlafen` can sit in the upper half,
  - label each time range at its left edge with the start time (`17:00`, `17:30`, ...),
  - show the current clock time above the fill edge (`currentTimeLabel`) and move it with `progress_percent`.
- Highlight fixed obligations visually, not just by text. Treat school and external activities (`Schule`, `Gitarre`, `Klavier`, `Mädchenriege`, `Turnen`, etc.) as obligation ranges/markers and give them stronger color/border styling.
- Remove generic PWA install hints such as `iPad: Teilen → Zum Home-Bildschirm hinzufügen...` once the app is in regular family use; they waste prime top-screen space.
- User-specified phase timelines:
  - Morning: if school starts 07:30, wake at 06:30; if school starts 08:20, wake at 07:00. Show `Frühstücken` until `Zähneputzen / Schuhe anziehen` beginning 07:05 or 07:55, ending at milestone `Ablaufen`.
  - Lunch: make `Mittagessen` an explicit visible range rather than hiding it inside a broad `Mittagspause`. In current-day timelines, let it start directly at morning-school end so `Schule -> Mittagessen -> Pause -> Zähneputzen -> Weg -> Schule` has no visual gap. Then show `Pause` until about 13:00, `Zähneputzen` until the afternoon leave-home time, and milestone/range `Ablaufen`/`Weg`. If no afternoon school, still show `Mittagessen`, then `Frei` until external appointments.
  - Current `school_running` must not collapse the whole day into one long `Schule` range plus `Ende`. Use the detailed day timeline even while school is running: morning school, lunch, pause, teeth, way to school, afternoon school, way home, free/evening. Remove `Ende` milestones from the child-facing status bar unless explicitly requested.
  - Do not show `Hausaufgaben` in the status timeline by default. If there are no school/external obligations in a period, render the time as `Frei` so children see free time rather than implied homework.
  - Compact-label polish: for cramped routine ranges, prefer symbols in `shortLabel` and keep the full German `label` for tooltips/tests/API clarity. Current proven symbols: `🪥` for `Zähneputzen`, `🍽️` for `Mittagessen`/`Abendessen`. In the frontend, add a dedicated icon-label class so icons are centred and larger instead of relying on ellipsized text styling.
  - External activities after lunch must appear in the status timeline even when the child has no afternoon school. Example: `Gitarre ZI 205` 12:50–13:15 should render as a named external obligation range after lunch/free time, not merely as a secondary hint.
  - After afternoon-school return: show `Frei` until the evening timeline begins.
  - Evening from 17:00: `Abendessen` 17:30–18:30, then `Frei` until 19:30, `Zähneputzen` until 19:45, `Abendritual` until 20:15, then milestone `Schlafen`. If `Schlafen` overlaps visually with `Abendritual`, pin the sleep marker to an upper lane (e.g. a `sleep-marker` CSS class) rather than lowering/alternating it into the ritual band. If an external appointment overlaps dinner (e.g. Mädchenriege 17:30–19:00), render that named appointment as the prominent obligation range rather than a generic `Termin`.

## Moving fixed-now timeline refinement

For the newer Home/Todo moving status timeline, also see `references/familydashboard-moving-status-timeline.md`. It captures the fixed-now viewport model, generalized next-departure logic for school and external activities, icon/display-mode rules, and iPad legibility targets.

## Backend data to expose

In `/api/dashboard` child timeline payloads, include enough fields so the frontend does not infer stale labels:

- `dayPhase`, `statusLevel`, `nowLabel`, `primaryMessage`, `secondaryMessage`.
- `minutesUntilLeaveHome` for morning/lunch leave countdowns.
- `schoolEndTime` and `minutesUntilSchoolEnd` for `school_running` / `afternoon_school`.
- `afternoonSchoolStart`, `afternoonLeaveHomeTime` only for lunch/morning contexts where they are relevant.
- `timelineSteps[]` with `{ key, label, shortLabel, time, state }` for milestone-only entries, and `{ key, label, shortLabel, time, endTime, kind: "range", state }` for duration bands.
- Optional `timelineRangeStart` / `timelineRangeEnd` if the UI needs explicit range control; otherwise derive from min/max `time`/`endTime` values.

## Verification pattern

- Add backend tests for the time text/phase that changed, e.g. after afternoon school start should be `afternoon_school`, `primaryMessage = Noch N Min.`, `secondaryMessage = Schule läuft bis HH:MM`, and `minutesUntilSchoolEnd = N`.
- Add backend tests for the timeline shape: lunch/evening routine items that consume time should expose `kind="range"` + `endTime` (e.g. `Mittagessen` directly after morning-school end, `Pause`, `Zähneputzen`, named external activity ranges, `Essen` 18:00-18:45, `Ritual` 19:45-20:15). Also assert no unwanted `Ende` milestone, no `Hausaufgaben` in status timelines unless explicitly requested, and no gaps between consecutive ranges.
- For clickable detail panels, annotate timeline steps with a `detail` field: school ranges should summarize subjects from the structured Stundenplan (`Heute Morgen: Turnen`, `Heute Nachmittag: Turnen`), and external activities should use the real appointment name (`Heute Nachmittag: Gitarre ZI 205`). Keep visual labels short, but expose the full text on tap/click below the bar.
- Add Playwright mocked-dashboard tests for:
  - lunch countdown rendering (`Noch 42 Min.` / `bis Loslaufen`),
  - school-running card hides `Schulbeginn 13:30`,
  - moving/proportional bar exists and uses short labels,
  - range bands render via `.timeline-range-label`,
  - no long labels such as `Tasche / Schuhe` appear under the bar,
  - Schedule and Benefits routes do not render the `Tagesstatus pro Kind` timeline.
- Run real browser/iPad-width visual smoke after tests; check for clipped headings, overlong detail-card text, marker overlap, range-label overlap, and console errors.

## Live deploy / preview communication

- Distinguish clearly between: code built/tested, code pushed, dev-preview verified, and Docker/live deployment on the user-facing port. Do not imply the iPad live app has the new UI until the running process/container has actually been rebuilt/restarted and smoke-tested.
- If the user says the app is temporarily on another port (e.g. 5173), verify whether that port is serving the freshly changed bundle before relying on it. A port can answer HTTP 200 while still serving an older Vite/Docker process. If needed, start a temporary known-current backend/frontend dev preview on separate ports, verify there, and stop those processes before finalizing.
- If live Docker deployment is blocked by local setup or permissions, still verify the current live app with health checks (`/api/health`, frontend HTTP 200) and explain the practical impact: existing app continues to work; the latest UI changes are not live yet.
- When asking the user to finish a blocked live deploy, give the exact command and post-checks in one compact block:
  ```bash
  cd /home/agent/projects/FamilyDashboard
  docker compose up -d --build
  docker compose ps
  curl -fsS http://localhost:8000/api/health
  curl -I http://localhost:5173
  ```
- After a successful Docker rebuild, remind that the iPad/PWA may need a full Safari/PWA close/reopen because service-worker/browser cache can keep the previous bundle briefly.
