# Technician (Mobile) — Cross-Role Handoffs

> The cross-role touchpoints this role fires into / receives from. The Technician is a **receiver of work-order assignments** (from the Maintenance TL) and a **producer of two outcomes** — **Done** (closes the action at the maintenance level) and **Return-with-reason** (back to the Maintenance TL). He never approves and never escalates to the Store Manager directly (`PROJECT_PLAN §3` + `CHANGE_LIST_v1.1` CL-2). Work-Order mechanics live in `FOUNDATION_SPEC §4a`.

---

## Upstream input (what arrives at the Technician)

| From | Trigger | What the Technician receives | Surfaces on |
|---|---|---|---|
| **Maintenance Team Leader** (`maintenance-tl-web`) | **Assign** a WO to me (`MTL-WO-ASSIGN` → `PATCH /work-orders/:id/assign`) | WO state → `ASSIGNED`, `assignedToId = me`; the source A-item + issue photos + instructions | `TECH-DASH`, `TECH-WO-TODAY`, `TECH-WO-DETAIL` + a `WO_ASSIGNED` notification (FCM + in-app) |
| **Maintenance Team Leader** | **Re-assign** a previously-returned WO back to me (`MTL-WO-REVIEW` → `/assign`) | WO state `RETURNED → ASSIGNED` again; the WO returns to my queue | `TECH-WO-TODAY` + a `WO_REASSIGNED` notification |
| **System (SLA sweep)** | `now() > dueAt` and not closed | WO → `OVERDUE`; due-soon warning before that | `TECH-DASH` / `TECH-WO-TODAY` overdue badge + `WO_DUE_SOON` / `WO_OVERDUE` notification |

> The A-item itself originates further upstream: a **Monitor** flags `A` on an inspection checklist → the **operations Team Leader routes** it to maintenance (`TL-CHK-VERIFY` "Route to Maintenance", spawns the WO, parent checklist → `HELD`) → the **Maintenance TL assigns** it to the Technician. The Technician only ever sees the WO once it is assigned to him.

## Downstream output (what the Technician fires)

| To | Trigger | What fires | Lands on |
|---|---|---|---|
| **(closes at maintenance level)** | Technician **marks Done** (`TECH-WO-DONE` → `PATCH /work-orders/:id/done`, ≥1 fix photo) | WO state → `DONE`, `closedAt`; `WorkOrderEvent` written. **Does NOT go to the Store Manager.** If this is the **last open WO** for the source checklist, the parent `ChecklistInstance` releases from `HELD` and resumes the approval cascade (`HELD → TL_APPROVED → …`) | `MTL-WO-REVIEW` (shows closed) + the parent checklist's status timeline resumes (`*-CHK-STATUS` / `*-CHK-OVERVIEW`) |
| **Maintenance Team Leader (Mahesh)** | Technician **returns with reason** (`TECH-WO-RETURN` → `PATCH /work-orders/:id/return { reason }`) | WO state → `RETURNED`, `returnReason` stored; **Maintenance TL notified** (FCM + in-app). He will re-assign or escalate/outsource | `MTL-WO-REVIEW` queue + a notification to Mahesh |

> **What the Technician never fires:** routing, approving, outsourcing/escalating to the Store Manager. Only the **Maintenance TL** can outsource (`MTL-WO-ESCALATE` → `/outsource`, the **only** state that reaches `SM-WO-OUTSOURCE`). Internally-fixed actions close at maintenance.

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

```
MON flags A ──route(Ops TL)──▶ WorkOrder ROUTED (parent checklist → HELD)
                                    │ assign (Maintenance TL)
                                    ▼
                            TECH-WO-TODAY (Suresh: WO assigned)
                                    │ Start → IN_PROGRESS
                    ┌───────────────┴───────────────┐
       Done (+fix photo)                       Return (+reason)
       WO → DONE                               WO → RETURNED
       closes at MAINTENANCE                   back to Maintenance TL (Mahesh)
       (NOT to Store Manager)                       │ re-assign ──▶ back to a TECH
            │                                       │ or outsource ──▶ SM-WO-OUTSOURCE
            ▼                                       ▼   (only OUTSOURCED reaches SM)
  if last open WO → parent checklist HELD → resumes cascade to Done
```

## Contract notes for the BE dev
- The **assign** handler (Maintenance TL pack) is the producer of the Technician's queue: on assign it sets `assignedToId`, writes a `WorkOrderEvent`, and enqueues a `WO_ASSIGNED` FCM + in-app notification to the Technician's `DeviceToken`s. This pack only *reads* that via `/me/work-orders` + `/me/notifications`.
- The **done** handler: photo-gate (422 if no `WorkOrderPhoto`) → `DONE` → `closedAt` → compute parent `HELD` release from `WorkOrder.@@unique(responseId)` counts (release only when **no** WO is left in a non-terminal state) → if released, hand the parent back into the cascade at the TL step. **No SM notification on Done.**
- The **return** handler: reason-required (422 if empty) → `RETURNED` → store `returnReason` + `WorkOrderEvent` → notify the **Maintenance TL** (not the SM, not the previous router).
- Do **not** expose any approve/route/assign/outsource endpoint to TECH — the resolver denies it (403). This pack consumes none of them.
