# Team Leader (Web) — Developer Task Breakdown

> Source-of-truth task list for the TL web slot (dev-mode v1.0 slot 6). One row per screen + the shared dependencies. Surface = Next.js web 1440px.
> **Team for this slot:** Web (Next.js) FE + Backend (shared cascade — TL is the first approver) + Tester. TL mobile companion deferred to the mobile sub-phase.
> **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 (incl. approve-by-level + `own_team` scope), auto-assign engine, approval cascade, `/me`, photo endpoint, web DS parity, generated TS models.

---

## 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

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

### TL-DASH — Team Leader Dashboard (role-resolved)
| Field | Value |
|---|---|
| Screen file | `screens/02-dashboard.html` |
| States / modals | `states/loading.html`, `states/empty.html` |
| Dependencies | AUTH-LOGIN; Wave-0 `/me`; cascade (submit producer); auto-assign |
| Web-FE tasks | Build the web shell (navy 240px sidebar from `/me` nav + 64px topbar w/ branch badge + team indicator); KPI tiles (awaiting-my-approval, in-progress, done-today, overdue, gaps); verify-queue panel + team-progress panel; loading skeleton; empty (all-clear). |
| Backend tasks | `GET /me/team/dashboard` (own team + GZ; counts; verify queue; team progress). |
| Pri | P0 |

## Team

### TL-TEAM — My Team
| Field | Value |
|---|---|
| Screen file | `screens/03-team.html` |
| States / modals | `states/loading.html`, `states/empty.html` |
| Dependencies | TL-DASH; Wave-0 hierarchy |
| Web-FE tasks | `DataTable`: name · role chip · certified rides · today shift · progress mini-bar · last active; search + role filter; row → member detail; no create/edit affordance. |
| Backend tasks | `GET /me/team` (reportsTo chain ⊆ me, own GZ; pagination). |
| Pri | P0 |

### TL-USER-DETAIL — Team Member Detail
| Field | Value |
|---|---|
| Screen file | `screens/04-team-member-detail.html` |
| States / modals | `states/loading.html`, `modals/photo-viewer.html` |
| Dependencies | TL-TEAM |
| Web-FE tasks | Profile + certs + checklist-history table; cascade drilldown; photos → viewer; read-only (no edit). |
| Backend tasks | `GET /users/:id` (team-scoped; 403 if not in team; checklist history). |
| Pri | P1 |

## Checklist verify (the TL core)

### TL-CHK-OVERVIEW — Team Checklist Status
| Field | Value |
|---|---|
| Screen file | `screens/05-checklist-overview.html` |
| States / modals | `states/loading.html`, `states/empty.html`, `states/error.html`, `states/forbidden.html` |
| Dependencies | TL-DASH; cascade; `renderStatusForViewer()` (Wave 0) |
| Web-FE tasks | `DataTable`: template · ride · shift · filler · mini cascade timeline · `StatusBadge` (viewer-resolved) · due; Active/Overdue tabs; filters; Verify action → verify; loud sent-back row. |
| Backend tasks | `GET /me/team/checklists` (team scope; `statusForViewer`; tab/filter/pagination). |
| Pri | P0 |

### TL-CHK-VERIFY — TL Verify / Approve (CRITICAL)
| Field | Value |
|---|---|
| Screen file | `screens/06-checklist-verify.html` |
| States / modals | `modals/photo-viewer.html`, `modals/send-back-reason.html`, **`modals/route-to-maintenance.html`** (CL-2), HeldBanner, `states/offline.html`, `states/forbidden.html`, **`states/trainee-tl-assist-only.html`** (CL-3) |
| Dependencies | TL-CHK-OVERVIEW; instance detail; cascade approve/sendback (Wave 0); photo viewer; **WorkOrder entity + state machine** (CL-2); RBAC Trainee split (CL-3) |
| Web-FE tasks | Two-column: left read-only item review (G/A + note + time + initials + A-photo thumbs + completion strip + **per-A WO chip + Route-to-Maintenance action**); right decision rail (filler card + `ApprovalTimeline` w/ TL node + **Approve** green + **Send back** red + **Route** navy); **HeldBanner** (`§6.24`, `st-held` #C2410C) when WOs open → **Approve disabled while HELD**; route-to-maintenance modal (target MTL, priority, note); photo thumbnails → lightbox; approve-confirm; send-back-reason modal; `If-Match`; 409/403 handling; offline draft; **Trainee TL: render Approve/Send-back/Route disabled from `/me` flags**. |
| Backend tasks | `GET /checklist-instances/:id` (team approver scope; version/ETag; full items+photos+timeline + **`workOrders[]`**); `POST …/approve` (level-resolved → `TL_APPROVED`; **409/422 if `HELD`**; notify SM; audit); `POST …/sendback` (reason→422; `SENT_BACK`; original `fillerId`; notify filler; audit); **`POST /work-orders`** (one WO per A-response → `ROUTED`; instance → `HELD`; notify Maintenance TL; idempotent `@@unique(responseId)`); release `HELD → TL_APPROVED` when last WO closes; **resolver: TL can't approve own-filled (→SM); Trainee TL `allowed:false` on approve/sendback/route**. |
| Pri | P0 |

### TL-CHK-FILL — Fill Checklist (TL can fill)
| Field | Value |
|---|---|
| Screen file | `screens/07-checklist-fill.html` |
| States / modals | `states/offline.html`, inline A-note+photo + completion strip |
| Dependencies | TL-CHK-OVERVIEW; photo endpoint; instance detail; cascade |
| Web-FE tasks | Sectioned `ChecklistItem` rows w/ G/A segmented toggle (G green / A red-orange); read-only server-time + auto-initials; on A require note+photo; completion `PhotoUpload` strip; `PATCH …/responses` drafts (`If-Match`); submit gate client-side; multipart upload; offline draft + retry. |
| Backend tasks | `GET /checklist-instances/:id` (own filler); `PATCH …/responses` (server time + auto-initials, set fillerId, version, 409, audit); `POST …/submit` (re-check gate→422; `SUBMITTED`; **next approver = SM when filler is TL**; create steps; notify SM; audit); `POST /uploads/photos` + DELETE (local disk, sharp thumb). |
| Pri | P1 |

## Team roster + assign

### TL-ROSTER — Team Roster Builder
| Field | Value |
|---|---|
| Screen file | `screens/08-roster-builder.html` |
| States / modals | `modals/publish-roster.html`, conflict warn, leave overlay |
| Dependencies | Wave-0 roster + auto-assign |
| Web-FE tasks | `Calendar/Roster grid` day/week; rows = team members; shift blocks template-colored; opener toggle; drag-drop w/ conflict warn; leave overlay; gap-alert badges; Publish → publish-roster confirm modal (fires auto-assign for the team). |
| Backend tasks | `GET /me/team/roster`; `POST/PATCH/DELETE /roster/entries` (own-team scope; 403 non-team; 409 dup); `POST /roster/publish` (scope team → auto-assign; idempotent). |
| Pri | P0 |

### TL-ROSTER-VIEW — Team Roster View (read)
| Field | Value |
|---|---|
| Screen file | `screens/09-roster-view.html` |
| States / modals | `states/empty.html`, day/week/month toggle |
| Dependencies | Wave-0 roster |
| Web-FE tasks | Day/week/month toggle; team `RosterEntry` rows template-colored; leave overlay; gap-alert badges; read-only (this is what the TL mobile companion mirrors). |
| Backend tasks | `GET /me/team/roster` (reuse; date/weekOf). |
| Pri | P1 |

### TL-ROSTER-REASSIGN — Mid-Shift Reassign (CL-4)
| Field | Value |
|---|---|
| Screen file | `screens/13-roster-reassign.html` |
| States / modals | `modals/reassign-monitor.html`, re-target preview, conflict warn |
| Dependencies | Wave-0 roster + auto-assign; **rotation-aware reassign** (`FOUNDATION_SPEC §3a`); FCM push; certification gate |
| Web-FE tasks | Current-floor board (rostered ride · **current ride (live)** · on-ride-since · today's counts · certified-for · Reassign); reassign modal (AllocationBoard §6.23) w/ **certified-only ride picker** + re-target preview + conflict warn; confirm/undo toast; **Trainee TL: Reassign disabled** from `/me` flags. |
| Backend tasks | `GET /me/team/floor` (live current ride per monitor); `PATCH /roster-entries/:id/reassign { newRideId }` — `assertCertified`→422; re-target **`NOT_STARTED`** instances to monitor; move old ride to current holder; **`IN_PROGRESS`/`SUBMITTED` NOT withdrawn**; FCM `ride-changed` to both; `AuditLog("ROSTER_REASSIGNED")`; **Trainee TL `allowed:false`**. |
| Pri | P0 |

### TL-CHK-UPLOAD — Upload Check List (team templates, CL-1)
| Field | Value |
|---|---|
| Screen file | `screens/14-checklist-upload.html` |
| States / modals | builder wizard (Stepper §6.17), assign sub-step |
| Dependencies | Wave-0 RBAC (`template.*` own_team); auto-assign engine; **ChecklistTemplate builder fields** (CL-1) |
| Web-FE tasks | **ChecklistBuilder §6.21** team-scoped: Stepper (Details → Sections & Items → Assign → Review); left section/item tree (drag add/reorder) + right item editor (text, test method, G/A, requires-photo-on-A); Assign sub-step (role/ride/shift); Save = orange Primary; **Trainee TL: read-only (no save/assign)**. |
| Backend tasks | `GET /me/team/templates`; `POST /checklist-templates` (gz forced to own; fill-role ⊆ team; 403 if scope exceeds; 422); `GET/PATCH /checklist-templates/:id`; `POST /checklist-templates/:id/assign` (feeds auto-assign); **Trainee TL `allowed:false` on create/edit/assign**. |
| Pri | P1 |

### TL-CHK-ASSIGN — Team Checklist Assign (override)
| Field | Value |
|---|---|
| Screen file | `screens/10-checklist-assign.html` |
| States / modals | `modals/assign-checklist.html` |
| Dependencies | TL-CHK-OVERVIEW; auto-assign (Wave 0) |
| Web-FE tasks | `DataTable` of auto-assigned instances (template · ride · shift · current filler · reason · status); Assign/Reassign → assign modal (member picker filtered to certified+rostered). |
| Backend tasks | `GET /me/team/assignments`; `POST /checklist-instances/:id/reassign` (toUserId in team + certified; 403 otherwise; audit). |
| Pri | P1 |

## Report + profile

### TL-REP-NEGATIVE — Team Negative Report
| Field | Value |
|---|---|
| Screen file | `screens/12-report-negative.html` |
| States / modals | `modals/photo-viewer.html`, `states/empty.html` (all-clear) |
| Dependencies | cascade + responses + photos |
| Web-FE tasks | Grouped A-item list/table (item · ride · shift · filler · date · note · issue-photo thumb → lightbox); date-range + ride filters; Export ▾ (PDF/Excel); all-clear empty state. |
| Backend tasks | `GET /me/team/reports/negative` (team scope; A items + photos); `…/export?format=`. |
| Pri | P1 |

### SH-PROFILE — Profile / More
| Field | Value |
|---|---|
| Screen file | `screens/11-profile.html` |
| States / modals | — |
| Dependencies | Wave-0 `/me` |
| Web-FE tasks | Profile (name, role, Game Zone, reports-to, certified rides); 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 (approve-by-level + `own_team` scope + TL-can't-self-approve + **Trainee-TL `allowed:false` split**, CL-3), schema (**+ WorkOrder + HELD state**, CL-2; **+ ChecklistTemplate builder fields**, CL-1), auto-assign (**+ rotation-aware reassign**, CL-4), cascade, `renderStatusForViewer()` (**+ Held**), photo endpoint, web DS, TS models.
2. `AUTH-LOGIN` → `TL-DASH` (shell + role-resolve + verify queue + **Actions-held KPI/row**).
3. `TL-CHK-OVERVIEW` → `TL-CHK-VERIFY` (the TL core — approve + send-back **+ Route-to-Maintenance + single-track Hold**, CL-2; **Trainee assist-only disabled variant**, CL-3). **This is the slot's demo gate.**
4. `TL-ROSTER` (publish → auto-assign) + **`TL-ROSTER-REASSIGN`** (mid-shift reassign, CL-4) + `TL-TEAM` (parallel).
5. `TL-CHK-FILL`, `TL-CHK-ASSIGN`, **`TL-CHK-UPLOAD`** (team templates, CL-1), `TL-ROSTER-VIEW`, `TL-USER-DETAIL`, `TL-REP-NEGATIVE`, `SH-PROFILE` (P1; parallel).

> The TL demo gate: **Priya logs in → sees Ramesh's submitted Trampoline Daily in her verify queue → opens it, reviews items + photos in the lightbox → Sends back with a reason (returns to Ramesh) → Ramesh re-fills + re-submits → it re-enters Priya's queue → Priya Approves → it passes to SM, and SM/OH see Pending.** When that closes end-to-end against real APIs, the TL slot is DONE, and SM/OH packs reuse the same approve/report shapes at levels 2/3.
