40227-vm/frontend/docs/zone-checkin-integration.md

61 lines
2.8 KiB
Markdown

# Daily Zone Check-in Integration
## Purpose
Campus staff log a daily self-regulation "Emotional Zone" (blue/green/yellow/red).
The same state drives three surfaces: the dashboard check-in card, the
`/zones-of-regulation` page (reminder banner + card), and a notification-dropdown
nudge when an eligible user has not checked in today.
## Backend contract
`/api/zone_checkins` requires explicit `ZONE_CHECKIN`. This personal workflow
permission is not implied by `globalAccess`. The client never computes the date;
"today" is the campus-local date computed server-side from `campuses.timezone`.
- `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 }`
## Frontend Structure
- API/types: `shared/api/zoneCheckins.ts`, `shared/types/zoneCheckins.ts`
- Business: `business/zone-checkin/hooks.ts` (`useTodayZoneCheckIn`,
`useZoneCheckInHistory`), `business/zone-checkin/selectors.ts`
(`canZoneCheckIn`, `shouldNudgeZoneCheckIn`)
- Components: `components/zone-checkin/ZoneCheckInCard.tsx` (shared card),
`ZoneCheckInReminder.tsx` (banner), `ZoneCheckInSection.tsx` (page section)
## Behavior
- **Eligibility/nudge gating** requires the effective `ZONE_CHECKIN` permission.
Seed data grants it only to the campus staff workflow audience
(`director`, `office_manager`, `teacher`, `support_staff`), but custom
permissions can extend or remove it per user. Global/full-access leadership
users do not see self-state nudges unless they receive explicit `ZONE_CHECKIN`.
- **Dashboard**: the card is wired through `useDashboardPage` (which exposes
`showZoneCheckIn` + `needsZoneCheckIn`) with an optimistic shell value for snappy
selection.
- **Zones page**: `ZoneCheckInSection` is self-contained (`useTodayZoneCheckIn`)
and renders above the regulation content.
- **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`. Its `error` surfaces
**only** save/clear failures; non-eligible users should not trigger the
`/today` request.
## Tests
- `business/zone-checkin/selectors.test.ts` (eligibility + nudge),
`business/top-bar/selectors.test.ts` (notification builder + zones `href`).
- 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.