14 KiB
Feature Specification: Transmittals + Circulation Complete Integration (v1.8.7 Post-ADR-021)
Feature Branch: 001-transmittals-circulation
Version: 1.8.7
Created: 2026-04-12
Status: Draft
Depends On: ADR-021 (Integrated Workflow Context & Step-specific Attachments — in feat/adr-021-integrated-workflow-context)
Input: "Transmittals + Circulation (v1.8.7) Post-ADR-021"
Context
ADR-021 introduced the shared IntegratedBanner, WorkflowLifecycle, and use-workflow-action components, and wired them fully for RFA and Correspondence. Both the Transmittal and Circulation detail pages already import these components but pass no workflow data — they are currently stub wired.
This feature delivers the complete, production-ready integration of both modules with the ADR-021 Workflow Engine, fixes known type violations (ADR-019), implements all pending edge cases (EC-RFA-004, EC-CIRC-001–003), and adds missing hooks and list-page functionality.
User Scenarios & Testing (mandatory)
User Story 1 — Transmittal Workflow-Wired Detail Page (Priority: P1) 🎯 MVP
A Document Control officer opens an existing Transmittal and immediately sees the document number, subject, workflow state, and available action buttons in the IntegratedBanner. The Workflow tab shows the full vertical timeline with each step's actor, date, comment, and evidence files.
Why this priority: The detail page is the primary touchpoint for reviewing/approving a Transmittal. Without live workflow data, reviewers cannot take action — this is a blocking gap.
Independent Test: Navigate to /transmittals/{uuid}. Verify: (1) IntegratedBanner shows real doc number, status badge, and action buttons (when user is the handler); (2) Workflow tab renders WorkflowLifecycle with at least the creation step; (3) all pnpm tsc --noEmit checks pass.
Acceptance Scenarios:
- Given a submitted Transmittal with an active workflow instance, When a Document Control user opens its detail page, Then the
IntegratedBannerdisplays the correct doc number, status,workflowState, and the available action buttons (e.g., APPROVE, REJECT). - Given a Transmittal where the current user is not the assigned handler, When they open the detail page, Then no action buttons are shown in the banner.
- Given a Transmittal detail page, When the user clicks the Workflow tab, Then a vertical timeline displays all history steps with actor, date, and comment. The most recent step is highlighted.
User Story 2 — Circulation Workflow-Wired Detail Page (Priority: P1) 🎯 MVP
A Document Control officer opens a Circulation Sheet and sees the circulation number, linked Correspondence, all assignees with their status, a deadline (with Overdue badge if past), and the full workflow timeline — all in one screen. Assignees can mark their task complete via the IntegratedBanner actions.
Why this priority: Circulation drives internal task tracking. Without live data wiring the page is read-only and useless for task management.
Independent Test: Navigate to /circulation/{uuid}. Verify: (1) IntegratedBanner displays circulationNo, statusCode; (2) Assignees card shows all routings with status; (3) Overdue badge appears when deadline_date is past; (4) Workflow tab shows history.
Acceptance Scenarios:
- Given an OPEN Circulation with a past deadline, When a user opens the detail page, Then an Overdue badge is displayed and the deadline date is highlighted in red.
- Given a Circulation with multiple assignees, When an assignee marks their task complete, Then their routing status updates to COMPLETED and the page refreshes.
- Given a Circulation where all Main/Action assignees are COMPLETED, When the Document Control user views the page, Then a "Close Circulation" action is available.
User Story 3 — Transmittal List Page with Search & Filter (Priority: P1)
A Document Control officer browses all Transmittals for a project, filters by purpose (FOR_APPROVAL, FOR_REVIEW, etc.), and searches by document number or subject.
Why this priority: The list page is the entry point for the module. Without working filters it cannot be used in production.
Independent Test: Navigate to /transmittals. Verify: paginated list loads; purpose filter updates results; search input filters by doc number/subject; clicking a row navigates to the detail page.
Acceptance Scenarios:
- Given the Transmittals list page, When a user selects purpose "FOR_APPROVAL", Then only Transmittals with that purpose are shown.
- Given the Transmittals list page, When a user types in the search box, Then results are filtered to matching document numbers or subjects within 500ms.
- Given no Transmittals in the project, When the list page loads, Then an "empty state" message is shown.
User Story 4 — Transmittal EC-RFA-004 Submit Validation (Priority: P2)
A Document Control officer tries to submit a Transmittal whose items include a DRAFT correspondence. The system blocks the submission with a clear, actionable error message.
Why this priority: EC-RFA-004 is a business integrity rule. Submitting a Transmittal with unsubmitted items violates the document lifecycle and must be blocked.
Independent Test: Create a Transmittal with one DRAFT item. Attempt to submit. Verify: 422 response with message "RFA [doc number] ยังอยู่ใน Draft กรุณา Submit ก่อน"; item is highlighted in the UI.
Acceptance Scenarios:
- Given a Transmittal containing a DRAFT correspondence, When a user submits the Transmittal, Then the system returns an error identifying which item is in DRAFT status.
- Given all Transmittal items are in SUBMITTED/APPROVED status, When a user submits the Transmittal, Then the submission succeeds and the status updates.
User Story 5 — Circulation Edge Cases: Re-assign & Force Close (Priority: P2)
Document Control can re-assign a Circulation when an assignee is deactivated (EC-CIRC-001), and can force-close a Circulation with a mandatory reason when some assignees have not responded (EC-CIRC-002).
Why this priority: Without these controls, Circulations can get permanently stuck, blocking downstream work.
Independent Test: Deactivate an assignee in an OPEN Circulation. Verify: Document Control sees a "Re-assign" button for that routing. Force-close a Circulation with partial responses; verify reason is recorded in audit log.
Acceptance Scenarios:
- Given an OPEN Circulation where one assignee has been deactivated, When Document Control opens the page, Then a "Re-assign" action is available for that assignee's routing.
- Given an OPEN Circulation where some assignees have not responded, When Document Control performs Force Close with a reason, Then the Circulation status changes to CANCELLED, all pending routings are force-closed, and the reason is logged.
Edge Cases
- EC-RFA-004: Transmittal with DRAFT items cannot be submitted →
422 Unprocessable Entitywith item identification. - EC-CIRC-001: Assignee deactivated before responding → Document Control can re-assign.
- EC-CIRC-002: Multi-assignee, some not responded → Document Control can Force Close with mandatory reason.
- EC-CIRC-003: Deadline = today
23:59:59; Overdue Badge the following day at00:00. - EC-CORR-001: Cancelling a Correspondence with open Circulations → all Circulations force-closed + audit log.
- Transmittal
workflowInstanceIdisnullwhen no workflow has been started (Draft state) → banner shows status only, no action buttons. - Circulation data is scoped to the user's organization — users from other organizations must receive a 403 response.
- Duplicate
Idempotency-Keyon workflow transition → return cached response, no re-processing.
Requirements (mandatory)
Functional Requirements
Transmittal Module:
- FR-T01: The Transmittal detail page MUST display
workflowState,availableActions, and action buttons viaIntegratedBannerusing the live workflow instance. - FR-T02: The Transmittal detail page Workflow tab MUST render
WorkflowLifecyclewired to the workflow history of the Transmittal's workflow instance. - FR-T03: The Transmittal list page MUST support pagination, search by document number/subject, and filter by
purpose. - FR-T04: The Transmittal
Transmittalfrontend type MUST includeworkflowInstanceId?: stringandworkflowState?: stringfields (ADR-019: string UUID only). - FR-T05: The
transmittalService.getByUuid()response MUST includeworkflowInstanceIdfrom the backend. - FR-T06: A dedicated
useTransmittal(uuid)TanStack Query hook MUST be created for the detail page. - FR-T07: Submitting a Transmittal with DRAFT items MUST return a
422error identifying the offending item (EC-RFA-004).
Circulation Module:
- FR-C01: The Circulation detail page MUST display
workflowState,availableActions, and action buttons viaIntegratedBannerusing the live workflow instance. - FR-C02: The Circulation detail page Workflow tab MUST render
WorkflowLifecyclewired to the workflow history. - FR-C03: The Circulation detail page assignee section MUST display deadline per assignee type and an Overdue badge when
NOW() > deadline_date + 1 day(EC-CIRC-003). - FR-C04: The Circulation
Circulationfrontend type MUST includeworkflowInstanceId?: stringandworkflowState?: string. - FR-C05: The
circulationService.getByUuid()response MUST includeworkflowInstanceIdfrom the backend. - FR-C06: A dedicated
useCirculation(uuid)TanStack Query hook MUST be created for the detail page. - FR-C07: Document Control MUST be able to re-assign a routing when the assignee is deactivated (EC-CIRC-001).
- FR-C08: Document Control MUST be able to Force Close a Circulation with a mandatory reason; all pending routings are force-closed and the reason is logged in the audit trail (EC-CIRC-002).
Cross-Cutting:
- FR-X01: All new API calls MUST use
publicId(UUIDv7 string) — noparseInton UUID values (ADR-019). - FR-X02: All new frontend types MUST NOT use
any— strict TypeScript required. - FR-X03: All backend responses for these modules MUST include
workflowInstanceId?: stringin the data shape. - FR-X04: All new user-facing strings MUST use i18n keys — no hardcoded Thai/English text in JSX.
Key Entities
- Transmittal: Extends Correspondence (
type_code = 'TRANSMITTAL'). Haspurpose,remarks, and a list oftransmittal_items. Has oneWorkflowInstancevia the Unified Workflow Engine. - TransmittalItem: Links a Transmittal to the document it carries (
correspondencesM:N). Hasquantity,itemType,remarks. - Circulation: Internal task-tracking document linked 1:1 to a Correspondence per organization. Has
statusCode,deadline, and a list ofroutings(assignees with type: Main/Action/Information). - CirculationRouting: A single assignee entry in a Circulation. Has
assigneeType,status,deadline,comments.
Assumptions
- ADR-021 backend is fully deployed —
workflow_history_idcolumn exists onattachments,workflowInstanceIdis exposed from the Workflow Engine module. - The backend
transmittalmodule already has aworkflowInstancerelation or can join it via the Correspondence FK chain. - The backend
circulationmodule already has aworkflowInstancerelation available. - The Unified Workflow Engine (
WorkflowEngineService) is the single source of truth for state and transitions — Transmittal and Circulation statuses are NOT independently maintained once a workflow is started.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: Both Transmittal and Circulation detail pages display live workflow state and action buttons in under 1 second after page load (TanStack Query with staleTime 60s).
- SC-002: Submitting a Transmittal with a DRAFT item is rejected 100% of the time with a user-readable error message identifying the offending document.
- SC-003: Force-closing a Circulation with partial responses succeeds in a single action with the mandatory reason captured in the audit log every time.
- SC-004: All new TypeScript code passes
pnpm tsc --noEmitwith zero errors andpnpm lintwith zero warnings. - SC-005: No hardcoded Thai or English text in any new JSX component — verified by grep.
- SC-006: Unit test coverage ≥ 80% on new business logic (EC-RFA-004 validation, EC-CIRC-001/002/003 handlers).
- SC-007: Overdue Badge appears correctly when
NOW() > deadline_date + 1 day— verified by unit test with mocked date.
Clarifications
Session 2026-04-12
- Q: Should the Transmittal "Submit" action go through the Workflow Engine transition (ADR-021 pattern), or does it remain a direct status update on the
correspondencestable? → A: Submit uses the Workflow Engine transition (action: 'SUBMIT'), consistent with ADR-001 Unified Workflow Engine for all document types. EC-RFA-004 validation fires as a pre-transition check in the service. - Q: Should Circulation
routings"Complete" action be a Workflow Engine transition or a direct routing status update? → A: Direct routing status update (not a full Workflow Engine transition) because Circulation workflow state is controlled at the Circulation level, not per-routing. The overall Circulation transitions (OPEN → IN_REVIEW → COMPLETED) go through the Workflow Engine. - Q: For
workflowInstanceIdin the Transmittal/Circulation API response — should it be added to the existing response shape or is a dedicated/workflowsub-resource needed? → A: AddworkflowInstanceIddirectly to the existingfindOneByUuidresponse shape (additive, backward-compatible). Consistent with how RFA/Correspondence expose it.