# Senior Court Monitor (Mobile) — Per-Screen Spec

> Acceptance detail per screen (Given/When/Then where useful). The fill→submit→status flow is **identical** to the anchor (Staff Court Monitor) — same auto-assigned ride-safety templates, same photo gates. The one difference is the **added read-only Team / Zone status view** (`SCM-TEAM-STATUS`). RBAC: SCM sees only **own roster / own assigned checklists / own Game Zone**, plus **read-only** visibility of own team's submissions — enforced server-side, mirrored in the app. **SCM cannot approve** (`PROJECT_PLAN §3`).
> References: `FOUNDATION_SPEC.md` (schema, conventions, auto-assign, cascade, `renderStatusForViewer`), `DESIGN_SYSTEM.md` (§2.4 state colors, §6.12 PhotoUpload, §6.13 ChecklistItem, §6.14 ApprovalTimeline, §8.2 mobile shell), `PROJECT_PLAN §4a/§4b/§9`.

---

## Global rules (apply to every screen)

- **Chrome:** navy 56px top app bar (white title + bell + avatar); a **Game-Zone scope strip** below it in light-blue wash reading `Game Zone · Air Maniax Ahmedabad-1` (read-only — SCM is locked to one Game Zone). 56px bottom nav, active slot orange. Orange FAB (camera) on fill screens only.
- **RBAC:** nav + permissions come from `GET /me` (`FOUNDATION_SPEC §2`). The app never hardcodes role logic. **No Approve/Verify affordance exists anywhere** — Senior Monitor cannot approve (`§3`); the Team view is read-only.
- **Game-Zone scope:** every list is server-filtered to the SCM's Game Zone + own assignments (and, for the Team view, own team). An out-of-scope id → 403 (`states/forbidden.html`).
- **Server time + auto initials (§9 #9):** per-item `recordedAt` is **server time** (tamper-proof); initials are **auto-derived** from the logged-in user. No manual time or initials field is editable.
- **Offline (L10):** any network failure shows the "No connection — retry" state; the **entered draft (G/A picks, notes, photos staged) is held in memory** and the action re-POSTs on retry. No data is silently lost on a momentary drop.
- **Status semantics:** `Pending` is what higher (approver) roles see; the Senior Monitor always sees the **real sub-state** of their own instance (Submitted / TL Approved / … / Sent back) and of team instances they observe — derived by the shared `renderStatusForViewer()` (`FOUNDATION_SPEC §4`). SCM is not an approver, so nothing renders as "Pending" to them.

---

## `AUTH-LOGIN` — Login (`screens/01-login.html`)

- **Given** the app is launched logged-out, **When** Karan enters email/phone + password and taps Sign In, **Then** the app calls `POST /auth/login`, stores the access+refresh tokens, calls `GET /me`, and routes to `SCM-DASH` (role resolved = SCM).
- **Given** bad credentials, **Then** show an inline `danger` error ("Incorrect email or password"); password field reveals on the eye icon.
- **Given** too many failed attempts, **Then** show the **locked** state (`states/locked.html`) — countdown + "Too many attempts".
- Primary button = **navy-on-orange** "Sign In" (52px mobile). Maniax wordmark lockup (AIR in orange / MANIAX in white) above the form. "Forgot password?" link in `brand-blue`.

## `SCM-DASH` — Senior Monitor Home (`screens/02-dashboard.html`)

- **Purpose:** at-a-glance — today's shift + the count of assigned checklists by status, due-soon and overdue badges, **plus a Team-status entry card** (unique to the senior role).
- **Given** Karan is on Trampoline · Morning, **Then** the Home shows a shift card ("Trampoline · Morning · 10:00–16:00") + KPI tiles (e.g. "Assigned 2 · In progress 1 · Done 0") + a list of today's checklists with `StatusBadge` chips, tappable into `SCM-CHK-TODAY`/`SCM-CHK-FILL`.
- **Given** the senior role, **Then** Home also shows a **"Team / Zone status" card** summarising the zone monitors' progress (e.g. "3 monitors · 5 submitted · 1 sent back · 2 overdue") that taps into `SCM-TEAM-STATUS`. The card is informational; it carries **no approve action**.
- **Given** a checklist is past `dueAt` and unsubmitted, **Then** its row shows a **solid-red Overdue** badge.
- **Given** nothing is assigned yet (roster not published), **Then** show the nothing-assigned empty state ("No checklists assigned for your shift yet", `states/empty.html`).
- Loading = skeleton list (`states/loading.html`), never a bare spinner.

## `SCM-CHK-TODAY` — Today's Checklists (`screens/03-today-checklists.html`)

- **Purpose:** the full list of this shift's auto-assigned checklists with status chips; the entry point to fill.
- **Given** the roster was published, **Then** the list shows each `ChecklistInstance` for Karan's roster entry (e.g. **Trampoline Daily**, **Trampoline Opening** if he is the opener) with: template name, frequency tag, item-count, a `StatusBadge` (Not started / In progress / Submitted / Sent back / Overdue), and a "📷 needed" hint where photos are still required.
- **When** Karan taps a Not-started or In-progress row, **Then** open `SCM-CHK-FILL` for that instance (state → `IN_PROGRESS` on first response).
- **When** he taps a Submitted/approved row, **Then** open `SCM-CHK-STATUS` (read-only cascade view).
- A **Sent back** row is loud (red) with a "Re-fill" affordance → reopens `SCM-CHK-FILL`.
- **Ride changed mid-shift (CL-4):** **Given** the Team Leader reassigns Karan to a new ride mid-shift (e.g. Trampoline → ZipZag), **When** Karan is on Today's Checklists, **Then** the screen receives the change **live via FCM** (mobile is **online-only**) and shows a dismissible **"Ride changed — your checklists were updated"** banner (brand-light-blue wash + orange accent); the list refreshes to the **new ride's auto-assigned checklists**, and his old ride's checklists move to whoever now holds it. State: `states/ride-changed.html`. The banner is informational (no approve affordance) and dismisses on tap.

## `SCM-CHK-FILL` — Fill Checklist (`screens/04-checklist-fill.html`) — CRITICAL

- **Purpose:** the heart of the role — set **G/A** per item + note + server-time + auto-initials; attach the mandatory **completion photo**; attach a **per-A-item issue photo**.
- **Layout:** sectioned list of `ChecklistItem` rows (`DESIGN_SYSTEM §6.13`). Each row: item text → large **segmented G | A toggle** (44px; G green when selected, A red-orange when selected; neutral until chosen) → **server time** auto-stamp (read-only) + **auto-initials** → conditional **note** + **A-photo tile** that appears and becomes **required** when A is chosen. A sticky **completion-photo** section + a **Review & Submit** bar at the bottom (thumb zone).
- **G/A toggle behaviour:**
  - **Given** an item is untouched, **Then** it renders neutral and prompts action; the instance cannot be submitted with any untouched item.
  - **When** Karan taps **G**, **Then** the row gets a green left rail, `value=G`, server time stamped, note optional; `PATCH …/responses` saves the response (draft, `IN_PROGRESS`).
  - **When** Karan taps **A**, **Then** the **A-note+photo bottom sheet** opens (`bottom-sheets/a-item-note-photo.html`); the row gets a red-orange left rail + a **photo-required flag**; the item is **blocked** from final submit until a `Photo{kind:NEGATIVE, itemId}` exists.
- **Completion photo:** the `PhotoUpload` completion tile (≥96px) opens the **photo-capture sheet** (Camera / Gallery, `bottom-sheets/photo-capture.html`); ≥1 completion photo is required before submit (§9 #7).
- **Save-draft:** responses persist as entered (`IN_PROGRESS`); leaving and returning restores them. Offline → in-memory draft + retry (L10).
- **Photo storage:** each photo is a multipart `POST /uploads/photos` → local disk → `Photo` row with uploader/timestamp/device/kind (`FOUNDATION_SPEC §1`, §4a).
- **Concurrency:** response saves carry `If-Match: <instance.version>` → 409 if stale (rare for a single filler, but mirrored from the contract).

## `SCM-CHK-SUBMIT` — Submit Checklist (`screens/05-checklist-submit.html`)

- **Purpose:** final review + submit; the **photo gate** is enforced here (and server-side).
- **Given** Karan taps Review & Submit, **Then** show a summary: count of G vs A items, the completion photo thumbnail(s), and any A items with their issue-photo thumbnails.
- **Submit gate (§4a, §9 #7, L7):**
  - **Given** any item is untouched, **Then** submit is blocked with an inline `danger` message listing the untouched items.
  - **Given** no completion photo, **Then** submit is blocked ("Add a completion photo to submit").
  - **Given** any A item lacks its issue photo, **Then** submit is blocked ("Item X needs a photo of the issue") and the row is highlighted.
  - **Given** all gates pass **and** Karan confirms in the **confirm-submit sheet** (`bottom-sheets/confirm-submit.html`), **Then** `POST …/submit` → instance state `SUBMITTED`, `submittedAt` set, `ApprovalStep` rows created, **TL (Priya) notified** (FCM + in-app), and the app routes to `SCM-CHK-STATUS` showing "Submitted · awaiting TL".
- The server independently re-checks the gate and returns **422** with the same `fields` shape if anything is missing — the UI never bypasses it.

## `SCM-CHK-STATUS` — My Checklist Status (`screens/06-my-status.html`)

- **Purpose:** live cascade status of the Senior Monitor's own submissions; the **send-back** re-fill entry.
- **Given** a submitted instance, **Then** render the **ApprovalTimeline** (`DESIGN_SYSTEM §6.14`) as a vertical stepper: `Filled by Karan (Senior Monitor) ✓ → TL → Store Manager → Operation Head (Done)`, each node showing actor + role + timestamp + a `StatusBadge`; the current pending node carries a ring.
- The Senior Monitor sees the **real** sub-state (Submitted / TL Approved / SM Approved / Done) — not "Pending" (that is the higher roles' view, L8).
- **Given** an instance was **Sent back** (§9 #3), **Then** show a prominent **red banner** with the reject reason + a **"Re-fill"** CTA → reopens `SCM-CHK-FILL` (state `IN_PROGRESS`). Send-back always returns to **Karan** (the original filler), regardless of which approver rejected. The cascade restarts from TL on re-submit (§9 #8).
- Empty state when nothing submitted yet.

## `SCM-ROSTER-OWN` — My Roster (`screens/08-my-roster.html`)

- **Purpose:** Karan's own shifts — **read-only** (Senior Monitor cannot edit rosters, `§3`).
- **Given** the day/week toggle, **Then** show own `RosterEntry` rows (ride + shift + date), shift blocks colored by template (Morning light-blue / Evening blue wash, `DESIGN_SYSTEM §6.19`). Leave days overlaid.
- No create/edit affordance anywhere. Empty state when no shifts.

## `SCM-TEAM-STATUS` — Team / Zone status (`screens/09-team-status.html`) — ADDED (read-only)

- **Purpose:** the senior role's oversight view — *see* how the Staff Court Monitors in the same zone/team are doing today, without approving anything. Senior = more experienced; this is informal visibility/coaching, **not** the formal cascade (which starts at TL).
- **Scope:** server-filtered to the SCM's **Game Zone + own team** (the Staff Court Monitors reporting to the same Team Leader). A user/instance outside that scope → 403 (`states/forbidden.html`). The backend resolver grants SCM a **read-only** `checklist.view` (team scope) permission only — never `approve`.
- **Layout:** a per-monitor list. Each monitor card: avatar + name + ride/shift + a completion summary ("3 / 4 checklists submitted") + a row of their instances each with a `StatusBadge` (Not started / In progress / Submitted / TL Approved / Done / Sent back / Overdue) rendered via the shared `renderStatusForViewer()` (SCM viewer = real sub-state, never "Pending"). Overdue rows use the solid-red badge so they stand out.
- **Filter chips:** All · Overdue · Sent back (read-only filters; no bulk actions).
- **Tap behaviour:** tapping an instance opens a **read-only detail** — the item G/A summary, the completion + A-item photos (lightbox), and the `ApprovalTimeline` — with **no Approve / Send-back / Edit buttons**. It is the same data a manager sees, minus every write affordance.
- **Empty / all-clear:** when no monitor has activity yet, show the nothing-yet empty state; when every monitor's checklists are submitted/done, show the **all-clear positive** variant (green check, "All zone checklists submitted").
- **Hard rule:** there is **no write path** from this screen. No approve, no send-back, no reassign, no edit. If the design ever needs an action here, it is out of scope for this role and belongs to TL+.

## `SH-PROFILE` (More tab) — Profile (`screens/07-profile.html`)

- **Purpose:** the More-tab landing — own profile, role, reports-to, certified rides; a **Team / Zone status** entry; logout.
- **Given** the profile, **Then** show name, role ("Senior Court Monitor"), Game Zone, reports-to ("Priya Nair · Team Leader"), and certified rides ("Trampoline"). A menu row "Team / Zone status" opens `SCM-TEAM-STATUS`. Logout confirms then clears tokens and returns to `AUTH-LOGIN`.
- Alerts (notification center) is reachable from here and the top-bar bell.

---

## Acceptance summary (the slot's must-pass behaviours)
- [ ] Login → `/me` role-resolve → Senior Monitor Home; no nav/permission is hardcoded.
- [ ] Today's list shows exactly the auto-assigned checklists for Karan's published roster entry (own GZ, own assignments).
- [ ] G/A toggle: G = green, A = red-orange; A opens the note+photo sheet and flags photo-required.
- [ ] Per-item time = server time; initials auto-derived (no manual entry) (§9 #9).
- [ ] Submit is blocked (UI **and** server 422) unless every item is answered, ≥1 completion photo exists, and every A item has its issue photo.
- [ ] On submit: state → Submitted, TL notified, status timeline shows "awaiting TL".
- [ ] Sent-back returns to Karan with a red banner + reason + Re-fill; re-submit restarts cascade from TL (§9 #8).
- [ ] Senior Monitor sees the real sub-state of own instances (never "Pending"); roster is read-only.
- [ ] **Team / Zone status is READ-ONLY: it shows team monitors' statuses + photos + timeline with NO approve/send-back/edit anywhere, scoped to own GZ + team.**
- [ ] Offline retry preserves the in-memory draft; out-of-scope access → 403.
