8.5 KiB
8.5 KiB
Tasks: Transmittals + Circulation Complete Integration (v1.8.7 Post-ADR-021)
Branch: 001-transmittals-circulation | Total Tasks: 18 | Phase: ✅ Complete (v1.8.7)
Phase 1 — Backend Foundation (Critical — blocks all frontend work)
B1 — WorkflowEngineService: Add getInstanceByEntity()
- File:
backend/src/modules/workflow-engine/workflow-engine.service.ts - Action: Add method that queries
WorkflowInstancebyentityType + entityId; returns{ id, currentState, availableActions? } | null - Dependencies: none
- Status: [x]
B2 — TransmittalService: Expose workflowInstanceId in findOneByUuid()
- File:
backend/src/modules/transmittal/transmittal.service.ts - Action: Call
workflowEngine.getInstanceByEntity('transmittal', correspondenceId.toString())and mergeworkflowInstanceId,workflowStateinto response - Dependencies: B1
- Status: [x]
B3 — TransmittalService: Add purpose filter to findAll()
- File:
backend/src/modules/transmittal/transmittal.service.ts - Action: Add
purpose?: stringtoSearchTransmittalDtoand applyandWhereinfindAll() - Dependencies: none (parallel with B1)
- Status: [x]
B4 — TransmittalService: Add submit() with EC-RFA-004 validation
- File:
backend/src/modules/transmittal/transmittal.service.ts - Action: New
submit(uuid, user)method; fetches alltransmittal_items, checks each item's correspondence current revision status — throws422 ValidationExceptionif any isDRAFT; then callsworkflowEngine.createInstance('TRANSMITTAL_FLOW_V1', 'transmittal', ...)and transitions withSUBMIT - Dependencies: B1
- Status: [x]
B5 — TransmittalController: Add POST /:uuid/submit endpoint
- File:
backend/src/modules/transmittal/transmittal.controller.ts - Action: Add endpoint with
@RequirePermission('document.manage'),@Audit('transmittal.submit', 'transmittal') - Dependencies: B4
- Status: [x]
B6 — CirculationService: Expose workflowInstanceId in findOneByUuid()
- File:
backend/src/modules/circulation/circulation.service.ts - Action: Call
workflowEngine.getInstanceByEntity('circulation', circulation.id.toString()), merge into response; also computeisOverdueper routing based ondeadline_date - Dependencies: B1
- Status: [x]
B7 — CirculationService: Add reassignRouting() (EC-CIRC-001)
- File:
backend/src/modules/circulation/circulation.service.ts - Action: Fetch routing, verify user has Document Control permission, resolve
newAssigneeUuid→ INT viauuidResolver.resolveUserId(), updaterouting.assignedTo, write audit log - Dependencies: none
- Status: [x]
B8 — CirculationService: Add forceClose() (EC-CIRC-002)
- File:
backend/src/modules/circulation/circulation.service.ts - Action: Require
reason(non-empty), update all PENDING routings toCANCELLED, setcirculation.statusCode = 'CANCELLED', write audit log entry; usequeryRunnerfor atomicity - Dependencies: none
- Status: [x]
B9 — CirculationController: Add reassign + force-close endpoints
- File:
backend/src/modules/circulation/circulation.controller.ts - Action:
PATCH /:uuid/routing/:routingId/reassign—@RequirePermission('circulation.manage')POST /:uuid/force-close—@RequirePermission('circulation.manage')
- Dependencies: B7, B8
- Status: [x]
Phase 2 — Frontend Types & Hooks (Important — depends on Phase 1)
F1 — Update types/transmittal.ts
- File:
frontend/types/transmittal.ts - Action: Add
workflowInstanceId?: string,workflowState?: string,availableActions?: string[]toTransmittalinterface; addpurpose?: stringtoSearchTransmittalDto; noanytypes (ADR-019) - Dependencies: none (parallel with Phase 1)
- Status: [x]
F2 — Update types/circulation.ts
- File:
frontend/types/circulation.ts - Action: Add
workflowInstanceId?: string,workflowState?: string,availableActions?: string[]toCirculation; adddeadline?: string,assigneeType?: 'MAIN' | 'ACTION' | 'INFORMATION'toCirculationRouting - Dependencies: none
- Status: [x]
F3 — Create hooks/use-transmittal.ts
- File:
frontend/hooks/use-transmittal.ts - Action: Create
useTransmittal(uuid: string | undefined)withqueryKey: ['transmittal', uuid],staleTime: 60_000; exporttransmittalKeysquery key factory - Dependencies: F1
- Status: [x]
F4 — Update hooks/use-circulation.ts
- File:
frontend/hooks/use-circulation.ts - Action: Add
useCirculation(uuid: string | undefined)hook withqueryKey: ['circulation', uuid],staleTime: 60_000 - Dependencies: F2
- Status: [x]
Phase 3 — Frontend Detail Pages (Important — depends on Phase 2 + Phase 1 deployed)
F5 — Wire Transmittal detail page
- File:
frontend/app/(dashboard)/transmittals/[uuid]/page.tsx - Action:
- Replace inline
useQuerywithuseTransmittal(uuid) - Add
useWorkflowHistory(transmittal?.workflowInstanceId) - Add
const [pendingAttachmentIds, setPendingAttachmentIds] = useState<string[]>([]) - Pass
instanceId,workflowState,availableActions,pendingAttachmentIdstoIntegratedBanner - Pass
history,currentState,isLoading,error,onAttachmentsChangetoWorkflowLifecyclein Workflow tab
- Replace inline
- Dependencies: F3, F1
- Status: [x]
F6 — Wire Circulation detail page
- File:
frontend/app/(dashboard)/circulation/[uuid]/page.tsx - Action:
- Replace inline
useQuerywithuseCirculation(uuid) - Add
useWorkflowHistory(circulation?.workflowInstanceId) - Add
isOverdue(deadline?)helper function - Wire
IntegratedBannerwithinstanceId,workflowState,availableActions - Wire
WorkflowLifecyclewith history in Workflow tab - Add Overdue badge to routing rows where
isOverdue(routing.deadline)is true - Replace hardcoded "Complete" button with proper workflow action
- Replace inline
- Dependencies: F4, F2
- Status: [x]
Phase 4 — List Page & i18n (Guidelines)
F7 — Transmittal list page: add purpose filter
- File:
frontend/app/(dashboard)/transmittals/page.tsx - Action: Add
purposeselect filter (FOR_APPROVAL / FOR_INFORMATION / FOR_REVIEW / OTHER) passing totransmittalService.getAll(). Read current page to assess if pagination works. - Dependencies: F1
- Status: [x]
I1 — i18n keys for Transmittal/Circulation workflow
- Files:
public/locales/th/*.json,public/locales/en/*.json - Action: Check
use-translations.tsfor key lookup pattern; add missing keys:transmittal.purpose.*,circulation.status.*,circulation.overdue,circulation.forceClose.*,circulation.reassign.* - Dependencies: F5, F6
- Status: [ ] (low priority — pending)
Phase 5 — Tests (Tier 2 — required before merge)
T1 — Transmittal service EC-RFA-004 unit test
- File:
backend/src/modules/transmittal/transmittal.service.spec.ts(create if needed) - Action: Test
submit()throwsValidationExceptionwhen item correspondence is DRAFT; test passes when all items are SUBMITTED - Dependencies: B4
- Status: [x]
T2 — Circulation service edge-case unit tests
- File:
backend/src/modules/circulation/circulation.service.spec.ts(create if needed) - Action: Test
reassignRouting()— permission check, assignment update; testforceClose()— all pending routings cancelled, reason logged; testisOverduehelper (EC-CIRC-003) - Dependencies: B7, B8
- Status: [x]
Execution Order
B1 (parallel: B3, F1, F2)
→ B2, B4 (parallel), B6 (parallel)
→ B5 → T1
→ B7, B8 (parallel)
→ B9 → T2
→ F3, F4 (parallel after F1, F2)
→ F5, F6 (parallel after F3, F4)
→ F7, I1 (polish)
Commit Message Convention
feat(transmittal): expose workflowInstanceId in findOneByUuid response
feat(circulation): expose workflowInstanceId + overdue in findOneByUuid
feat(circulation): add reassignRouting EC-CIRC-001 handler
feat(circulation): add forceClose EC-CIRC-002 handler
feat(transmittal): add submit endpoint with EC-RFA-004 validation
feat(frontend): wire WorkflowLifecycle in transmittal detail page
feat(frontend): wire WorkflowLifecycle + overdue badge in circulation detail
test(transmittal): EC-RFA-004 submit validation unit tests
test(circulation): EC-CIRC-001/002/003 edge case unit tests