690414:1113 Update README.md /.agents/skills, /.windsurf/workflows
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
# Tasks: Transmittals + Circulation Complete Integration (v1.8.7 Post-ADR-021)
|
||||
|
||||
**Branch**: `001-transmittals-circulation` | **Total Tasks**: 18 | **Phase**: Implementation
|
||||
|
||||
---
|
||||
|
||||
## 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 `WorkflowInstance` by `entityType + entityId`; returns `{ id, currentState, availableActions? } | null`
|
||||
- **Dependencies**: none
|
||||
- **Status**: [ ]
|
||||
|
||||
### B2 — TransmittalService: Expose `workflowInstanceId` in `findOneByUuid()`
|
||||
- **File**: `backend/src/modules/transmittal/transmittal.service.ts`
|
||||
- **Action**: Call `workflowEngine.getInstanceByEntity('transmittal', correspondenceId.toString())` and merge `workflowInstanceId`, `workflowState` into response
|
||||
- **Dependencies**: B1
|
||||
- **Status**: [ ]
|
||||
|
||||
### B3 — TransmittalService: Add `purpose` filter to `findAll()`
|
||||
- **File**: `backend/src/modules/transmittal/transmittal.service.ts`
|
||||
- **Action**: Add `purpose?: string` to `SearchTransmittalDto` and apply `andWhere` in `findAll()`
|
||||
- **Dependencies**: none (parallel with B1)
|
||||
- **Status**: [ ]
|
||||
|
||||
### B4 — TransmittalService: Add `submit()` with EC-RFA-004 validation
|
||||
- **File**: `backend/src/modules/transmittal/transmittal.service.ts`
|
||||
- **Action**: New `submit(uuid, user)` method; fetches all `transmittal_items`, checks each item's correspondence current revision status — throws `422 ValidationException` if any is `DRAFT`; then calls `workflowEngine.createInstance('TRANSMITTAL_FLOW_V1', 'transmittal', ...)` and transitions with `SUBMIT`
|
||||
- **Dependencies**: B1
|
||||
- **Status**: [ ]
|
||||
|
||||
### 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**: [ ]
|
||||
|
||||
### 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 compute `isOverdue` per routing based on `deadline_date`
|
||||
- **Dependencies**: B1
|
||||
- **Status**: [ ]
|
||||
|
||||
### 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 via `uuidResolver.resolveUserId()`, update `routing.assignedTo`, write audit log
|
||||
- **Dependencies**: none
|
||||
- **Status**: [ ]
|
||||
|
||||
### B8 — CirculationService: Add `forceClose()` (EC-CIRC-002)
|
||||
- **File**: `backend/src/modules/circulation/circulation.service.ts`
|
||||
- **Action**: Require `reason` (non-empty), update all PENDING routings to `CANCELLED`, set `circulation.statusCode = 'CANCELLED'`, write audit log entry; use `queryRunner` for atomicity
|
||||
- **Dependencies**: none
|
||||
- **Status**: [ ]
|
||||
|
||||
### 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**: [ ]
|
||||
|
||||
---
|
||||
|
||||
## 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[]` to `Transmittal` interface; add `purpose?: string` to `SearchTransmittalDto`; no `any` types (ADR-019)
|
||||
- **Dependencies**: none (parallel with Phase 1)
|
||||
- **Status**: [ ]
|
||||
|
||||
### F2 — Update `types/circulation.ts`
|
||||
- **File**: `frontend/types/circulation.ts`
|
||||
- **Action**: Add `workflowInstanceId?: string`, `workflowState?: string`, `availableActions?: string[]` to `Circulation`; add `deadline?: string`, `assigneeType?: 'MAIN' | 'ACTION' | 'INFORMATION'` to `CirculationRouting`
|
||||
- **Dependencies**: none
|
||||
- **Status**: [ ]
|
||||
|
||||
### F3 — Create `hooks/use-transmittal.ts`
|
||||
- **File**: `frontend/hooks/use-transmittal.ts`
|
||||
- **Action**: Create `useTransmittal(uuid: string | undefined)` with `queryKey: ['transmittal', uuid]`, `staleTime: 60_000`; export `transmittalKeys` query key factory
|
||||
- **Dependencies**: F1
|
||||
- **Status**: [ ]
|
||||
|
||||
### F4 — Update `hooks/use-circulation.ts`
|
||||
- **File**: `frontend/hooks/use-circulation.ts`
|
||||
- **Action**: Add `useCirculation(uuid: string | undefined)` hook with `queryKey: ['circulation', uuid]`, `staleTime: 60_000`
|
||||
- **Dependencies**: F2
|
||||
- **Status**: [ ]
|
||||
|
||||
---
|
||||
|
||||
## 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 `useQuery` with `useTransmittal(uuid)`
|
||||
- Add `useWorkflowHistory(transmittal?.workflowInstanceId)`
|
||||
- Add `const [pendingAttachmentIds, setPendingAttachmentIds] = useState<string[]>([])`
|
||||
- Pass `instanceId`, `workflowState`, `availableActions`, `pendingAttachmentIds` to `IntegratedBanner`
|
||||
- Pass `history`, `currentState`, `isLoading`, `error`, `onAttachmentsChange` to `WorkflowLifecycle` in Workflow tab
|
||||
- **Dependencies**: F3, F1
|
||||
- **Status**: [ ]
|
||||
|
||||
### F6 — Wire Circulation detail page
|
||||
- **File**: `frontend/app/(dashboard)/circulation/[uuid]/page.tsx`
|
||||
- **Action**:
|
||||
- Replace inline `useQuery` with `useCirculation(uuid)`
|
||||
- Add `useWorkflowHistory(circulation?.workflowInstanceId)`
|
||||
- Add `isOverdue(deadline?)` helper function
|
||||
- Wire `IntegratedBanner` with `instanceId`, `workflowState`, `availableActions`
|
||||
- Wire `WorkflowLifecycle` with history in Workflow tab
|
||||
- Add Overdue badge to routing rows where `isOverdue(routing.deadline)` is true
|
||||
- Replace hardcoded "Complete" button with proper workflow action
|
||||
- **Dependencies**: F4, F2
|
||||
- **Status**: [ ]
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — List Page & i18n (Guidelines)
|
||||
|
||||
### F7 — Transmittal list page: add purpose filter
|
||||
- **File**: `frontend/app/(dashboard)/transmittals/page.tsx`
|
||||
- **Action**: Add `purpose` select filter (FOR_APPROVAL / FOR_INFORMATION / FOR_REVIEW / OTHER) passing to `transmittalService.getAll()`. Read current page to assess if pagination works.
|
||||
- **Dependencies**: F1
|
||||
- **Status**: [ ]
|
||||
|
||||
### I1 — i18n keys for Transmittal/Circulation workflow
|
||||
- **Files**: `public/locales/th/*.json`, `public/locales/en/*.json`
|
||||
- **Action**: Check `use-translations.ts` for key lookup pattern; add missing keys: `transmittal.purpose.*`, `circulation.status.*`, `circulation.overdue`, `circulation.forceClose.*`, `circulation.reassign.*`
|
||||
- **Dependencies**: F5, F6
|
||||
- **Status**: [ ]
|
||||
|
||||
---
|
||||
|
||||
## 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()` throws `ValidationException` when item correspondence is DRAFT; test passes when all items are SUBMITTED
|
||||
- **Dependencies**: B4
|
||||
- **Status**: [ ]
|
||||
|
||||
### 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; test `forceClose()` — all pending routings cancelled, reason logged; test `isOverdue` helper (EC-CIRC-003)
|
||||
- **Dependencies**: B7, B8
|
||||
- **Status**: [ ]
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
```
|
||||
Reference in New Issue
Block a user