# FamilyDashboard Bildschirmzeit + Shop pattern

Use when adding or maintaining child-operated screen-time tracking, Shop/Benefits exchanges, timer UI, or Admin day/week allowance controls in `/home/agent/projects/FamilyDashboard`.

## Product semantics

- Add child-facing navigation as a first-class page, not a hidden widget: `Bildschirmzeit` with the same Emilia/Valerie two-column mental model as Home/Todo.
- Default allowance is per child per date (currently 60 min/day), persisted as a daily allowance row rather than inferred only from settings.
- Children start and stop their own timer for TV/Gaming/Tablet usage. Store immutable session rows; derive used/remaining from sessions plus active elapsed time.
- A locked day blocks starting even if remaining time exists.
- Timer expiry should be visible and audible in the browser. Let Admin select among named alarm sounds via app settings; keep a browser-safe WebAudio fallback instead of relying on hosted audio files.
- The old `Benefits` page may be product-framed as `Shop`: simple exchange of earned coins into same-day screen time plus existing benefits.
- Default exchange used in this session: `4 Coins = +10 minutes for today`. Make both sides configurable through Admin settings.

## Backend shape

- Prefer additive SQLModel tables:
  - `ScreenTimeDayAllowance(child_id, day, base_minutes, bonus_minutes, adjustment_minutes, locked, notes)` with unique `(child_id, day)`.
  - `ScreenTimeSession(child_id, day, started_at, ended_at, duration_seconds, status, idempotency_key)`.
- Keep allowance updates admin-only; child routes are only start/stop/exchange.
- Keep exchange ledger-based: before granting bonus minutes, verify `ledger_for_child(...).summary.available >= cost`; then add bonus minutes and append a negative `CoinTransaction` with a stable idempotency key/comment. Do not mutate balances directly.
- Public endpoints used:
  - `GET /api/screen-time?date=YYYY-MM-DD`
  - `POST /api/screen-time/{child_id}/start`
  - `POST /api/screen-time/{child_id}/stop`
  - `POST /api/screen-time/exchange`
- Admin endpoints used:
  - `GET /api/admin/screen-time?start=YYYY-MM-DD&days=7`
  - `PATCH /api/admin/screen-time/{child_id}/{date}`
- Persist global settings in `AppSetting`: default daily minutes, exchange coin cost, exchange minutes, alarm sound.

## Frontend shape

- Add view routing/path `/screen-time` and SideNav entry `⏱️ Bildschirmzeit`.
- Rename visible `Benefits` copy/navigation to `Shop`, but preserve existing backend benefit concepts/routes unless doing a deeper migration.
- Screen-time card should show: child identity, total minutes today, large countdown (`HH:MM:SS`), progress bar, used minutes, bonus/admin adjustments, lock state, and one large Start/Stop button.
- While a timer is active, tick client-side every second for smooth UX and also refetch periodically (e.g. 10s) to reconcile persisted state.
- Use a one-shot alarm guard (`useRef`) so an expired running timer does not beep every render/tick.
- Admin screen-time panel should be weekly by default with per-day/per-child quick controls (`-10`, `+10`, lock/unlock) plus global settings for the exchange and alarm.

## Verification checklist

- Add focused backend tests for:
  - default allowance appears as 60 minutes;
  - start/stop creates and closes a session;
  - locked/zero-budget days reject start;
  - coin exchange spends exactly once and adds bonus minutes idempotently;
  - admin week range and per-day adjustment work.
- Run the focused test file first, then frontend `npm run build`.
- Full backend tests may contain unrelated brittle ledger/date expectations in this repo; if they fail, isolate with `-x` and confirm whether the failure is unrelated before reporting. Do not silently call the feature verified from a timed-out full suite.
- Rebuild with `docker compose up -d --build` (never `down -v`), then verify container health and at least one screen-time API response.

## Pitfalls

- SQLite may return naive datetimes even when defaults used timezone-aware datetimes. Normalize before subtracting active elapsed time.
- Do not rely on browser audio files unless they are committed/static; WebAudio oscillator patterns are enough for a selectable MVP alarm.
- Avoid making the Shop exchange a normal BenefitRedemption reservation flow; screen-time exchange should be immediate for the current day and ledger-audited.
