# Daily Zone Check-in Integration ## Purpose Staff log a daily self-regulation "Emotional Zone" (blue/green/yellow/red). The same state drives the dashboard check-in card, the `/zones-of-regulation` overview cards, the profile unified results table, leader dashboard completion/risk sections, and a notification-dropdown nudge when an eligible user has not checked in today. ## Backend contract `/api/zone_checkins` requires explicit `ZONE_CHECKIN` for personal reads/writes. This personal workflow permission is not implied by `globalAccess`. The client never computes the date; "today" is computed server-side from the user's campus timezone, falling back to UTC for organization/school-scope staff without a campus. - `GET /today` → `{ date, zone, isCheckedInToday }` - `POST /` `{ data: { zone } }` → record today's zone (upsert) - `DELETE /today` → clear today's zone - `GET /?from=&to=` → history `{ rows: [{ date, zone }], count }` - `GET /completion` → leader/report scoped staff completion `{ summary, rows }` with `READ_ZONE_CHECKIN_REPORTS`. ## Frontend Structure - API/types: `shared/api/zoneCheckins.ts`, `shared/types/zoneCheckins.ts` - Business: `business/zone-checkin/hooks.ts` (`useTodayZoneCheckIn`, `useZoneCheckInHistory`, `useZoneCheckInCompletion`), `business/zone-checkin/selectors.ts` (`canZoneCheckIn`, `shouldNudgeZoneCheckIn`) - Components: `components/zone-checkin/ZoneCheckInCard.tsx` (shared dashboard card), `ZoneCheckInReminder.tsx` (banner), `ZoneCheckInSection.tsx` (composed section), and the `/zones-of-regulation` overview cards. ## Behavior - **Eligibility/nudge gating** requires the effective `ZONE_CHECKIN` permission. Seed data grants it to staff users expected to complete the daily workflow across organization, school, campus, and class scopes; custom permissions can extend or remove it per user. - **Dashboard**: the card is wired through `useDashboardPage` (which exposes `showZoneCheckIn` + `needsZoneCheckIn`) with an optimistic shell value for snappy selection. - **Zones page**: the main zone overview cards call `useTodayZoneCheckIn` through `useZonesOfRegulationPage`; selecting blue/green/yellow/red both opens the zone detail panel and saves the eligible user's daily check-in. Parent drill-down keeps the selection local and does not persist personal state; the backend also rejects personal zone mutations in child scopes. - **Notifications**: `business/top-bar` derives a single unread notification from `shouldNudgeZoneCheckIn` (`buildTopBarNotifications`) — there is no backend notifications store. The notification carries an `href` (`APP_ROUTE_PATHS.zones`); clicking it navigates to `/zones-of-regulation` (a react-router `Link`) and closes the dropdown. - `useTodayZoneCheckIn` is disabled for users without `ZONE_CHECKIN` or when the user is drilled into a child scope. Disabled callers receive empty local state instead of stale cached check-in data. Its `error` surfaces **only** save/clear failures; non-eligible users should not trigger the `/today` request. - **Leader dashboards**: `useDirectorDashboardPage` loads `useZoneCheckInCompletion` with the effective tenant in its query key and appends Daily Zone Check-In rows to the unified completion table. Non-green completed zones are shown as medium risk in Risk Areas. - **Profile**: the unified quiz/results table includes today's Daily Zone Check-In for eligible users. - **Content**: zone cards and page copy are backend-owned content catalog presets (`regulation-zones`, `zones-of-regulation-page-content`) for new organizations. ## Tests - `business/zone-checkin/selectors.test.ts` (eligibility + nudge), `business/top-bar/selectors.test.ts` (notification builder + zones `href`), `business/director-dashboard/selectors.test.ts`, `business/profile/selectors.test.ts`, and `shared/api/zoneCheckins.test.ts`. - Seeded e2e: `frontend/tests/e2e/zone-checkins.seeded.e2e.ts` (record / read-back / clear today, invalid-zone rejection, external-role lockout). ## Verification - `npm run typecheck`, `npm run lint`, `npm run test` pass.