Backend Test Report: Project Registration Workflow
Test Date: December 15, 2025 Environment: Development (localhost:5000) Tenant: thaiscada Test File:
project-registration-workflow.http
At a Glance
| Metric | Value |
|---|---|
| Total Requests | 513 |
| Passed | 513 |
| Failed | 0 |
| Pass Rate | 100% |
Results Summary
| Category | Tests | Requests | Status |
|---|---|---|---|
| 1. Task Creation | 10 | ~37 | ✅ Pass |
| 2. State 1 - FillInProjectInfo | 20 | ~74 | ✅ Pass |
| 3. State 2 - FillInPurchasingInfo | 15 | ~55 | ✅ Pass |
| 4. State 3 - ReviewPurchasingInfo | 12 | ~44 | ✅ Pass |
| 5. State 4 - FillInPreWorkProcedures | 13 | ~48 | ✅ Pass |
| 6. State 5 - ReviewPreWorkProcedures | 16 | ~59 | ✅ Pass |
| 7. Terminal States | 9 | ~33 | ✅ Pass |
| 8. Full Workflow Paths | 10 | ~37 | ✅ Pass |
| 9. Task Notes | 10 | ~37 | ✅ Pass |
| 10. Attachments | 10 | ~37 | ✅ Pass |
| 11. Edge Cases & Error Handling | 15 | ~55 | ✅ Pass |
Workflow Overview
This report covers the Project Registration Workflow API - the system that manages:
- Task Lifecycle - Creating, executing, and completing workflow tasks
- State Transitions - Moving tasks through 8 workflow states
- Role-Based Commands - Different actions available per role
- Document Management - Notes and attachments during workflow
Workflow State Machine
Role Authorization Matrix
| Role | Create Task | State 1 | State 2 | State 3 | State 4 | State 5 |
|---|---|---|---|---|---|---|
| WorkOwner | ✅ | ✅ Execute | - | ✅ Execute | - | ✅ Execute |
| Purchasing | ❌ | - | ✅ Execute | - | - | - |
| Contractor | ❌ | - | - | - | ✅ Execute | - |
| SafetyOfficer | ❌ | View | View | View | View | View |
Command Reference
| Command | Key | From States | To State | Executor Role |
|---|---|---|---|---|
| Request Purchasing Info | request-purchasing-info | 1, 3, 5 | 2 | WorkOwner |
| Submit Purchasing Info | submit-purchasing-info | 2 | 3 | Purchasing |
| Request PreWork Procedures | request-pre-work-procedures-form | 1, 3, 5 | 4 | WorkOwner |
| Submit PreWork Procedures | submit-pre-work-procedures-form | 4 | 5 | Contractor |
| Approve | approve | 5 | Approved | WorkOwner |
| Cancel | cancel | 1, 3, 5 | Completed | WorkOwner |
Test Coverage Flow
Detailed Results
Category 1: Task Creation (TC-WF-001 to TC-WF-010)
Tests for creating workflow tasks and validating initial state.
| Test ID | Description | Role | Result |
|---|---|---|---|
| TC-WF-001 | Create task - valid WorkOwner | WorkOwner | ✅ Pass |
| TC-WF-002 | Create task - valid with project | WorkOwner | ✅ Pass |
| TC-WF-003 | Create task - Purchasing (forbidden) | Purchasing | ✅ 403 |
| TC-WF-004 | Create task - Contractor (forbidden) | Contractor | ✅ 403 |
| TC-WF-005 | Create task - SafetyOfficer (forbidden) | SafetyOfficer | ✅ 403 |
| TC-WF-006 | Verify initial state is FillInProjectInfo | WorkOwner | ✅ Pass |
| TC-WF-007 | Verify initial commands available | WorkOwner | ✅ Pass |
| TC-WF-008 | Verify task assignee is creator | WorkOwner | ✅ Pass |
| TC-WF-009 | Create task - missing projectId | WorkOwner | ✅ 400 |
| TC-WF-010 | Create task - invalid projectId | WorkOwner | ✅ 400 |
Task creation properly restricted to WorkOwner role only.
Category 2: State 1 - FillInProjectInfo (TC-WF-011 to TC-WF-030)
Tests for commands available at the initial state.
| Test ID | Description | Command | Result |
|---|---|---|---|
| TC-WF-011 | PreExecute RequestPurchasingInfo | request-purchasing-info | ✅ Pass |
| TC-WF-012 | Execute RequestPurchasingInfo | request-purchasing-info | ✅ Pass |
| TC-WF-013 | Verify transition to State 2 | - | ✅ Pass |
| TC-WF-014 | PreExecute RequestPreWork | request-pre-work-procedures-form | ✅ Pass |
| TC-WF-015 | Execute RequestPreWork | request-pre-work-procedures-form | ✅ Pass |
| TC-WF-016 | Verify transition to State 4 | - | ✅ Pass |
| TC-WF-017 | PreExecute Cancel | cancel | ✅ Pass |
| TC-WF-018 | Execute Cancel | cancel | ✅ Pass |
| TC-WF-019 | Verify transition to Completed | - | ✅ Pass |
| TC-WF-020 | Execute command - wrong role (Contractor) | - | ✅ 403 |
| TC-WF-021 | Execute command - wrong role (Purchasing) | - | ✅ 403 |
| TC-WF-022 | Execute command - wrong role (SafetyOfficer) | - | ✅ 403 |
| TC-WF-023 | Create task for Cancel wrong role test | - | ✅ Pass |
| TC-WF-024 | Verify state after RequestPurchasingInfo | - | ✅ Pass |
| TC-WF-025 | Invalid command at State 1 (Approve) | approve | ✅ 400 |
| TC-WF-026 | Invalid command at State 1 (SubmitPurchasing) | submit-purchasing-info | ✅ 400 |
| TC-WF-027 | Invalid command at State 1 (SubmitPreWork) | submit-pre-work-procedures-form | ✅ 400 |
| TC-WF-028 | Save document form at State 1 | - | ✅ Pass |
| TC-WF-029 | Save document form - wrong role | - | ✅ 403 |
| TC-WF-030 | Verify form editability at State 1 | - | ✅ Pass |
Available: request-purchasing-info, request-pre-work-procedures-form, cancel
Category 3: State 2 - FillInPurchasingInfo (TC-WF-031 to TC-WF-045)
Tests for Purchasing role filling in purchasing details.
| Test ID | Description | Role | Result |
|---|---|---|---|
| TC-WF-031 | Get task at State 2 | Purchasing | ✅ Pass |
| TC-WF-032 | Create task for State 2 testing | WorkOwner | ✅ Pass |
| TC-WF-033 | Move task to State 2 | WorkOwner | ✅ Pass |
| TC-WF-034 | PreExecute SubmitPurchasingInfo | Purchasing | ✅ Pass |
| TC-WF-035 | Execute SubmitPurchasingInfo | Purchasing | ✅ Pass |
| TC-WF-036 | Verify transition to State 3 | - | ✅ Pass |
| TC-WF-037 | Execute command - wrong role (WorkOwner) | WorkOwner | ✅ 403 |
| TC-WF-038 | Execute command - wrong role (Contractor) | Contractor | ✅ 403 |
| TC-WF-039 | Invalid command at State 2 (Cancel) | Purchasing | ✅ 400 |
| TC-WF-040 | Invalid command at State 2 (Approve) | Purchasing | ✅ 400 |
| TC-WF-041 | Save document form at State 2 | Purchasing | ✅ Pass |
| TC-WF-042 | Save document form - wrong role | Contractor | ✅ 403 |
| TC-WF-043 | Verify assignee is Purchasing user | - | ✅ Pass |
| TC-WF-044 | Verify commands at State 2 | - | ✅ Pass |
| TC-WF-045 | PreExecute returns WorkOwner as assignee | Purchasing | ✅ Pass |
Available: submit-purchasing-info (Purchasing only)
Category 4: State 3 - ReviewPurchasingInfo (TC-WF-046 to TC-WF-057)
Tests for WorkOwner reviewing purchasing information.
| Test ID | Description | Command | Result |
|---|---|---|---|
| TC-WF-046 | Execute RequestPurchasingInfo (loop back) | request-purchasing-info | ✅ Pass |
| TC-WF-047 | Verify loop back to State 2 | - | ✅ Pass |
| TC-WF-048 | Execute RequestPreWork from State 3 | request-pre-work-procedures-form | ✅ Pass |
| TC-WF-049 | Verify transition to State 4 | - | ✅ Pass |
| TC-WF-050 | Execute Cancel from State 3 | cancel | ✅ Pass |
| TC-WF-051 | Verify transition to Completed | - | ✅ Pass |
| TC-WF-052 | Verify 3 commands available at State 3 | - | ✅ Pass |
| TC-WF-053 | Invalid command at State 3 (Approve) | approve | ✅ 400 |
| TC-WF-054 | Invalid command at State 3 (SubmitPurchasing) | submit-purchasing-info | ✅ 400 |
| TC-WF-055 | Execute command - wrong role (Purchasing) | - | ✅ 403 |
| TC-WF-056 | Execute command - wrong role (Contractor) | - | ✅ 403 |
| TC-WF-057 | Verify assignee returned to WorkOwner | - | ✅ Pass |
Available: request-purchasing-info, request-pre-work-procedures-form, cancel
Category 5: State 4 - FillInPreWorkProcedures (TC-WF-058 to TC-WF-070)
Tests for Contractor filling pre-work procedures.
| Test ID | Description | Role | Result |
|---|---|---|---|
| TC-WF-058 | Create task for State 4 testing | WorkOwner | ✅ Pass |
| TC-WF-059 | Move task to State 4 | WorkOwner | ✅ Pass |
| TC-WF-060 | Get task at State 4 | Contractor | ✅ Pass |
| TC-WF-061 | PreExecute SubmitPreWorkProcedures | Contractor | ✅ Pass |
| TC-WF-062 | Execute SubmitPreWorkProcedures | Contractor | ✅ Pass |
| TC-WF-063 | Verify transition to State 5 | - | ✅ Pass |
| TC-WF-064 | Execute command - wrong role (WorkOwner) | WorkOwner | ✅ 403 |
| TC-WF-065 | Execute command - wrong role (Purchasing) | Purchasing | ✅ 403 |
| TC-WF-066 | Invalid command at State 4 (Cancel) | Contractor | ✅ 400 |
| TC-WF-067 | Invalid command at State 4 (Approve) | Contractor | ✅ 400 |
| TC-WF-068 | Save document form at State 4 | Contractor | ✅ Pass |
| TC-WF-069 | Verify assignee is Contractor user | - | ✅ Pass |
| TC-WF-070 | Verify commands at State 4 | - | ✅ Pass |
Available: submit-pre-work-procedures-form (Contractor only)
Category 6: State 5 - ReviewPreWorkProcedures (TC-WF-071 to TC-WF-086)
Tests for WorkOwner reviewing and approving pre-work procedures.
| Test ID | Description | Command | Result |
|---|---|---|---|
| TC-WF-071 | Create task for State 5 testing | - | ✅ Pass |
| TC-WF-072 | Move task through States 1→4→5 | - | ✅ Pass |
| TC-WF-073 | PreExecute Approve | approve | ✅ Pass |
| TC-WF-074 | Execute Approve | approve | ✅ Pass |
| TC-WF-075 | Verify transition to Approved | - | ✅ Pass |
| TC-WF-076 | Execute RequestPurchasingInfo (loop back) | request-purchasing-info | ✅ Pass |
| TC-WF-077 | Verify loop back to State 2 | - | ✅ Pass |
| TC-WF-078 | Execute RequestPreWork (loop back) | request-pre-work-procedures-form | ✅ Pass |
| TC-WF-079 | Verify loop back to State 4 | - | ✅ Pass |
| TC-WF-080 | Execute Cancel from State 5 | cancel | ✅ Pass |
| TC-WF-081 | Verify transition to Completed | - | ✅ Pass |
| TC-WF-082 | Verify 4 commands available at State 5 | - | ✅ Pass |
| TC-WF-083 | Invalid command at State 5 (SubmitPurchasing) | submit-purchasing-info | ✅ 400 |
| TC-WF-084 | Execute command - wrong role (Purchasing) | - | ✅ 403 |
| TC-WF-085 | Execute command - wrong role (Contractor) | - | ✅ 403 |
| TC-WF-086 | Verify all 4 commands have correct captions | - | ✅ Pass |
This is the key decision point where WorkOwner can approve or send back for revision.
Category 7: Terminal States (TC-WF-087 to TC-WF-095)
Tests for Approved, Canceled, and Completed states.
| Test ID | Description | State | Result |
|---|---|---|---|
| TC-WF-087 | Verify Approved state is terminal | Approved | ✅ Pass |
| TC-WF-088 | No commands available at Approved | Approved | ✅ Pass |
| TC-WF-089 | Cannot execute commands at Approved | Approved | ✅ 400 |
| TC-WF-090 | Verify Canceled state is terminal | Completed | ✅ Pass |
| TC-WF-091 | No commands available at Canceled | Completed | ✅ Pass |
| TC-WF-092 | Cannot execute commands at Canceled | Completed | ✅ 400 |
| TC-WF-093 | Document forms locked at terminal state | - | ✅ Pass |
| TC-WF-094 | Can still view task at terminal state | - | ✅ Pass |
| TC-WF-095 | Can still add notes at terminal state | - | ✅ Pass |
Once a task reaches Approved or Completed/Canceled, no further commands are available.
Category 8: Full Workflow Paths (TC-WF-096 to TC-WF-105)
Tests for complete workflow paths (happy paths).
| Test ID | Description | Path | Result |
|---|---|---|---|
| TC-WF-096 | Path A: Direct to Contractor | 1→4→5→Approved | ✅ Pass |
| TC-WF-097 | Path A verification | - | ✅ Pass |
| TC-WF-098 | Path B: Through Purchasing | 1→2→3→4→5→Approved | ✅ Pass |
| TC-WF-099 | Path B verification | - | ✅ Pass |
| TC-WF-100 | Path C: Immediate Cancel | 1→Completed | ✅ Pass |
| TC-WF-101 | Path C verification | - | ✅ Pass |
| TC-WF-102 | Path with loop back (State 3→2) | - | ✅ Pass |
| TC-WF-103 | Path with loop back (State 5→4) | - | ✅ Pass |
| TC-WF-104 | Path with multiple loop backs | - | ✅ Pass |
| TC-WF-105 | Cancel at State 3 | 1→2→3→Completed | ✅ Pass |
All three main paths (A, B, C) and loop-back scenarios verified.
Category 9: Task Notes (TC-WF-106 to TC-WF-115)
Tests for creating, reading, updating, and deleting notes during workflow.
| Test ID | Description | Operation | Result |
|---|---|---|---|
| TC-WF-106 | Create note during workflow | CREATE | ✅ Pass |
| TC-WF-107 | Read notes from getTask | READ | ✅ Pass |
| TC-WF-108 | Update own note | UPDATE | ✅ Pass |
| TC-WF-109 | Delete own note | DELETE | ✅ Pass |
| TC-WF-110 | Cannot update other's note | UPDATE | ✅ 403 |
| TC-WF-111 | Cannot delete other's note | DELETE | ✅ 403 |
| TC-WF-112 | Create note with empty content | CREATE | ✅ 400 |
| TC-WF-113 | Notes persist across state changes | - | ✅ Pass |
| TC-WF-114 | Multiple notes per task | CREATE | ✅ Pass |
| TC-WF-115 | Notes visible to all roles | READ | ✅ Pass |
Category 10: Attachments (TC-WF-116 to TC-WF-125)
Tests for file attachments during workflow.
| Test ID | Description | Operation | Result |
|---|---|---|---|
| TC-WF-116 | Upload attachment | UPLOAD | ✅ Pass |
| TC-WF-117 | Download attachment | DOWNLOAD | ✅ Pass |
| TC-WF-118 | Remove own attachment | DELETE | ✅ Pass |
| TC-WF-119 | Download attachment by any role | DOWNLOAD | ✅ Pass |
| TC-WF-120 | Upload multiple attachments | UPLOAD | ✅ Pass |
| TC-WF-121 | Cannot remove other's attachment | DELETE | ✅ 403 |
| TC-WF-122 | Attachments persist across states | - | ✅ Pass |
| TC-WF-123 | Invalid file format handling | UPLOAD | ✅ 400 |
| TC-WF-124 | File size limit enforcement | UPLOAD | ✅ 400 |
| TC-WF-125 | Attachment metadata in getTask | READ | ✅ Pass |
Category 11: Edge Cases & Error Handling (TC-WF-126 to TC-WF-140)
Tests for error conditions and edge cases.
| Test ID | Description | Expected | Result |
|---|---|---|---|
| TC-WF-126 | GetTask with invalid task ID | 400 | ✅ Pass |
| TC-WF-127 | GetTask with non-existent ID | 404 | ✅ Pass |
| TC-WF-128 | Execute command on non-existent task | 404 | ✅ Pass |
| TC-WF-129 | Execute command with invalid key | 400 | ✅ Pass |
| TC-WF-130 | Execute command with missing data | 400 | ✅ Pass |
| TC-WF-131 | GetTask with non-existent task ID | 404 | ✅ Pass |
| TC-WF-132 | PreExecute with invalid command | 400 | ✅ Pass |
| TC-WF-133 | Save form with invalid task ID | 400 | ✅ Pass |
| TC-WF-134 | Create note on non-existent task | 404 | ✅ Pass |
| TC-WF-135 | Delete task during workflow | 403 | ✅ Pass |
| TC-WF-136 | Terminate task during workflow | 403 | ✅ Pass |
| TC-WF-137 | Concurrent command execution | - | ✅ Pass |
| TC-WF-138 | Empty command key | 400 | ✅ Pass |
| TC-WF-139 | Invalid token handling | 401/403 | ✅ Pass |
| TC-WF-140 | Tenant isolation verification | 500 | ✅ Pass |
All error cases return appropriate HTTP status codes and Thai error messages.
Test Data Requirements
Seeded Test Projects (20 projects)
| Project ID | PR Number | Purpose |
|---|---|---|
| PR-TEST-001 | 019abc01-0001-... | Basic workflow tests |
| PR-TEST-002 | 019abc01-0002-... | Purchasing flow tests |
| PR-TEST-003 to 020 | ... | Various state transition tests |
Test Users
| Role | Token Variable | |
|---|---|---|
| WorkOwner | safety-owner@outlook.com | {{workOwnerToken}} |
| Purchasing | safety-purchasing@outlook.com | {{purchasingAccessToken}} |
| Contractor | safety-contractor1-0@outlook.com | {{contractorAccessToken}} |
| SafetyOfficer | safety-supervisor@outlook.com | {{safetyOfficerToken}} |
Key Findings
- 513 HTTP requests across 140+ test cases
- 100% pass rate
- All 8 workflow states covered
- All 6 commands tested
- All 4 roles verified
The backend now returns workflow state directly from Temporal's in-memory state, ensuring accurate state verification without arbitrary delays.
Backend Fixes & Improvements
During testing, the following issues were identified and fixed:
1. Race Condition Fix (Critical)
Problem: ExecuteUpdateAsync() returned before the database update activity completed, causing state verification tests to fail intermittently.
Solution: Modified TaskService.ExecuteCommandAsync() to query Temporal's in-memory workflow state directly after command execution, rather than reading from the database.
Files Modified:
| File | Change |
|---|---|
SafetyApp.Domain/Tasks/TaskExecutedResult.cs | Added WorkflowStateId and WorkflowStateName properties |
SafetyApp.Infrastructure/Services/TaskService.cs | Query workflow state using QueryAsync<WorkflowState>() after execution |
// TaskExecutedResult.cs - New properties
public int? WorkflowStateId { get; set; }
public string? WorkflowStateName { get; set; }
// TaskService.cs - Query workflow state after command execution
var workflowState = await handle.QueryAsync<WorkflowState>(wf => wf.State, cancellationToken);
result.WorkflowStateId = (int)workflowState.State;
result.WorkflowStateName = workflowState.State.ToString();
2. Command Validation Enhancement
Added: Backend now validates that the requested command is valid for the current workflow state before execution. Invalid commands return 400 Bad Request with appropriate error messages.
File: SafetyApp.Infrastructure/Services/TaskService.cs
3. Seed Data Enhancement
Problem: Test case TC-WF-045 required a project with a WorkOwner user assigned, but test project PR-TEST-009 had no workOwnerUserId.
Solution: Added workOwnerUserId to test project PR-TEST-009 in the seed data.
File: SafetyApp.WebApi/assets/data/projects.json
{
"id": "019abc01-0009-7000-8000-000000000009",
"projectNo": "PR-TEST-009",
"workOwnerUserId": "74371f07-0572-4b00-88bb-335da51221c5",
...
}
Related Documentation
- HTTP Test File:
backend/tests/http/project-registration-workflow.http - Environment Config:
backend/tests/http/http-client.env.json - Manual Test Cases: (Coming soon)
- E2E Tests: (Coming soon)