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.
This commit is contained in:
+36
-16
@@ -6,7 +6,7 @@
|
||||
|
||||
## 1. Screens
|
||||
|
||||
| Screen | Route (suggested) | Actual route (frontend-only build) | Purpose |
|
||||
| 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. |
|
||||
@@ -14,7 +14,18 @@
|
||||
| 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) — no `Dtos/Production` or `30-BACKEND-PHASE2.md` exist 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 surface `ProblemDetails`/error codes from. See §8 for the itemized gap list.
|
||||
> **Build status (updated 2026-07-30).** The **backend is complete** — `Dtos/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.1–D.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 | **Done** — `412` 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` §§11–13 is the authoritative state.
|
||||
|
||||
---
|
||||
|
||||
@@ -70,7 +81,13 @@ These colors are the single source for status coloring everywhere (board, run gr
|
||||
|
||||
## 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 local `useState` — reloading the page resets to the seeded mock run. See §8.
|
||||
> **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.
|
||||
|
||||
@@ -99,24 +116,27 @@ These colors are the single source for status coloring everywhere (board, run gr
|
||||
## 7. Foundation additions (PROGRESS seed)
|
||||
|
||||
- [x] 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.ts` is a standalone frontend-only placeholder shape, nothing to mirror against yet.
|
||||
- [x] Types mirroring `Dtos/Production` (template graph, run graph, stage actions) — `types/production.ts`, rewritten against `30-BACKEND-PHASE2 §D`. The placeholder shapes are gone.
|
||||
- [x] 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/`ProblemDetails` to map yet.
|
||||
- [x] 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.
|
||||
- [x] Screens: template list · builder · run board · start dialog · run detail + drawer — all implemented against the real API.
|
||||
- [x] Error-code → message map for §D.4 additions — all 17 codes in `lib/error-map.ts`.
|
||||
|
||||
---
|
||||
|
||||
## 8. Gaps vs. this spec (frontend-only mock — no `Dtos/Production` / `30-BACKEND-PHASE2.md` yet)
|
||||
## 8. Gaps vs. this spec
|
||||
|
||||
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:
|
||||
> **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.** All state is per-page `useState` seeded 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.stageSummary` only 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, no `412`/`409` handling, no `Idempotency-Key` — there's no server to produce any of it yet.
|
||||
- **Save uses no `If-Match`/concurrency token** on the builder (§2) — a local `locked` boolean (from mock `activeRunCount`) stands in for the server's `409 TEMPLATE_IN_USE` edit 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.
|
||||
- ~~**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 `409`s 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`.*
|
||||
|
||||
Reference in New Issue
Block a user