Files
ERP-core/docs/21-FRONTEND-PHASE2.md
T
ImanThiyanga 7d6e597389 feat: add production templates API and documentation for manufacturing phase 2
- Implemented CRUD operations for production templates, including listing, retrieving, creating, updating, and deactivating templates.
- Introduced a new API contract for production runs, detailing the lifecycle from creation to completion, including handling of stock inputs and outputs.
- Documented the architecture, requirements, entity model, and API contract for the manufacturing phase 2, ensuring clarity on the production process and its integration with existing systems.
2026-07-31 10:22:40 +05:30

15 KiB
Raw Blame History

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 follows 20-FRONTEND §3: client validation is UX only; the server is authoritative. Register this doc in 00-CORE.md §7 and 01-DOC-GUIDE.md §2.


1. Screens

Screen Route (suggested) Actual route (as built) 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 (updated 2026-07-30). The backend is completeDtos/Production, both controllers and the full 30-BACKEND-PHASE2.md contract all exist, last verified at 312/312 smoke assertions (Backend/smoke/run_all.py). Every frontend screen is now wired to it and both mock modules are deleted:

Piece State
Contract layer — types/production.ts, lib/api/production-templates.ts, lib/api/production-runs.ts, error-code map Done, mirrors §D.1D.4
§1 Template overview Real API — live list, debounced search, status filter, paging
§2 Template builder Real API — loads/saves the graph with server keys, If-Match, persisted positions, real item/UOM pickers
§3 Run board · §4 Start dialog Real API — filters + paging; the dialog posts and navigates to the run
§5 Run detail + stage drawer Real API — canvas from the run's own positions/edges, and the full per-status action set
§6 Validation posture Done412 banner, server-driven 409 TEMPLATE_IN_USE lock, per-action Idempotency-Key, silent stage-status 409 refetch

Caveat, stated plainly: none of it has been driven in a browser. The tree type-checks and Turbopack compiles it, but no screen has been clicked and no end-to-end run walked through the UI — blocked on AuthHex being unable to issue a token. §8 records the remaining live deviations; Frontend/PROGRESS.md §§1113 is the authoritative state.


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 the fieldDefs jsonb 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

  1. Template picker (Active only), target quantity (of the finished item, unit shown), warehouse, optional output bin.
  2. Scaled preview: client computes scaleFactor = targetQty / terminalOutputQtyPerBatch and shows every stage's scaled inputs/outputs as a preview only — the authoritative scaled figures come back on the 201 response.
  3. 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: 1 and the user opens it from the board like any other run.

5. Run detail

AS BUILT — this section is implemented as specified, with three deviations worth naming:

  • Refetch, not poll. The page reloads the whole run after every action rather than polling on a timer; the drawer's body is switched on the server's stage status, so nothing is ever rendered from a local guess. A stage-status 409 also triggers a silent refetch (§6), which covers the "someone else acted first" case a poll would have caught.
  • No inbound-edge badges; intake lives on the node. React Flow edge labels are cramped and a stage can have several upstream inputs from the same parent, so the aggregate delivered/planned badge sits on the stage card — colour-coded, so it doubles as an explanation of why a stage is still Waiting. The available-to-transfer badge is on the card too.
  • Delivery progress is a labelled figure, not a bar. Per-upstream-input delivered / planned reads better as numbers in the drawer's input list than as a row of bars, and it keeps the base-UOM vs declared-UOM distinction visible (see the consumed/returned note in 30-BACKEND-PHASE2 §D.3).

Files: runs/[id]/page.tsx (canvas + header), StageDrawer.tsx (shell + every per-status body + event timeline), CustomFieldForm.tsx (runtime field renderer), RunActions.tsx (run-level Return leftover / Cancel).

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-hand enquiry, advisory only — never block client-side, per 20-FRONTEND §3), and Start. On start errors surface STOCK_NEGATIVE_BLOCKED / ONHOLD_NOT_ISSUABLE / EXPIRED_BATCH_BLOCKED with 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 with 400 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_AVAILABLE surfaced 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 ProblemDetails renders its title; map domain codes to friendly inline messages (table in 30-BACKEND-PHASE2 §D.4). Unknown codes fall back to the ProblemDetails title + trace id.
  • 412 CONCURRENCY_CONFLICT → "This item changed elsewhere — reloading" + refetch. Stage-action 409s (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) — types/production.ts, rewritten against 30-BACKEND-PHASE2 §D. The placeholder shapes are gone.
  • 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) — both halves: the designer in StageEditorPanel.tsx, and the runtime renderer in runs/[id]/CustomFieldForm.tsx, used by the drawer's Complete action.
  • Screens: template list · builder · run board · start dialog · run detail + drawer — all implemented against the real API.
  • Error-code → message map for §D.4 additions — all 17 codes in lib/error-map.ts.

8. Gaps vs. this spec

Closed. Everything below was intentional scope while no backend existed; the backend is built and verified and every screen is now wired to it. Struck-through items are done; what remains is a short list of live deviations and one honest caveat.

  • No persistence. Both mock modules (lib/production-mock-templates.ts, lib/production-mock-runs.ts) are deleted. Every screen reads and writes the real API.
  • Run detail is a simplified single action, not the stage drawer (§5). The drawer (runs/[id]/StageDrawer.tsx) implements the full per-status action set — Start, Complete (qty + scrap + reason + custom fields), Approve with optional partial transfer, the terminal receipt confirmation, Reject for rework, Transfer remainder, Reject intake — plus the per-stage event timeline and estimated-vs-actual time with a live elapsed counter while a stage is running.
  • No run-level actions. runs/[id]/RunActions.tsx implements Return leftover and Cancel run, both hidden once the run leaves InProgress.
  • Stage identity on the run board/detail is reconstructed, not authoritative. buildStagePlan() is deleted. Run detail renders named per-stage records straight from GET /production-runs/{id}. The board deliberately does not name stages at all — its list projection carries stageSummary counts only, so it shows counts per status rather than guessing which stage holds which count.
  • Validation/error posture (§6). Fully closed: the 412 conflict banner, the server-driven 409 TEMPLATE_IN_USE lock banner (with a distinct message for the mid-edit TOCTOU case), per-action Idempotency-Key, and silent refetch on stage-status 409s via isStaleStageError().
  • Save uses no If-Match/concurrency token on the builder (§2). It holds the ETag from the GET and sends If-Match on every PUT; the lock now comes from the server's activeRunCount, not a local boolean.
  • Template overview deviates from "list" (§1). Still one shared canvas (all templates as production lines, one row each) instead of a browsable list/grid, per explicit product direction during the build. It now has a real debounced search, status filter and pagination around it.
  • 422 GRAPH_* node focus is a substring match, not a structured reference. The server's detail names the offending stages rather than returning their keys, so the builder highlights any stage whose name appears in the message. Advisory by design: the full message is always shown too, so an ambiguous name costs a highlight, never the explanation.
  • Canvas annotations are a frontend feature that grew a backend column. The builder's grouping boxes and divider lines had nowhere to persist, which meant every save silently discarded them. They now round-trip through PRODUCTION_TEMPLATE.annotations; see the AS BUILT note in 30-BACKEND-PHASE2 Part C, including the client obligation to echo them back on a PUT.
  • Not browser-verified. Every screen type-checks and Turbopack compiles the tree, and every endpoint behind them is smoke-verified server-side — but no production screen has been driven in a browser and no end-to-end run has been walked through the UI. Blocked on AuthHex being unable to issue a token (its configured MySQL host is unreachable). Tracked in Frontend/PROGRESS.md §13.

End of 21-FRONTEND-PHASE2.md. Contract: 30-BACKEND-PHASE2.md. Record work: Frontend/PROGRESS.md.