# Store Manager (Web) — Cross-Role Handoffs

> The cross-role touchpoints this role fires into / receives from. The Store Manager is the **branch hub**: it **produces** auto-assignment (by publishing rosters **and by authoring/mapping own-GZ check lists — CL-1**), is the **second approval level** (consumes TL output, produces OH input), **issues send-backs** that return to the original filler, and is the **sole recipient of outsource work-orders (CL-2)** escalated by the Maintenance TL. Cascade mechanics live in `FOUNDATION_SPEC §3` (auto-assign) + `§4` (cascade + derived Pending) + `§5` (multi-branch scoping); the WorkOrder state machine + single-track hold live in the `FOUNDATION_SPEC` WorkOrder section (CL-2).

---

## Upstream input (what arrives at the Store Manager)

| From | Trigger | What the SM receives | Surfaces on |
|---|---|---|---|
| **Operation Head** | OH creates the branch (`OH-GZ-NEW`) + rides (`OH-RIDE-MASTER`) and binds **one** Store Manager | The SM's Game Zone, its rides, and the seeded checklist templates exist; `/me` resolves `gameZoneScope=own` + the branch | whole pack (every screen is scoped to this GZ) |
| **Team Leader** | TL **approves** a submission (`TL-CHK-VERIFY` → `POST …/approve` level 1) | Instance state → `TL_APPROVED`; enters the **SM approval queue** | `SM-DASH` (Awaiting my approval), `SM-CHK-OVERVIEW`, `SM-CHK-APPROVE` + an `AWAITING_SM_APPROVAL` notification |
| **Filler (Monitor/SCM/CS) → up the chain** | Floor person submits; TL approves | The cascade reaches SM; until SM approves it reads **Pending** to SM (derived, `§9 #5`) | `SM-CHK-OVERVIEW` / `SM-DASH` Pending + approval counts |
| **System (overdue sweep)** | `now() > dueAt` and not submitted | Instance → `OVERDUE`; escalates up to SM | `SM-REP-OVERDUE`, `SM-DASH` overdue KPI |
| **Maintenance Team Leader (CL-2)** | MTL **escalates** a work-order it can't fix internally (`maintenance-tl-web` `MTL-WO-ESCALATE` → `POST /work-orders/:id/escalate`) | WorkOrder → **`OUTSOURCED`** (the **only** WO state that reaches SM) with the source A-item + issue photos + Technician return reason + MTL note; the parent `ChecklistInstance` is **HELD** | `SM-WO-OUTSOURCE` (Outsource Inbox) + a `WO_OUTSOURCED` notification. Internally-fixed actions (`wo-done`) close at the maintenance level and never reach SM. |

## Downstream output (what the Store Manager fires)

| To | Trigger | What fires | Lands on |
|---|---|---|---|
| **Every rostered person (auto-assign)** | SM **publishes** a roster period (`SM-ROSTER-PUBLISH` → `POST /roster/publish`) | Auto-assign runs: `role + certified ride + shift → templates` (+ 114-pt to the one opener) → `ChecklistInstance`s tagged to the GZ, state `NOT_STARTED`; `ROSTER_PUBLISHED` notifications | each filler's `*-CHK-TODAY` / `*-DASH` (Monitor/SCM/CS/TL packs) |
| **Operation Head (Anjali)** | SM **approves** (`SM-CHK-APPROVE` → `POST …/approve` level 2) | Instance → `SM_APPROVED`; `ApprovalStep[2].APPROVE`; **OH notified**; the OH final-approve queue gains it | `OH-CHK-APPROVE` / `OH-CHK-OVERVIEW` + a notification to Anjali |
| **Original filler (Ramesh)** | SM **sends back** (`SM-CHK-APPROVE` → `POST …/sendback` level 2, reason required) | Instance → `SENT_BACK` with reason; returns to **the original `fillerId`** (`§9 #3`), NOT the TL; on re-submit the cascade **restarts from TL** (`§9 #8`) | filler's `*-CHK-STATUS` (red banner + Re-fill) + a `SENT_BACK` notification |
| **Up the chain (derived)** | SM approves → awaiting OH | While not yet `OH_APPROVED`, the instance reads **Pending** to OH; SM now sees the real climbing state | `OH-DASH` / `OH-CHK-OVERVIEW` Pending counts |
| **Reports (roll-up)** | items recorded | G items feed `SM-REP-POSITIVE`; A items + issue photos feed `SM-REP-NEGATIVE`; missed → `SM-REP-OVERDUE`. OH sees the same rolled up across all branches | `SM-REP-*` (this pack) + `OH-REP-*` (OH pack) |
| **Auto-assign engine (CL-1)** | SM **authors + maps** an own-GZ check list (`SM-CHK-UPLOAD` → `POST /checklist-templates`; `SM-CHK-TPL-ASSIGN` → mapping) | The template + its role/ride/shift mapping enter the engine; on the next `POST /roster/publish`, matching staff auto-receive instances of it (own GZ) | each filler's `*-CHK-TODAY` / `*-DASH` (Monitor/SCM/CS/TL packs) — same as seeded templates |
| **Maintenance Team Leader (CL-2)** | SM **confirms outsource** (`SM-WO-OUTSOURCE` → `POST /work-orders/:id/outsource`) or **returns** (`…/return-to-maintenance`) | Outsource decision + note logged on the WO timeline; the parent checklist stays **HELD** until all A-item WOs close, then resumes its cascade to Done | `maintenance-tl-web` (`MTL-WO-*`) + a notification to the Maintenance TL (Vikas) |

## The closed loop (SM end-to-end)

```
OH creates GZ + rides + binds SM ──▶ SM onboards staff (≤ SM) ──▶ SM builds/uploads roster
                                                                          │ PUBLISH
                                                                          ▼ (auto-assign fires)
                              filler fills G/A + photos ──submit──▶ TL approve ──▶  SM approval queue
                                        ▲                                              │ approve
                                        │ send-back (to filler, restart from TL)        ▼
                                  filler re-fills  ◀───────────────────────  OH approve = DONE
                                                                  (until OH approves, OH sees PENDING)
```

## Contract notes for the BE dev
- **Publish is the producer of auto-assign:** the `POST /roster/publish` handler transitions entries to `PUBLISHED` and runs the engine (`FOUNDATION §3`) in the same transaction, idempotent via `ChecklistAssignment @@unique([rosterEntryId, templateId])`. Implement once; every filler pack consumes the resulting instances.
- **SM approve/sendback are level-2 only:** the `approve`/`sendback` handlers take `level` and the resolver must confirm the caller's role maps to that cascade level **and** the instance's GZ = caller's GZ. SM at TL/OH level → 403.
- **Send-back targets the original `fillerId`, not the previous approver** (`§9 #3`); the re-fill resets the `ApprovalStep` rows so the cascade restarts from TL (`§9 #8`). The SM pack only *issues* the send-back; the filler pack *reads* the outcome via `/me/submissions` + notifications.
- **Pending is derived once** via the shared `renderStatusForViewer()` (`FOUNDATION §4`) — the SM overview/dashboard pass `viewerRole=SM`. Never store "Pending".
- **Every query is GZ-filtered** server-side; the SM pack must not accept a `gameZoneId` from the client beyond its own scope (that is the OH selector's job, OH-only).
