Producers can now drag cards on both boards. Three distinct write
paths, each with validation appropriate to what it's moving:
Projects board (status lens only):
- Drop updates Project.status via PATCH /api/projects/:id.
- Stage lens stays read-only — Project.stage is derived from the
dominant deliverable stage, there's no single write target.
Deliverables board (status lens):
- Drop updates Deliverable.status directly.
Deliverables board (stage lens) — the interesting one:
- Drop hits new POST /api/deliverables/:id/transition endpoint,
validated by new stage-transition-service.
- Forward transitions: current → APPROVED, optional intermediates
→ SKIPPED, target → IN_PROGRESS. If a REQUIRED intermediate
isn't already done, the drop is rejected ("walk through it
first") — toast shows the blocking stage name.
- Rework (backward) transitions: only allowed if the pipeline
template declares an explicit rework path from current → target.
Otherwise rejected. No cross-pipeline drops possible because the
target slug is looked up inside the deliverable's own pipeline.
Schema:
- New PipelineStageRework self-join on PipelineStageDefinition —
per-template declaration of "from stage X you can push back to
stage Y". Migration 20260423000000_pipeline_stage_reworks.
- Seed populates Dow's canonical rework paths: Client Review
(Copy) → Copywriter, Internal Review → In Progress Creative,
Client Feedback → In Progress Creative, Final Approval → In
Progress Creative, Completed → In Progress Creative.
Pipeline template editor UI (where producers would add their own
rework paths) is deferred; the seed covers Dow out of the box.
Hooks: added useUpdateProjectById, useUpdateDeliverableById,
useTransitionDeliverable — all take ids at mutation time so the
boards don't need one hook per card.