- Add ProductionTemplatesPage component for managing production templates with a visual representation using React Flow. - Create LineHeaderNode and LineStageNode components for rendering production line nodes. - Introduce RunStageNode and RunHeaderNode components for displaying run stages and headers. - Implement StageProgressStrip for visualizing stage progress in runs. - Create mock data for production runs and templates to simulate backend functionality. - Define types for production templates and runs to structure mock data. - Document frontend Phase 2 specifications for manufacturing processes, including screens, dialogs, and validation posture.
12 KiB
21 · FRONTEND-PHASE2 — Manufacturing: Production Lines (Flows & Rules)
Purpose: Frontend source of truth for Phase 2 (Manufacturing): the template canvas builder, the run board, and run execution screens. API contract and all business rules live in
30-BACKEND-PHASE2.md— this doc never redefines them. Validation posture follows20-FRONTEND §3: client validation is UX only; the server is authoritative. Register this doc in00-CORE.md §7and01-DOC-GUIDE.md §2.
1. Screens
| Screen | Route (suggested) | Actual route (frontend-only build) | Purpose |
|---|---|---|---|
| Template list | /production/templates |
/dashboard/production/templates — a single shared React Flow canvas, one row per template (header + stages left→right), not a list/grid |
Browse templates, status, active-run count; open builder. |
| Template builder (canvas) | /production/templates/{id} |
/dashboard/production/templates/{id} |
Drag-and-drop stage graph design. |
| Run board | /production/runs |
/dashboard/production/runs |
All runs with per-stage progress at a glance. |
| Start run dialog | modal from board/list | modal from run board | Pick template, target qty, warehouse; preview scaled quantities. |
| Run detail | /production/runs/{id} |
/dashboard/production/runs/{id} |
Read-only graph with live statuses + stage action drawer. |
Build status: §§1–4 are implemented as a frontend-only mock (per-page
useState, no persistence across pages/reloads) — noDtos/Productionor30-BACKEND-PHASE2.mdexist yet, so nothing here talks to a real API. §5 (Run detail) is implemented in a simplified form: one generic per-stage advance action instead of the full status-specific stage drawer. §6 (validation/error posture) does not apply yet — there's no server to surfaceProblemDetails/error codes from. See §8 for the itemized gap list.
2. Template builder (canvas)
Library: React Flow (drag/drop nodes, edge drawing, pan/zoom, minimap). Node positions map 1:1 to posX/posY; the backend stores layout uninterpreted, so all layout behavior is client-owned.
Node (stage card) shows: name, role label chip, estimated minutes, input count → output count. Selecting a node opens the stage editor panel:
- Name, role label (free text with suggestions e.g. QA, Assembly), estimated minutes.
- Formula rows — Inputs: source toggle
Stock | Upstream; Stock → Item picker (active items only) + UOM + qty/batch; Upstream → dropdown of direct parents' outputs only (disable others). Outputs: name + UOM + qty/batch; on the terminal stage the single output requires an Item picker (finished good). - Custom field builder — add/remove fields: key (auto-slug from label), label, type (
Text|Number|Checkbox|Date|Select+ options), required toggle. Serialized to thefieldDefsjsonb shape verbatim.
Edges: drawn parent → child. Client blocks duplicate edges and self-loops at draw time.
Client-side graph checks (UX only — server re-validates on save):
- Cycle detection (toposort) — highlight the offending edge.
- Exactly one terminal (no-outbound) node — banner "Connect stages so the line converges to a single final stage" when ≠1.
- ≥1 entry node; no disconnected nodes (grey them out).
- Terminal output has an Item; Upstream inputs reference a current direct parent (re-check after edge deletions and clear broken references with a warning toast).
Save: full-graph POST/PUT with If-Match. Surface 422 GRAPH_* codes by focusing the offending node/edge. Edit lock: when activeRunCount > 0, render the canvas read-only with a banner "Template locked — N run(s) in progress" (server enforces via 409 TEMPLATE_IN_USE; the banner is UX). Deactivate action instead of delete.
3. Run board
List/grid of runs, newest first, filters: status, template, warehouse, search by doc no.
Each row/card: docNo (PRD-2026-00001), template name, target qty + finished item, created/completed timestamps, rework badge when reworkCount > 0, and a stage progress strip rendered from stageSummary — one segment per stage-status count using the canonical colors:
| Status | Color |
|---|---|
| Waiting | grey #9CA3AF |
| Ready | blue #3B82F6 |
| InProgress | amber #F59E0B |
| Done | green #22C55E |
| Approved | teal #14B8A6 |
| Run Cancelled | red accent on the card |
| Run Completed | full teal strip + check |
These colors are the single source for status coloring everywhere (board, run graph, drawers, legend). Show a legend on the board.
4. Start run dialog
- Template picker (Active only), target quantity (of the finished item, unit shown), warehouse, optional output bin.
- Scaled preview: client computes
scaleFactor = targetQty / terminalOutputQtyPerBatchand shows every stage's scaled inputs/outputs as a preview only — the authoritative scaled figures come back on the201response. - On create → navigate to run detail. Quantity fine-tuning happens there via the per-stage quantities editor (not in this dialog).
- As built: stays on the run board with a success toast instead of navigating — the new run's stages start
waiting: stageCount-1, ready: 1and the user opens it from the board like any other run.
- As built: stays on the run board with a success toast instead of navigating — the new run's stages start
5. Run detail
As built (mock): a single-row React Flow line (header box + one box per real stage name, left→right) instead of the full copied-template graph, with a header progress bar/percentage and one Give Progress action (canvas button on the active stage, and a mirrored button in the header) that steps that stage through the canonical status sequence
Waiting → Ready → InProgress → Done → Approved. No drawer, no per-status action set, no quantities/scrap/custom-field forms, no delivered/available badges, no polling (single local page, no backend to refetch from). All state is localuseState— reloading the page resets to the seeded mock run. See §8.
Layout: the template graph re-rendered read-only (same React Flow canvas, positions from the run's copied stages), each node colored by live status, with deliveredQty/plannedQty badges on inbound edges and an available-to-transfer badge on approved stages holding a remainder. Poll or refetch after every action.
Stage drawer (click a node) — content by status:
- Any status: name, role chip, estimated vs actual time (
actualStartAt/actualEndAt, live elapsed while InProgress), event history timeline. - Waiting: per-upstream-input delivery progress bars; nothing actionable except Reject intake when
deliveredQty > 0(see below). - Ready: Edit quantities (planned in/out — disabled after start, surface
409 STAGE_NOT_EDITABLE), Stock-input availability hints (on-handenquiry, advisory only — never block client-side, per20-FRONTEND §3), and Start. On start errors surfaceSTOCK_NEGATIVE_BLOCKED/ONHOLD_NOT_ISSUABLE/EXPIRED_BATCH_BLOCKEDwith the item named. - InProgress: Complete form — per output: produced qty, scrapped qty (reason-code picker appears and becomes required when scrap > 0), plus the custom field form rendered from
fieldDefs(required fields block submit client-side; server backs with400 REQUIRED_FIELD_MISSING). - Done: Approve — non-terminal: default "transfer all" with an optional per-output partial amount (validated ≤ available); terminal: confirmation summarizing the receipt (qty, computed unit cost from cost pool preview). Terminal also offers Reject with a strong confirm modal: "This resets the entire run to its starting stages (rework #N). Consumed materials remain in the run."
- Approved (non-terminal): Transfer remainder action while available > 0 (
422 TRANSFER_EXCEEDS_AVAILABLEsurfaced inline). - Reject intake (on a Ready/Waiting stage with deliveries): confirm modal "Returns work to the previous completed stage for rework" → parents visibly flip back to InProgress on refresh.
Run-level actions: Return leftover (per started Stock input: qty ≤ consumed − returned, reason code required; hidden once run Completed — RUN_COST_CLOSED), Cancel run (reason code + note, confirm modal explaining stock return; hidden when Completed).
6. Validation posture & error surfacing
- Client checks: required/format/range, graph checks (§2), qty ≤ available style guards — all UX; never assume stock rules client-side.
- Every
ProblemDetailsrenders itstitle; map domaincodes to friendly inline messages (table in30-BACKEND-PHASE2 §D.4). Unknown codes fall back to the ProblemDetails title + trace id. 412 CONCURRENCY_CONFLICT→ "This item changed elsewhere — reloading" + refetch. Stage-action409s (wrong status) → refetch the run silently and re-render; another user likely acted first.- Stage-transition posts send an
Idempotency-Key(uuid per click) so double-clicks are replay-safe.
7. Foundation additions (PROGRESS seed)
- React Flow dependency + canvas components — but not a single shared editable/read-only variant: the template-overview canvas (
templates/page.tsx), the builder canvas (templates/[id]/page.tsx), and the run-detail canvas (runs/[id]/page.tsx) are three separate node-type sets (ProductionLineNodes.tsx,StageNode.tsx/AnnotationNodes.tsx,RunStageNode.tsx). - Types mirroring
Dtos/Production(template graph, run graph, stage actions) — not started;types/production.tsis a standalone frontend-only placeholder shape, nothing to mirror against yet. - Status-color tokens (§3 table) exported from one module —
lib/production-status-colors.ts(STAGE_STATUS_COLOR/_LABEL/_ORDER,RUN_CANCELLED_COLOR,RUN_COMPLETED_COLOR). - [~] Custom-field renderer (defs jsonb → form) + builder (form → defs jsonb) — builder half only (
StageEditorPanel.tsx, defs jsonb ← form). The runtime renderer (form → filled values, used during the spec'd Complete action) doesn't exist since there's no stage drawer/Complete step (§5). - [~] Screens: template list · builder · run board · start dialog · run detail + drawer — list/builder/board/dialog implemented (as mock); run detail implemented without the drawer or per-status action set (§5, §8).
- Error-code → message map for §D.4 additions — not started, no backend/
ProblemDetailsto map yet.
8. Gaps vs. this spec (frontend-only mock — no Dtos/Production / 30-BACKEND-PHASE2.md yet)
Everything below is intentional scope for the current build, not a bug — recorded so whoever wires up the real backend knows exactly what's still owed against this doc:
- No persistence. All state is per-page
useStateseeded from hardcoded mock arrays (lib/production-mock-templates.ts,lib/production-mock-runs.ts). Templates, runs, and stage-status edits don't survive a reload and don't sync across the three canvases/pages. - Run detail is a simplified single action, not the stage drawer (§5). One generic "Give Progress" step (Waiting→Ready→InProgress→Done→Approved) replaces Start/Complete (qty+scrap+custom fields)/Approve/Reject/Transfer remainder/Reject intake. No event history timeline, no actual-vs-estimated time tracking, no delivered/available badges.
- No run-level actions. Return leftover and Cancel run (§5) aren't implemented.
- Stage identity on the run board/detail is reconstructed, not authoritative.
ProductionRun.stageSummaryonly carries counts per status;buildStagePlan()(lib/production-mock-runs.ts) maps those counts onto the template's real stage names most-complete-first as a display approximation — a real backend would return named per-stage records directly. - No validation/error posture (§6). No
ProblemDetails, no domain error-code mapping, no412/409handling, noIdempotency-Key— there's no server to produce any of it yet. - Save uses no
If-Match/concurrency token on the builder (§2) — a locallockedboolean (from mockactiveRunCount) stands in for the server's409 TEMPLATE_IN_USEedit lock. - Template overview deviates from "list" (§1). Implemented as one shared canvas (all templates as production lines, one row each) instead of a browsable list/grid, per explicit product direction during the build.
End of 21-FRONTEND-PHASE2.md. Contract: 30-BACKEND-PHASE2.md. Record work: Frontend/PROGRESS.md.