# Operation Head (Web) — Developer Task Breakdown

> Source-of-truth task list for the Operation Head (web) slot (dev-mode v1.0 Step 3b). One row per screen + the shared dependencies. Surface = Next.js web, desktop 1440×900.
> **Team for this slot:** Web (Next.js) FE + Backend (shared cascade + RBAC) + Tester. No mobile-FE (web-primary role).
> **Priority:** P0 (must-ship Phase 1) · P1 (nice-to-have).
> **Dependencies** are topological — build in order. Foundation (Wave 0) precedes everything: schema, auth, runtime RBAC resolver, auto-assign engine, approval cascade + `renderStatusForViewer()`, `/me`, multi-branch scope, generated TS types.

---

## Columns
| Column | Meaning |
|---|---|
| Screen ID | Stable short ID (cross-refs `spec.md`, `api-contract.md`). |
| Screen file | Path under `screens/` (the pixel target). |
| States / modals | The `states/` + `modals/` variants to wire. |
| Dependencies | What must exist first. |
| Web-FE tasks | Next.js route/component/data work. |
| Backend tasks | Endpoint(s) + logic + migration notes (most are Wave-0 shared). |
| Pri | P0 / P1. |

---

## Auth + bootstrap + shell

### AUTH-LOGIN — Login
| Field | Value |
|---|---|
| Screen file | `screens/01-login.html` |
| States / modals | `states/error.html`, locked (inline) |
| Dependencies | Wave-0 auth + `/me` |
| Web-FE tasks | Login form (email/phone + password, reveal); `POST /auth/login`; store tokens; `GET /me` → route by role; locked/error states; navy-on-orange Sign In; Maniax wordmark lockup. |
| Backend tasks | (Wave 0) `POST /auth/login` (bcrypt, JWT, rate-limit→423/429); refresh/logout/forgot/reset. |
| Pri | P0 |

### OH-DASH — Operation Head Dashboard (role-resolved) — CRITICAL
| Field | Value |
|---|---|
| Screen file | `screens/02-dashboard.html` |
| States / modals | `states/loading.html`, `states/empty.html` |
| Dependencies | AUTH-LOGIN; Wave-0 `/me`; cascade + `renderStatusForViewer()`; **`GET /oh/dashboard` (flagged gap #1)** |
| Web-FE tasks | Build the **web shell** (navy 240px sidebar from `/me` nav + 64px topbar + **Game-Zone selector chip** + breadcrumb) once, reused by all OH screens; render KPI cards (Pending/Overdue/Done/Compliance%/Gaps) + per-GZ tile grid; pending-by-frequency segmented control; tile→branch drilldown via the selector; loading skeleton; empty (add first GZ). |
| Backend tasks | `GET /oh/dashboard` (all-GZ aggregate; pending-by-frequency via shared derived query; per-GZ roll-up; roster gaps — **confirm gap source #3**). |
| Pri | P0 |

## Checklists (the cascade terminal)

### OH-CHK-OVERVIEW — Checklist Status Overview — CRITICAL
| Field | Value |
|---|---|
| Screen file | `screens/15-checklist-overview.html` |
| States / modals | `states/loading.html`, `states/no-results.html`, `states/error.html` |
| Dependencies | OH-DASH; cascade + `renderStatusForViewer()` (Wave 0) |
| Web-FE tasks | `DataTable` (GZ/ride/shift/period/filler/cascade/status); compact `ApprovalTimeline` cell; `StatusBadge` with **derived Pending** (viewer=OH); filters (GZ/ride/shift/period/status) + Overdue tab; row → `OH-CHK-APPROVE` drawer when at OH step. |
| Backend tasks | `GET /checklist-instances?scope=all&...` (all GZ; `statusForViewer` via shared resolver; pagination; period/status filters incl. derived pending/overdue). |
| Pri | P0 |

### OH-CHK-APPROVE — OH Approval / Verify — CRITICAL
| Field | Value |
|---|---|
| Screen file | `screens/16-checklist-approve.html` |
| States / modals | `modals/approve-confirm.html`, `modals/send-back-reason.html`, `modals/photo-lightbox.html`, `states/error.html` |
| Dependencies | OH-CHK-OVERVIEW; cascade engine (Wave 0); send-back-to-filler (shared) |
| Web-FE tasks | Approval drawer: full `ApprovalTimeline` (OH node = ring); read-only item list (G/A + server time + initials); completion + A-item photo grid → lightbox; **green Approve (Final)** → confirm → `POST …/approve`; **red-orange Send back** → reason modal (required) → `POST …/sendback`; handle 409 (refetch) + 422 (blank reason). |
| Backend tasks | `POST /checklist-instances/:id/approve` — **terminal**: `SM_APPROVED→OH_APPROVED` (=Done), `ApprovalLog` + `ApprovalStep[3].APPROVE`, drop off Pending; 422 if not at OH step, 409 stale. `POST …/sendback` — `SENT_BACK`, required reason, notify **original filler** (§9 #3), restart-from-TL on re-submit (§9 #8). `GET …/timeline`, `GET …/photos`. |
| Pri | P0 |

## Game Zones + rides

### OH-GZ-LIST — Game Zones List
| Field | Value |
|---|---|
| Screen file | `screens/03-game-zones.html` |
| States / modals | `states/empty.html`, `states/no-results.html` |
| Dependencies | Wave-0 GameZone model |
| Web-FE tasks | `DataTable` (name/location/capacity/SM/staff/rides/compliance/status); search + status filter; +Add → `OH-GZ-NEW`; row View/Edit. |
| Backend tasks | `GET /game-zones` (all; pagination; counts + compliance roll-up). |
| Pri | P0 |

### OH-GZ-NEW — Add Game Zone
| Field | Value |
|---|---|
| Screen file | `screens/04-game-zone-new.html` |
| States / modals | `modals/assign-store-manager.html`, validation (inline) |
| Dependencies | OH-GZ-LIST; SM-role users exist |
| Web-FE tasks | Form (name/location/capacity); assign-SM modal (pick unassigned SM); `POST /game-zones`; duplicate-name validation. |
| Backend tasks | `POST /game-zones` (enforce `storeManagerId @unique` — one SM/GZ); `GET /users?role=SM&unassignedGz=true`. |
| Pri | P0 |

### OH-GZ-EDIT — Edit Game Zone
| Field | Value |
|---|---|
| Screen file | `screens/05-game-zone-edit.html` |
| States / modals | `modals/assign-store-manager.html` (reassign-SM confirm), deactivate (inline) |
| Dependencies | OH-GZ-LIST |
| Web-FE tasks | Edit form; reassign-SM confirm (frees previous SM scope); deactivate toggle; `PATCH /game-zones/:id` with `If-Match`. |
| Backend tasks | `PATCH /game-zones/:id` (reassign SM, isActive, 409 stale, audit). |
| Pri | P0 |

### OH-GZ-DETAIL — Game Zone Detail
| Field | Value |
|---|---|
| Screen file | `screens/06-game-zone-detail.html` |
| States / modals | `states/loading.html`, tabs (inline) |
| Dependencies | OH-GZ-LIST; users/rides/roster/checklist reads |
| Web-FE tasks | Tabbed page (Staff / Rides → `OH-RIDE-MASTER` / Rosters read-only / Checklists status); each tab GZ-scoped. |
| Backend tasks | `GET /game-zones/:id` (branch end-to-end summary). |
| Pri | P0 |

### OH-RIDE-MASTER — Rides / Activity Zones Master
| Field | Value |
|---|---|
| Screen file | `screens/07-ride-master.html` |
| States / modals | add/edit ride (inline modal), deactivate |
| Dependencies | OH-GZ-DETAIL |
| Web-FE tasks | Ride table (name/code/active) per GZ; add/edit modal; deactivate (soft). |
| Backend tasks | `GET/POST /game-zones/:id/rides`, `PATCH /rides/:id` (code unique within GZ). |
| Pri | P0 |

## People + hierarchy + RBAC

### OH-USERS — All Users (cross-GZ)
| Field | Value |
|---|---|
| Screen file | `screens/08-users.html` |
| States / modals | `states/empty.html`, `states/no-results.html` |
| Dependencies | Wave-0 User model |
| Web-FE tasks | `DataTable` (name/role/GZ/reports-to/certs/status); filters GZ + role + search; row → `OH-USER-DETAIL` drawer; +Onboard → `OH-USER-NEW`. |
| Backend tasks | `GET /users?...` (all GZ; pagination; filters). |
| Pri | P0 |

### OH-USER-NEW — Onboard User
| Field | Value |
|---|---|
| Screen file | `screens/09-user-new.html` |
| States / modals | validation (inline), wizard steps |
| Dependencies | OH-USERS; GameZone + rides exist |
| Web-FE tasks | 5-step wizard (details→role→reports-to→GZ→certified rides); reports-to filtered by §3 hierarchy + GZ; cert-rides multiselect; `POST /users`. |
| Backend tasks | `POST /users` (uniques, valid reports-to for role/GZ); `GET /managers?roleId=&gameZoneId=`. |
| Pri | P0 |

### OH-USER-EDIT — Edit User
| Field | Value |
|---|---|
| Screen file | `screens/10-user-edit.html` |
| States / modals | `modals/reassign-manager.html`, `modals/deactivate-user.html` |
| Dependencies | OH-USERS |
| Web-FE tasks | Edit (role/reports-to/GZ/certs); reassign-manager confirm (sub-tree impact); deactivate modal; `PATCH /users/:id` with `If-Match`. |
| Backend tasks | `PATCH /users/:id` (reassign, deactivate, 409, audit). |
| Pri | P0 |

### OH-USER-DETAIL — User Detail
| Field | Value |
|---|---|
| Screen file | `screens/11-user-detail.html` |
| States / modals | drawer, `states/loading.html` |
| Dependencies | OH-USERS |
| Web-FE tasks | Right-side drawer: identity/role/GZ/reports-to + reports + certs + checklist history with `StatusBadge`. |
| Backend tasks | `GET /users/:id` (profile + sub-tree + checklist history). |
| Pri | P0 |

### OH-ROLES — Roles & Access Matrix (editable) — CRITICAL
| Field | Value |
|---|---|
| Screen file | `screens/12-roles-matrix.html` |
| States / modals | save toast, scope-change confirm (inline) |
| Dependencies | Wave-0 RBAC (`Role`/`Permission`/`RolePermission`); **matrix endpoints (flagged gap #2)** |
| Web-FE tasks | Editable grid (rows=permissions, cols=roles); per-cell allowed toggle + scope select; Trainee-TL=TL note; live `PATCH` on change; reset-to-seed; optimistic UI + audit feedback. |
| Backend tasks | `GET /roles/matrix`, `PATCH /roles/:roleId/permissions` (write `RolePermission` + `updatedBy`; **effective next request, no redeploy**), `POST /roles/matrix/reset`. |
| Pri | P0 |

### OH-HIER-TREE — Hierarchy Tree (org-wide)
| Field | Value |
|---|---|
| Screen file | `screens/13-hierarchy.html` |
| States / modals | expand/collapse, per-GZ filter |
| Dependencies | Wave-0 User reportsTo chain |
| Web-FE tasks | `HierarchyTree` (7-level, role-colored chips); per-GZ filter; node → `OH-USER-DETAIL`. |
| Backend tasks | `GET /hierarchy?gameZoneId=` (org tree; GZ filter). |
| Pri | P0 |

## Roster overview (read-only)

### OH-ROSTER-ALL — All-Zones Roster Overview
| Field | Value |
|---|---|
| Screen file | `screens/14-roster-all.html` |
| States / modals | `states/empty.html`, day/week/month toggle |
| Dependencies | Wave-0 roster; **gap source (flagged gap #3)** |
| Web-FE tasks | Roster grid across zones (template-colored blocks); day/week/month toggle; **gap-alert badge**; **no create/edit/publish affordance** (read-only). |
| Backend tasks | `GET /roster?scope=all&date=/weekOf=` (read across zones; `gaps[]`). |
| Pri | P0 |

## Reports

### OH-REP-POSITIVE — Positive Report (org)
| Field | Value |
|---|---|
| Screen file | `screens/17-report-positive.html` |
| States / modals | `states/empty.html` (all-clear), export |
| Dependencies | cascade reads |
| Web-FE tasks | `DataTable` of compliant (all-G) instances; GZ/ride/shift filters + date range; Export ▾. |
| Backend tasks | `GET /reports/positive?scope=all&...`; `…/export` (**flagged gap #4**). |
| Pri | P0 |

### OH-REP-NEGATIVE — Negative Report (org) — CRITICAL
| Field | Value |
|---|---|
| Screen file | `screens/18-report-negative.html` |
| States / modals | `modals/photo-lightbox.html`, export |
| Dependencies | photo viewer; cascade reads |
| Web-FE tasks | A-item rows (GZ/ride/shift/item/note/filler/time/photo); thumbnail → lightbox; GZ filter; Export ▾. |
| Backend tasks | `GET /reports/negative?scope=all&...` (A-items + issue photos, local-disk URLs). |
| Pri | P0 |

### OH-REP-OVERDUE — Overdue / Escalation Report
| Field | Value |
|---|---|
| Screen file | `screens/20-report-overdue.html` |
| States / modals | export, drilldown |
| Dependencies | overdue sweep (Wave 0) |
| Web-FE tasks | Overdue rows (GZ/ride/shift/template/dueAt/lateBy/state, solid-red badge); GZ drilldown; Export ▾. |
| Backend tasks | `GET /reports/overdue?scope=all&...` (derived overdue). |
| Pri | P0 |

### OH-CHK-UPLOAD — Upload Check List (template list + create) *(CL-1)* — CRITICAL
| Field | Value |
|---|---|
| Screen file | `screens/21-checklist-upload.html` |
| States / modals | loading, empty, no-results; `modals/change-items-confirm.html`; builder Stepper |
| Dependencies | rides + roles; auto-assign engine (FOUNDATION_SPEC §3) |
| Web-FE tasks | Template `DataTable` (name/frequency/ride/fill-role/GZ-scope/source/status) with filters + row Assign/Edit; `ChecklistBuilder` (§6.21) Stepper (Details → Sections&Items → Assign → Review): name, frequency (incl. opening/closing), ride, fill-role, GZ scope, section/item tree (drag/reorder), item editor (text, test method, G/A, requires-photo-on-A); validation; Save-draft. |
| Backend tasks | `GET /checklist-templates?scope=all&...`; `GET /checklist-templates/:id`; `POST /checklist-templates`; `PATCH /checklist-templates/:id` (versioned) — **flagged gap #6**. |
| Pri | P0 |

### OH-CHK-TPL-ASSIGN — Assign Check List *(CL-1)*
| Field | Value |
|---|---|
| Screen file | `screens/22-checklist-tpl-assign.html` |
| States / modals | builder step 3, scope picker; `modals/assign-template.html` |
| Dependencies | `OH-CHK-UPLOAD`; auto-assign engine |
| Web-FE tasks | Assign mapping form (fill-role / ride / shift / GZ scope) + summary; standalone assign modal from the list; feeds auto-assign. |
| Backend tasks | `POST /checklist-templates/:id/assign`; `GET /checklist-templates/:id/assignments` — **flagged gap #6**. |
| Pri | P0 |

### OH-CHK-TPL-EDIT — Edit Check List *(CL-1)*
| Field | Value |
|---|---|
| Screen file | `screens/23-checklist-tpl-edit.html` |
| States / modals | builder re-entry, change-items warning; `modals/change-items-confirm.html` |
| Dependencies | `OH-CHK-UPLOAD` |
| Web-FE tasks | Reuse the builder to edit items/test-methods/mapping; change-items warning banner + confirm modal on save; deactivate (soft); `If-Match`. |
| Backend tasks | `PATCH /checklist-templates/:id` (versioned — applies next auto-assign cycle); 409 stale — **flagged gap #6**. |
| Pri | P0 |

### OH-WO-OVERVIEW — Action / Work-Order Overview (org) *(CL-2)* — CRITICAL
| Field | Value |
|---|---|
| Screen file | `screens/24-wo-overview.html` |
| States / modals | filter (GZ/ride/state/priority), state-KPI strip, drilldown drawer |
| Dependencies | WorkOrder entity + state machine (FOUNDATION_SPEC CL-2); maintenance-tl-web (owns mutations) |
| Web-FE tasks | `wo-*` state-KPI strip; `DataTable` (WO#/GZ/ride/A-item/source/technician/age-SLA/state) with `StatusBadge wo=…`; filters; **read-only** drilldown drawer (no route/assign/close); Held note. |
| Backend tasks | `GET /work-orders?scope=all&...` (+ stateCounts, heldChecklists); `GET /work-orders/:id` — read-only for OH (`workorder.view`); **flagged gap #7**. |
| Pri | P0 |

### SH-PROFILE — Profile / Settings
| Field | Value |
|---|---|
| Screen file | `screens/19-profile.html` |
| States / modals | — |
| Dependencies | Wave-0 `/me` |
| Web-FE tasks | Profile (name/role/email; OH has no reports-to/certs); Alerts entry; logout (confirm → clear tokens → login). |
| Backend tasks | `GET /me/profile`; `POST /auth/logout`; `GET /me/notifications` + read. |
| Pri | P0 |

---

## Build order (topological)
1. **(Wave 0)** auth, `/me`, RBAC resolver, schema, auto-assign, cascade + `renderStatusForViewer()`, multi-branch scope, TS types.
2. `AUTH-LOGIN` → `OH-DASH` (web shell + sidebar + topbar GZ selector + role-resolve).
3. `OH-CHK-OVERVIEW` → `OH-CHK-APPROVE` (the terminal-approval flow — depends on cascade + send-back-to-filler).
4. `OH-GZ-LIST` → `OH-GZ-NEW`/`OH-GZ-EDIT`/`OH-GZ-DETAIL` → `OH-RIDE-MASTER` (Game Zone + rides — gate the rest of the data).
5. `OH-USERS` → `OH-USER-NEW`/`OH-USER-EDIT`/`OH-USER-DETAIL`; `OH-ROLES` (live RBAC matrix); `OH-HIER-TREE`.
6. `OH-ROSTER-ALL`, `OH-REP-POSITIVE`/`OH-REP-NEGATIVE`/`OH-REP-OVERDUE`, `SH-PROFILE` (independent; parallel).
7. **(CL-1)** `OH-CHK-UPLOAD` → `OH-CHK-TPL-ASSIGN`/`OH-CHK-TPL-EDIT` (the `ChecklistBuilder` + auto-assign mapping; depends on rides + roles + the auto-assign engine).
8. **(CL-2)** `OH-WO-OVERVIEW` (read-only WO overview; depends on the WorkOrder entity + state machine, mutations owned by `maintenance-tl-web`).

> The OH demo gate: **Anjali logs in → sees all-GZ Pending on the dashboard → opens an SM-approved Trampoline Daily → reviews G/A + photos read-only → Approves = Done (drops off Pending) → on another, Sends back with a reason → it returns to the original filler (not SM) → she edits the RBAC matrix and the change takes effect on the next request.** When that closes end-to-end against real APIs, the OH slot is DONE.
