260324:1439 Refactor RFA :correct ci-deploy #03
This commit is contained in:
@@ -16,15 +16,15 @@ jobs:
|
||||
- name: 📥 Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 📦 Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: 🟢 Setup Node
|
||||
- name: � Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "pnpm"
|
||||
|
||||
- name: � Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: 📦 Install deps
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ export default function RFAEditPage() {
|
||||
const updateMutation = useUpdateRFA();
|
||||
|
||||
const currentRevision =
|
||||
rfa?.revisions?.find((r) => r.isCurrent) ?? rfa?.revisions?.[0];
|
||||
rfa?.revisions?.find((r: { isCurrent: boolean }) => r.isCurrent) ?? rfa?.revisions?.[0];
|
||||
|
||||
const form = useForm<EditRfaFormValues>({
|
||||
resolver: zodResolver(editRfaSchema),
|
||||
|
||||
@@ -24,7 +24,7 @@ import { correspondenceService } from '@/lib/services/correspondence.service';
|
||||
const rfaSchema = z.object({
|
||||
projectId: z.string().min(1, 'Project is required'), // ADR-019: UUID
|
||||
contractId: z.string().min(1, 'Contract is required'),
|
||||
disciplineId: z.number({ required_error: 'Discipline is required' }).min(1, 'Discipline is required'),
|
||||
disciplineId: z.number({ message: 'Discipline is required' }).min(1, 'Discipline is required'),
|
||||
rfaTypeId: z.number().min(1, 'Type is required'),
|
||||
subject: z.string().min(5, 'Subject must be at least 5 characters'),
|
||||
description: z.string().optional(),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 📖 User Stories — LCBP3-DMS v1.8.0
|
||||
# 📖 User Stories — LCBP3-DMS v1.8.1
|
||||
|
||||
---
|
||||
|
||||
@@ -187,6 +187,7 @@ So that ดำเนินการได้ทันที (สร้าง Cir
|
||||
|
||||
- List แสดง Received/Sent แยก | PDF Viewer ในแอป (Streaming)
|
||||
- ดาวน์โหลดไฟล์แนบได้ (ถ้ามีสิทธิ์)
|
||||
- อ้างอิงเอกสารด้วย UUID (ADR-019)
|
||||
|
||||
---
|
||||
|
||||
@@ -202,7 +203,7 @@ So that จัดกลุ่มเอกสารและ Navigate ข้า
|
||||
|
||||
**Done When:**
|
||||
|
||||
- ค้นหาและเลือก Reference Documents | Link ระหว่างเอกสาร (คลิก Navigate)
|
||||
- ค้นหาและเลือก Reference Documents | Link ระหว่างเอกสาร (คลิก Navigate ด้วย UUID)
|
||||
- กำหนด Tag หลาย Tag | ค้นหาได้จาก Tag
|
||||
|
||||
---
|
||||
@@ -314,8 +315,11 @@ So that ส่งเอกสารเป็นชุด ที่ปรึก
|
||||
**Done When:**
|
||||
|
||||
- Transmittal → เลือก RFA หลายฉบับ | ออกเลขเองเป็น Correspondence
|
||||
- สถานะ → FAP (For Approval) | Workflow Instance ถูกสร้าง
|
||||
- ผู้รับ → Notification | สถานะ SUBMITTED
|
||||
- สร้าง Workflow Instance อัตโนมัติ
|
||||
- อ้างอิงเอกสารด้วย UUID (ADR-019)
|
||||
- RFA แต่ละฉบับ → ออกเลขตาม Format `LCBP3-RFA-{DISCIPLINE}-{SEQ}`
|
||||
- ที่ปรึกษา → Notification
|
||||
|
||||
---
|
||||
|
||||
@@ -331,9 +335,10 @@ So that Contractor ได้รับผลพิจารณาและดำ
|
||||
|
||||
**Done When:**
|
||||
|
||||
- PDF Viewer Streaming | ปุ่ม: Approved / Approved w/Comments / Rejected
|
||||
- Comment บังคับสำหรับ Approved w/Comments และ Rejected
|
||||
- PDF Viewer Streaming | ปุ่ม: Approved (1A) / Approved w/Comments (1B) / Rejected (4X)
|
||||
- Comment บังคับสำหรับ 1B และ 4X
|
||||
- Originator → Notification | Workflow History บันทึกครบ
|
||||
- อ้างอิงเอกสารด้วย UUID (ADR-019)
|
||||
|
||||
---
|
||||
|
||||
@@ -408,6 +413,7 @@ So that รู้ทันทีว่าเอกสารอยู่ขั้
|
||||
- Workflow Diagram แสดง State ปัจจุบัน (Highlight)
|
||||
- คลิก Step ที่ผ่านมา → Audit Log ย่อย (ใคร/เมื่อไหร่/Comment)
|
||||
- Step ที่ยังไม่ถึง → Disabled Style
|
||||
- อ้างอิงเอกสารด้วย UUID (ADR-019)
|
||||
|
||||
---
|
||||
|
||||
@@ -425,7 +431,8 @@ So that Workflow เดินหน้าหรือส่งกลับตา
|
||||
|
||||
- เห็นปุ่ม Action เฉพาะ Step ที่เป็นของฉัน
|
||||
- Wrong Role → ปุ่มซ่อน / 403 ถ้าเรียก API ตรงๆ
|
||||
- ทุก Action → Workflow History + Timestamp
|
||||
- ทุก Action → Workflow History + Timestamp + Audit Log
|
||||
- อ้างอิงเอกสารด้วย UUID (ADR-019)
|
||||
|
||||
---
|
||||
|
||||
@@ -481,6 +488,7 @@ So that งานถูก Assign ชัดเจนและมีหลัก
|
||||
- กำหนด Main / Action / Information Assignees (หลายคน)
|
||||
- Assignees → In-App + Email Notification
|
||||
- Internal Only (ไม่เห็นข้ามองค์กร)
|
||||
- อ้างอิงเอกสารด้วย UUID (ADR-019)
|
||||
|
||||
---
|
||||
|
||||
@@ -499,6 +507,7 @@ So that ไม่พลาดงาน และ Track สถานะได้
|
||||
- Dashboard My Tasks แสดง Deadline + Overdue Badge
|
||||
- ปิด Circulation → สถานะ CLOSED + Timestamp
|
||||
- My Tasks ลบรายการที่ปิดแล้ว
|
||||
- อ้างอิงเอกสารด้วย UUID (ADR-019)
|
||||
|
||||
---
|
||||
|
||||
@@ -534,7 +543,7 @@ So that ไม่พลาดงานโดยไม่ต้องเช็ค
|
||||
**Done When:**
|
||||
|
||||
- Email ถูกส่งภายใน 5 นาที หลัง Event (BullMQ Queue)
|
||||
- Bell Icon Unread Count | คลิก → Navigate ไปเอกสาร
|
||||
- Bell Icon Unread Count | คลิก → Navigate ไปเอกสาร (ใช้ UUID)
|
||||
- Retry 3 ครั้ง ถ้าส่งไม่ได้ → Dead Letter Queue
|
||||
|
||||
---
|
||||
@@ -579,24 +588,25 @@ So that รู้สถานะงานโดยไม่ต้องไล่
|
||||
|
||||
## 📊 Story Map Summary
|
||||
|
||||
| Epic | Stories | 🔴 Must | 🟠 Should | 🟡 Could |
|
||||
| ---------------- | ---------- | ------- | --------- | -------- |
|
||||
| Auth & Users | US-001~006 | 4 | 1 | 1 |
|
||||
| Correspondence | US-007~011 | 2 | 2 | 1 |
|
||||
| RFA | US-012~015 | 2 | 2 | 0 |
|
||||
| Drawing | US-016~017 | 0 | 2 | 0 |
|
||||
| Workflow | US-018~021 | 1 | 1 | 2 |
|
||||
| Circulation | US-022~023 | 0 | 2 | 0 |
|
||||
| Search & Notify | US-024~025 | 0 | 2 | 0 |
|
||||
| File & Dashboard | US-026~027 | 0 | 2 | 0 |
|
||||
| **รวม** | **27** | **9** | **14** | **4** |
|
||||
| Epic | Stories | 🔴 Must | 🟠 Should | 🟡 Could |
|
||||
| ---------------- | --------------- | ------- | --------- | -------- |
|
||||
| Auth & Users | US-001~006 | 4 | 1 | 1 |
|
||||
| Correspondence | US-007~011 | 2 | 2 | 1 |
|
||||
| RFA | US-012~015, 012a~012c | 4 | 3 | 0 |
|
||||
| Drawing | US-016~017 | 0 | 2 | 0 |
|
||||
| Workflow | US-018~021 | 1 | 1 | 2 |
|
||||
| Circulation | US-022~023 | 0 | 2 | 0 |
|
||||
| Search & Notify | US-024~025 | 0 | 2 | 0 |
|
||||
| File & Dashboard | US-026~027 | 0 | 2 | 0 |
|
||||
| **รวม** | **30** | **11** | **15** | **4** |
|
||||
|
||||
> **MVP Sprint Focus:** US-001~006, US-007~008, US-012~014, US-019 — ครอบคลุม Core Happy Path ทั้งหมด
|
||||
> **MVP Sprint Focus:** US-001~006, US-007~008, US-012~015, US-012a~012c, US-019 — ครอบคลุม Core Happy Path ทั้งหมด
|
||||
|
||||
---
|
||||
|
||||
## 📝 Document Control
|
||||
|
||||
- **Version:** 1.0.0 | **Status:** DRAFT
|
||||
- **Created:** 2026-03-11 | **Owner:** Nattanin Peancharoen
|
||||
- **Version:** 1.8.1 | **Status:** Updated
|
||||
- **Created:** 2026-03-11 | **Updated:** 2026-03-24 | **Owner:** Nattanin Peancharoen
|
||||
- **Changes:** Added US-012a~012c (Edit/Cancel/Search RFA), Updated Epic 3 story count, Added RBAC filtering details
|
||||
- **Classification:** Internal Use Only
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# ✅ Acceptance Criteria — LCBP3-DMS MVP (UAT)
|
||||
# ✅ Acceptance Criteria — LCBP3-DMS MVP (UAT) v1.8.1
|
||||
|
||||
---
|
||||
|
||||
title: 'Acceptance Criteria & UAT Test Scenarios'
|
||||
version: 1.8.0
|
||||
status: DRAFT — Pending Stakeholder Sign-off
|
||||
version: 1.8.1
|
||||
status: updated
|
||||
owner: Nattanin Peancharoen (Product Owner)
|
||||
last_updated: 2026-03-11
|
||||
last_updated: 2026-03-24
|
||||
related:
|
||||
|
||||
- specs/01-Requirements/01-01-objectives.md
|
||||
- specs/01-Requirements/01-03-modules/
|
||||
- specs/01-Requirements/01-04-user-stories.md
|
||||
- specs/01-Requirements/01-06-edge-cases-and-rules.md
|
||||
- specs/01-Requirements/01-02-business-rules/01-02-01-rbac-matrix.md
|
||||
- specs/01-Requirements/01-02-business-rules/01-02-04-non-functional-rules.md
|
||||
- specs/06-Decision-Records/ADR-001-unified-workflow-engine.md
|
||||
@@ -245,7 +246,7 @@ related:
|
||||
| **When** | กด Submit |
|
||||
| **Then** | ✅ เลขที่ RFA ถูกออกอัตโนมัติตาม Format (`LCBP3-RFA-STR-0001`) |
|
||||
| | ✅ เลขไม่ reset ตามปี (RFA = No reset policy) |
|
||||
| | ✅ สถานะ = `SUBMITTED` |
|
||||
| | ✅ สถานะ = `SUBMITTED` → สร้าง Transmittal อัตโนมัติ |
|
||||
| | ✅ Workflow Routing เริ่มทำงาน (ส่งไปยัง Reviewer) |
|
||||
|
||||
### AC-RFA-003 — Review RFA (Approved)
|
||||
@@ -256,7 +257,7 @@ related:
|
||||
| --------- | ---------------------------------------------------- |
|
||||
| **Given** | RFA อยู่ในสถานะรอ Review ที่องค์กรเรา |
|
||||
| **When** | Engineer คลิก "Approved" |
|
||||
| **Then** | ✅ สถานะ RFA เปลี่ยนเป็น `APPROVED` |
|
||||
| **Then** | ✅ สถานะ RFA เปลี่ยนเป็น `APPROVED` (1A) |
|
||||
| | ✅ Originator (Contractor) ได้รับแจ้งเตือน |
|
||||
| | ✅ Workflow History บันทึก Action + Timestamp + User |
|
||||
|
||||
@@ -268,7 +269,7 @@ related:
|
||||
| --------- | ----------------------------------------------------- |
|
||||
| **Given** | RFA อยู่ในสถานะรอ Review |
|
||||
| **When** | Engineer คลิก "Approved with Comments" + กรอก Comment |
|
||||
| **Then** | ✅ สถานะ = `APPROVED_WITH_COMMENTS` |
|
||||
| **Then** | ✅ สถานะ = `APPROVED_WITH_COMMENTS` (1B) |
|
||||
| | ✅ Comment ถูกบันทึกใน Workflow History |
|
||||
| | ✅ Originator เห็น Comment ได้ |
|
||||
|
||||
@@ -280,7 +281,7 @@ related:
|
||||
| --------- | --------------------------------------------- |
|
||||
| **Given** | RFA อยู่ในสถานะรอ Review |
|
||||
| **When** | Engineer คลิก "Rejected" + ระบุเหตุผล |
|
||||
| **Then** | ✅ สถานะ = `REJECTED` |
|
||||
| **Then** | ✅ สถานะ = `REJECTED` (4X) |
|
||||
| | ✅ เหตุผลการ Reject บันทึกครบถ้วน |
|
||||
| | ✅ Contractor สามารถยื่น RFA Revision ใหม่ได้ |
|
||||
|
||||
@@ -296,6 +297,45 @@ related:
|
||||
| | ✅ เลขที่เอกสารเดิม — Revision Code เปลี่ยน (เช่น `-B`) |
|
||||
| | ✅ Rev.A ยังอ่านได้ (ไม่ถูกลบ) |
|
||||
|
||||
### AC-RFA-007 — Edit Draft RFA
|
||||
|
||||
**Priority:** 🔴 Blocker | **Role:** Document Control (Contractor)
|
||||
|
||||
| | Description |
|
||||
| --------- | ---------------------------------------------- |
|
||||
| **Given** | RFA อยู่ในสถานะ DRAFT (EC-RFA-001 enforced) |
|
||||
| **When** | Document Control แก้ไข Subject/Body/Remarks |
|
||||
| **Then** | ✅ RFA ถูกอัปเดตในสถานะ DRAFT |
|
||||
| | ✅ หากสถานะไม่ใช่ DFT → 403 Forbidden |
|
||||
| | ✅ Audit Log บันทึก UPDATE + user + timestamp |
|
||||
| | ✅ 1 Shop Drawing Revision = 1 RFA เท่านั้น |
|
||||
|
||||
### AC-RFA-008 — Cancel Draft RFA
|
||||
|
||||
**Priority:** 🟠 Critical | **Role:** Document Control (Contractor)
|
||||
|
||||
| | Description |
|
||||
| --------- | ---------------------------------------------- |
|
||||
| **Given** | RFA อยู่ในสถานะ DRAFT |
|
||||
| **When** | กด Cancel |
|
||||
| **Then** | ✅ สถานะเปลี่ยนเป็น CANCELLED |
|
||||
| | ✅ Shop Drawing Revision ถูกปลดผูก (available) |
|
||||
| | ✅ Audit Log บันทึก CANCELLED + reason |
|
||||
| | ✅ ไม่สามารถกด Cancel ได้ถ้าสถานะไม่ใช่ DFT |
|
||||
|
||||
### AC-RFA-009 — Search/Filter RFA
|
||||
|
||||
**Priority:** 🔴 Blocker | **Role:** Document Control/Engineer
|
||||
|
||||
| | Description |
|
||||
| --------- | ---------------------------------------------------- |
|
||||
| **Given** | มี RFA ในระบบหลายฉบับ |
|
||||
| **When** | Filter ด้วย Project/Status หรือค้นหา Keyword |
|
||||
| **Then** | ✅ ผลลัพธ์ถูกต้องตาม Filter |
|
||||
| | ✅ DFT → เห็นเฉพาะ originator org (RBAC) |
|
||||
| | ✅ Pagination ทำงาน (20 items/page) |
|
||||
| | ✅ ค้นหาจากเลขเอกสาร/Subject ได้ |
|
||||
|
||||
---
|
||||
|
||||
## 📐 Module 5: Drawing Management
|
||||
@@ -642,10 +682,10 @@ related:
|
||||
|
||||
| | Description |
|
||||
| --------- | --------------------------------------------------------------------------- |
|
||||
| **Given** | ดำเนินการ Action ต่างๆ ในระบบ (Create, Update, Submit, Approve) |
|
||||
| **Given** | ดำเนินการ Action ต่างๆ ในระบบ (Create, Update, Submit, Approve, Cancel) |
|
||||
| **When** | ตรวจสอบ Audit Log |
|
||||
| **Then** | ✅ ทุก Action มีบันทึกใน `audit_logs` |
|
||||
| | ✅ บันทึกมี: user_id, action, entity_type, entity_id, ip_address, timestamp |
|
||||
| **Then** | ✅ ทุก Action มีบันทึกใน `audit_logs` (severity INFO/WARN/ERROR/CRITICAL) |
|
||||
| | ✅ บันทึกมี: user_id, action, entity_type, entity_uuid, details_json, ip_address, timestamp |
|
||||
| | ✅ ไม่สามารถแก้ไขหรือลบ Audit Log ได้ (Read-only) |
|
||||
|
||||
---
|
||||
@@ -678,10 +718,10 @@ related:
|
||||
|
||||
**Priority:** 🔴 Blocker | **Role:** QA (Security Test)
|
||||
|
||||
| | Description |
|
||||
| --------- | --------------------------------------------------------- |
|
||||
| **Given** | User A รู้ Document ID ของ User B |
|
||||
| **When** | User A เรียก `GET /correspondences/:id` ของ User B โดยตรง |
|
||||
| | Description |
|
||||
| --------- | -------------------------------------------------------------- |
|
||||
| **Given** | User A รู้ Document UUID ของ User B (ADR-019) |
|
||||
| **When** | User A เรียก `GET /correspondences/:uuid` ของ User B โดยตรง |
|
||||
| **Then** | ✅ ได้รับ 403 Forbidden (ไม่ใช่ 404) |
|
||||
| | ✅ ข้อมูลของ User B ไม่ถูกเปิดเผย |
|
||||
|
||||
@@ -793,7 +833,7 @@ related:
|
||||
| 1 | AC-AUTH-001 ~ AC-AUTH-005 ผ่านทั้งหมด | ⬜ |
|
||||
| 2 | AC-ADMIN-001 ~ AC-ADMIN-005 ผ่านทั้งหมด | ⬜ |
|
||||
| 3 | AC-CORR-001 ~ AC-CORR-002 (Happy Path) ผ่าน | ⬜ |
|
||||
| 4 | AC-RFA-001 ~ AC-RFA-003 (Submit + Approve) ผ่าน | ⬜ |
|
||||
| 4 | AC-RFA-001 ~ AC-RFA-003, AC-RFA-007 ~ AC-RFA-009 (RFA Core) ผ่าน | ⬜ |
|
||||
| 5 | AC-WF-001 ~ AC-WF-003 (Workflow Engine Core) ผ่าน | ⬜ |
|
||||
| 6 | AC-DN-001 (Concurrent Number) ผ่าน | ⬜ |
|
||||
| 7 | AC-STOR-001 (Two-Phase Storage + ClamAV) ผ่าน | ⬜ |
|
||||
@@ -818,10 +858,11 @@ related:
|
||||
|
||||
## 📝 Document Control
|
||||
|
||||
- **Version:** 1.0.0
|
||||
- **Status:** DRAFT — Pending Stakeholder Sign-off
|
||||
- **Created:** 2026-03-11
|
||||
- **Version:** 1.8.1
|
||||
- **Status:** updated
|
||||
- **Created:** 2026-03-11 | **Updated:** 2026-03-24
|
||||
- **Owner:** Nattanin Peancharoen (Product Owner / System Architect)
|
||||
- **Changes:** Added AC-RFA-007~009 (Edit/Cancel/Search RFA), Updated status codes, Added UUID references (ADR-019), Linked edge cases
|
||||
- **Next Review:** Prior to UAT Start
|
||||
- **Classification:** Internal Use Only
|
||||
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
# 🛡️ Module Edge Cases & Business Rules — LCBP3-DMS v1.8.0
|
||||
# 🛡️ Module Edge Cases & Business Rules — LCBP3-DMS v1.8.1
|
||||
|
||||
---
|
||||
|
||||
title: 'Edge Cases, Business Rules, and Anti-Bug Specifications'
|
||||
version: 1.0.0
|
||||
status: DRAFT
|
||||
version: 1.8.1
|
||||
status: updated
|
||||
owner: Nattanin Peancharoen (Product Owner / System Architect)
|
||||
last_updated: 2026-03-11
|
||||
last_updated: 2026-03-24
|
||||
related:
|
||||
|
||||
- specs/01-Requirements/01-04-user-stories.md
|
||||
- specs/01-Requirements/01-05-acceptance-criteria.md
|
||||
- specs/01-Requirements/01-02-business-rules/01-02-02-doc-numbering-rules.md
|
||||
- specs/06-Decision-Records/ADR-001-unified-workflow-engine.md
|
||||
- specs/06-Decision-Records/ADR-016-security-authentication.md
|
||||
- specs/06-Decision-Records/ADR-019-hybrid-identifier-strategy.md
|
||||
- specs/03-Data-and-Storage/lcbp3-v1.8.0-schema-02-tables.sql
|
||||
|
||||
---
|
||||
@@ -389,6 +391,62 @@ XLSX: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
|
||||
---
|
||||
|
||||
### EC-RFA-005 — Edit Draft RFA Validation
|
||||
|
||||
**Severity:** 🔴 Critical | **Type:** Business Rule, Data Integrity
|
||||
|
||||
**Scenario:** User พยายามแก้ไข RFA ที่ไม่ใช่สถานะ DRAFT หรือพยายามแก้ไข Shop Drawing Revision
|
||||
|
||||
**Expected Behavior:**
|
||||
|
||||
- ถ้าสถานะ ≠ DRAFT → 403 Forbidden: "สามารถแก้ไขได้เฉพาะในสถานะ Draft"
|
||||
- ถ้าสถานะ = DRAFT → อนุญาตแก้ไข Subject, Body, Remarks, Description, Due Date
|
||||
- Shop Drawing Revision ที่ผูกอยู่ **ไม่สามารถเปลี่ยนได้** (EC-RFA-001 enforced)
|
||||
- Audit Log บันทึก UPDATE + user + timestamp ทุกครั้ง
|
||||
- Details JSON schema_version คงที่ (ไม่อนุญาตเปลี่ยน version)
|
||||
|
||||
**Reference:** US-012a, AC-RFA-007
|
||||
|
||||
---
|
||||
|
||||
### EC-RFA-006 — Cancel Draft RFA Cascade Effects
|
||||
|
||||
**Severity:** 🔴 Critical | **Type:** Business Rule, Data Integrity
|
||||
|
||||
**Scenario:** User ยกเลิก RFA ที่อยู่ในสถานะ DRAFT หรือพยายามยกเลิกที่ไม่ใช่ DRAFT
|
||||
|
||||
**Expected Behavior:**
|
||||
|
||||
- ถ้าสถานะ ≠ DRAFT → 403 Forbidden: "สามารถยกเลิกได้เฉพาะในสถานะ Draft"
|
||||
- ถ้าสถานะ = DRAFT → RFA status เปลี่ยนเป็น CANCELLED
|
||||
- Shop Drawing Revision ถูกปลดผูก (available = true) ทันที
|
||||
- Audit Log บันทึก CANCELLED + reason + user + timestamp
|
||||
- ไม่สามารถ Undo การ Cancel ได้ (ต้องสร้าง RFA ใหม่)
|
||||
|
||||
**Reference:** US-012b, AC-RFA-008
|
||||
|
||||
---
|
||||
|
||||
### EC-RFA-007 — Search Results RBAC Filtering
|
||||
|
||||
**Severity:** 🔴 Critical | **Type:** Security, Business Rule
|
||||
|
||||
**Scenario:** Contractor A ค้นหา RFA แต่พยายามเห็น RFA ของ Contractor B โดยใช้ Advanced Filter
|
||||
|
||||
**Expected Behavior:**
|
||||
|
||||
- RFA ในสถานะ DRAFT → เห็นเฉพาะ originator organization (เจ้าของ RFA)
|
||||
- RFA ในสถานะอื่น (SUBMITTED, FAP, APPROVED, REJECTED) → เห็นตามสิทธิ์ปกติ (project/contract scope)
|
||||
- Elasticsearch query filter ด้วย `visible_to_organizations` array field
|
||||
- Frontend ไม่แสดงผลลัพธ์ที่ไม่มีสิทธิ์ (return empty ไม่ใช่ error)
|
||||
- API Response ไม่เปิดเผย entity_uuid ของเอกสารที่ไม่มีสิทธิ์
|
||||
|
||||
**Implementation:** Backend filter ใน service layer + Elasticsearch query filter
|
||||
|
||||
**Reference:** US-012c, AC-RFA-009, ADR-019
|
||||
|
||||
---
|
||||
|
||||
## Module 5: Authentication & Session Edge Cases
|
||||
|
||||
### EC-AUTH-001 — Token Refresh Race Condition
|
||||
@@ -469,14 +527,17 @@ if (isBlacklisted) throw new UnauthorizedException('Account deactivated');
|
||||
|
||||
**Severity:** 🔴 Critical | **Type:** Security
|
||||
|
||||
**Scenario:** User A รู้ ID ของเอกสาร User B (เช่น `/correspondences/12345`) แล้วเรียกตรงๆ
|
||||
**Scenario:** User A รู้ UUID ของเอกสาร User B (เช่น `/correspondences/550e8400-e29b-41d4-a716-446655440000`) แล้วเรียกตรงๆ
|
||||
|
||||
**Expected Behavior:**
|
||||
|
||||
- CASL AbilityGuard ตรวจสอบทั้ง Action และ Resource Owner
|
||||
- CASL AbilityGuard ตรวจสอบทั้ง Action และ Resource Owner (ADR-019)
|
||||
- ถ้าไม่มีสิทธิ์ → **403 Forbidden** (ไม่ใช่ 404 — เพราะ 404 บอกว่ามีอยู่แต่หาไม่เจอ)
|
||||
- **Exception:** ถ้าต้องการซ่อน Existence ของ Document → Return 404
|
||||
- ทุก API ต้องผ่าน Permission Check โดยไม่มีข้อยกเว้น
|
||||
- ParseUuidPipe ตรวจสอบ UUID format ก่อน query database
|
||||
|
||||
**Implementation:** UUID-based routing + CASL permissions
|
||||
|
||||
---
|
||||
|
||||
@@ -681,14 +742,14 @@ if (isBlacklisted) throw new UnauthorizedException('Account deactivated');
|
||||
| Document Numbering | 2 | 2 | 1 | 5 |
|
||||
| Workflow Engine | 2 | 1 | 2 | 5 |
|
||||
| File Storage | 2 | 2 | 1 | 5 |
|
||||
| RFA & Drawing | 1 | 2 | 1 | 4 |
|
||||
| RFA & Drawing | 4 | 2 | 1 | 7 |
|
||||
| Auth & Session | 3 | 0 | 1 | 4 |
|
||||
| Permission & RBAC | 2 | 0 | 1 | 3 |
|
||||
| Correspondence | 1 | 0 | 2 | 3 |
|
||||
| Circulation | 0 | 1 | 2 | 3 |
|
||||
| Search | 1 | 0 | 2 | 3 |
|
||||
| Notifications | 0 | 1 | 1 | 2 |
|
||||
| **รวม** | **14** | **9** | **14** | **37** |
|
||||
| **รวม** | **17** | **9** | **14** | **40** |
|
||||
|
||||
---
|
||||
|
||||
@@ -697,6 +758,21 @@ if (isBlacklisted) throw new UnauthorizedException('Account deactivated');
|
||||
### สำหรับ Unit Tests (Backend)
|
||||
|
||||
```typescript
|
||||
// ตัวอย่าง: EC-RFA-005 — Edit Draft RFA Validation
|
||||
describe('RFAService - Edit Draft Validation', () => {
|
||||
it('should allow edit when status is DRAFT', async () => {
|
||||
const rfa = await service.createRFA({ status: 'DRAFT' });
|
||||
const updated = await service.updateRFA(rfa.uuid, { subject: 'Updated' });
|
||||
expect(updated.subject).toBe('Updated');
|
||||
});
|
||||
|
||||
it('should reject edit when status is not DRAFT', async () => {
|
||||
const rfa = await service.createRFA({ status: 'SUBMITTED' });
|
||||
await expect(service.updateRFA(rfa.uuid, { subject: 'Updated' }))
|
||||
.rejects.toThrow('403');
|
||||
});
|
||||
});
|
||||
|
||||
// ตัวอย่าง: EC-DN-001 — Concurrent Number Generation
|
||||
describe('DocumentNumberingService - Concurrency', () => {
|
||||
it('should generate unique numbers for concurrent requests', async () => {
|
||||
@@ -713,19 +789,23 @@ describe('DocumentNumberingService - Concurrency', () => {
|
||||
|
||||
- EC-DN-001: k6 Load Test Script (50 VUs, `/document-numbering/reserve`)
|
||||
- EC-AUTH-001: Cypress Multi-tab Token Refresh Test
|
||||
- EC-PERM-001: API Test Suite — Direct Object Reference สำหรับทุก Resource
|
||||
- EC-PERM-001: API Test Suite — Direct Object Reference สำหรับทุก Resource (UUID-based)
|
||||
- EC-RFA-005~007: RFA CRUD operations test with different user roles
|
||||
|
||||
### สำหรับ Manual UAT
|
||||
|
||||
- EC-WF-001: Test Parallel Approval ด้วย 2 Browser Session พร้อมกัน
|
||||
- EC-STOR-002: Upload EICAR Test File (ClamAV Test Virus)
|
||||
- EC-RFA-001: สร้าง RFA สำหรับ Revision เดิมที่มี Active RFA → Assert Block
|
||||
- EC-RFA-006: Cancel Draft RFA → Verify Shop Drawing Revision ถูกปลดผูก
|
||||
- EC-RFA-007: Contractor A ค้นหา → Assert ไม่เห็น RFA ของ Contractor B
|
||||
|
||||
---
|
||||
|
||||
## 📝 Document Control
|
||||
|
||||
- **Version:** 1.0.0 | **Status:** DRAFT
|
||||
- **Created:** 2026-03-11 | **Owner:** Nattanin Peancharoen
|
||||
- **Version:** 1.8.1 | **Status:** updated
|
||||
- **Created:** 2026-03-11 | **Updated:** 2026-03-24 | **Owner:** Nattanin Peancharoen
|
||||
- **Changes:** Added EC-RFA-005~007 (Edit/Cancel/Search RFA), Updated UUID references (ADR-019), Sync with US-012a~012c and AC-RFA-007~009
|
||||
- **Next Review:** Pre-UAT (T-2 สัปดาห์ก่อน Go-Live)
|
||||
- **Classification:** Internal Use Only — Developer & QA Reference
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
# 🖼️ UI/UX Wireframes & Screen Inventory — LCBP3-DMS v1.8.0
|
||||
# 🖼️ UI/UX Wireframes & Screen Inventory — LCBP3-DMS v1.8.1
|
||||
|
||||
---
|
||||
|
||||
title: 'UI/UX Screen Inventory, Navigation Map, and Wireframes'
|
||||
version: 1.0.0
|
||||
status: DRAFT
|
||||
version: 1.8.1
|
||||
status: updated
|
||||
owner: Nattanin Peancharoen (Product Owner)
|
||||
last_updated: 2026-03-11
|
||||
last_updated: 2026-03-24
|
||||
related:
|
||||
|
||||
- specs/01-Requirements/01-02-business-rules/01-02-03-ui-ux-rules.md
|
||||
- specs/01-Requirements/01-04-user-stories.md
|
||||
- specs/01-Requirements/01-05-acceptance-criteria.md
|
||||
- specs/01-Requirements/01-06-edge-cases-and-rules.md
|
||||
- specs/06-Decision-Records/ADR-012-ui-components.md
|
||||
- specs/06-Decision-Records/ADR-019-hybrid-identifier-strategy.md
|
||||
|
||||
---
|
||||
|
||||
@@ -36,27 +39,29 @@ related:
|
||||
│
|
||||
├── /correspondences → รายการ Correspondence
|
||||
│ ├── /correspondences/new → สร้างใหม่
|
||||
│ └── /correspondences/:id → รายละเอียด + Workflow
|
||||
│ └── /correspondences/:uuid → รายละเอียด + Workflow
|
||||
│
|
||||
├── /rfas → รายการ RFA
|
||||
│ ├── /rfas/new → สร้างใหม่
|
||||
│ └── /rfas/:id → รายละเอียด + Workflow
|
||||
│ ├── /rfas/:uuid → รายละเอียด + Workflow
|
||||
│ ├── /rfas/:uuid/edit → แก้ไข Draft RFA (ใหม่!)
|
||||
│ └── /rfas/search → ค้นหาและกรอง RFA (ใหม่!)
|
||||
│
|
||||
├── /transmittals → รายการ Transmittal
|
||||
│ ├── /transmittals/new → สร้างใหม่ (รวม RFAs)
|
||||
│ └── /transmittals/:id → รายละเอียด
|
||||
│ └── /transmittals/:uuid → รายละเอียด
|
||||
│
|
||||
├── /drawings → Drawing Management
|
||||
│ ├── /drawings/contract → Contract Drawings
|
||||
│ │ ├── /drawings/contract/new → Upload ใหม่
|
||||
│ │ └── /drawings/contract/:id → รายละเอียด
|
||||
│ │ └── /drawings/contract/:uuid → รายละเอียด
|
||||
│ └── /drawings/shop → Shop Drawings
|
||||
│ ├── /drawings/shop/new → Upload ใหม่
|
||||
│ └── /drawings/shop/:id → รายละเอียด + RFA History
|
||||
│ └── /drawings/shop/:uuid → รายละเอียด + RFA History
|
||||
│
|
||||
├── /circulations → Circulation Sheets (Internal)
|
||||
│ ├── /circulations/new → สร้างใหม่
|
||||
│ └── /circulations/:id → รายละเอียด + Assignees
|
||||
│ └── /circulations/:uuid → รายละเอียด + Assignees
|
||||
│
|
||||
├── /search → Full-text Search
|
||||
│
|
||||
@@ -122,13 +127,16 @@ Mobile: Sidebar → Collapsible Hamburger Drawer (ตาม UI-Rule 5.11)
|
||||
| SCR-003 | `/dashboard` | Dashboard | ทุก Role | 🔴 Must |
|
||||
| SCR-004 | `/correspondences` | Correspondence List | Doc Control | 🔴 Must |
|
||||
| SCR-005 | `/correspondences/new` | Create Correspondence | Doc Control | 🔴 Must |
|
||||
| SCR-006 | `/correspondences/:id` | Correspondence Detail + Workflow | ทุก Role | 🔴 Must |
|
||||
| SCR-006 | `/correspondences/:uuid` | Correspondence Detail + Workflow | ทุก Role | 🔴 Must |
|
||||
| SCR-007 | `/rfas` | RFA List | Doc Control | 🔴 Must |
|
||||
| SCR-008 | `/rfas/new` | Create RFA | Doc Control | 🔴 Must |
|
||||
| SCR-009 | `/rfas/:id` | RFA Detail + Workflow | ทุก Role | 🔴 Must |
|
||||
| SCR-009 | `/rfas/:uuid` | RFA Detail + Workflow | ทุก Role | 🔴 Must |
|
||||
| SCR-008b | `/rfas/:uuid/edit` | Edit Draft RFA | Doc Control | 🔴 Must |
|
||||
| SCR-008c | — (action modal) | Cancel Draft RFA | Doc Control | 🔴 Must |
|
||||
| SCR-008d | `/rfas/search` | RFA Search & Filter | Doc Control | 🔴 Must |
|
||||
| SCR-010 | `/transmittals` | Transmittal List | Doc Control | 🟠 Should |
|
||||
| SCR-011 | `/transmittals/new` | Create Transmittal | Doc Control | 🟠 Should |
|
||||
| SCR-012 | `/transmittals/:id` | Transmittal Detail | ทุก Role | 🟠 Should |
|
||||
| SCR-012 | `/transmittals/:uuid` | Transmittal Detail | ทุก Role | 🟠 Should |
|
||||
| SCR-013 | `/drawings/contract` | Contract Drawing List | Doc Control | 🟠 Should |
|
||||
| SCR-014 | `/drawings/shop` | Shop Drawing List | Doc Control | 🟠 Should |
|
||||
| SCR-015 | `/drawings/shop/:id` | Shop Drawing Detail | ทุก Role | 🟠 Should |
|
||||
@@ -144,7 +152,7 @@ Mobile: Sidebar → Collapsible Hamburger Drawer (ตาม UI-Rule 5.11)
|
||||
| SCR-025 | `/admin/doc-numbering` | Document Number Config | Superadmin | 🟠 Should |
|
||||
| SCR-026 | `/admin/audit-logs` | Audit Log Viewer | Org Admin+ | 🟠 Should |
|
||||
|
||||
**รวม:** 26 หน้า (9 Must / 13 Should / 1 Could)
|
||||
**รวม:** 29 หน้า (12 Must / 14 Should / 1 Could)
|
||||
|
||||
---
|
||||
|
||||
@@ -404,6 +412,122 @@ Workflow Step Popup (คลิก Step ที่ผ่านแล้ว):
|
||||
|
||||
---
|
||||
|
||||
### SCR-008b: Edit Draft RFA
|
||||
|
||||
```
|
||||
┌─ แก้ไข RFA (Draft) ───────────────────────────────────────────────┐
|
||||
│ LCBP3-RFA-STR-0042 | สถานะ: 🟡 DRAFT | แก้ไขล่าสุด: 13:28:45 │
|
||||
│ │
|
||||
│ ⚠️ สามารถแก้ไขได้เฉพาะในสถานะ Draft เท่านั้น │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Subject* │ │
|
||||
│ │ [ขออนุมัติแก้ไขแบบ Shop Drawing ส่วน Foundation...] │ │
|
||||
│ │ │ │
|
||||
│ │ Body/Description* │ │
|
||||
│ │ [เนื่องจากมีการเปลี่ยนแปลงรายละเอียด Connection Plate...] │ │
|
||||
│ │ │ │
|
||||
│ │ Remarks │ │
|
||||
│ │ [_____________________________________________] │ │
|
||||
│ │ │ │
|
||||
│ │ 📋 RFA Details (JSON Schema v1) — ไม่สามารถแก้ไขได้ │ │
|
||||
│ │ Drawing Count: 1 | Discipline: Structural | Due: 20 มี.ค. │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📎 Shop Drawing (ไม่สามารถเปลี่ยนได้): │
|
||||
│ ☑️ CD-STR-001-Foundation-RevA.pdf (2.3MB) ✅ Scan OK │
|
||||
│ │
|
||||
│ [บันทึก Draft] [Submit →] [ยกเลิก] │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Validation:
|
||||
- ถ้าสถานะ ≠ DRAFT → Redirect ไปหน้า detail พร้อม error toast
|
||||
- Shop Drawing Revision ไม่สามารถเปลี่ยน (EC-RFA-001)
|
||||
- Auto-save ทุก 2 วินาที
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SCR-008c: Cancel Draft RFA (Modal)
|
||||
|
||||
```
|
||||
┌─ ยกเลิก RFA (Draft) ───────────────────────────────────────────────┐
|
||||
│ LCBP3-RFA-STR-0042 | สถานะ: 🟡 DRAFT │
|
||||
│ │
|
||||
│ ⚠️ การยกเลิกจะทำให้ Shop Drawing Revision นี้สามารถสร้าง RFA ใหม่ได้ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ เหตุผลการยกเลิก* │ │
|
||||
│ │ [_____________________________________________] │ │
|
||||
│ │ │ │
|
||||
│ │ เลือกเหตุผล: │ │
|
||||
│ │ ○ ข้อมูลไม่ครบถ้วย │ │
|
||||
│ │ ○ แก้ไขข้อมูลผิดพลาดหลายครั้ง │ │
|
||||
│ │ ○ ไม่ต้องการส่งออกแล้ว │ │
|
||||
│ │ ○ อื่นๆ (ระบุ) │ │
|
||||
│ │ │ │
|
||||
│ │ [คำอธิบายเพิ่มเติม...] │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 🔔 ผู้ที่เกี่ยวข้องจะได้รับแจ้งเตือน: │
|
||||
│ - Document Control ที่สร้าง RFA (Email + In-App) │
|
||||
│ - Admin ขององค์กร (ถ้ามีการตั้งค่า) │
|
||||
│ │
|
||||
│ [← กลับ] [✅ ยืนยันการยกเลิก] │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Post-cancel Flow:
|
||||
- RFA status → CANCELLED
|
||||
- Shop Drawing Revision.available → true
|
||||
- Audit Log: CANCELLED + reason + user + timestamp
|
||||
- Redirect ไปหน้า RFA List พร้อม success toast
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SCR-008d: RFA Search & Filter
|
||||
|
||||
```
|
||||
┌─ ค้นหาและกรอง RFA ───────────────────────────────────────────────────┐
|
||||
│ 🔍 [ค้นหา RFA...] [ค้นหา] [ตั้งค่ากรอง] │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 📁 Project: [LCBP3 ▼] │ │
|
||||
│ │ 📊 Status: [ทั้งหมด ▼] 🟡DRAFT 🔵SUBMITTED 🔄FAP ✅APPROVED ❌REJECTED │ │
|
||||
│ │ 📅 Revision: [ทั้งหมด ▼] CURRENT OLD ALL │ │
|
||||
│ │ 🏢 Originator: [ทั้งหมด ▼] [สค.] [กทท.] [ผรม.] [คคง.] │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ พบ 15 รายการ (แสดงตามสิทธิ์ของคุณ) │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ ☐ │ เลขที่ │ Subject | สถานะ | วันที่ │ │ │
|
||||
│ ├──┼─────────────┼──────────────────────┼────────┼──────────┤ │
|
||||
│ │ ☐ │ RFA-STR-0042 │ Foundation Plan Rev.A│ 🟡DRAFT │ 10 มี.ค. │[✏️]│ │
|
||||
│ │ ☐ │ RFA-STR-0043 │ Column Detail Rev.B │ 🔵SUBMIT│ 12 มี.ค. │[👁️]│ │
|
||||
│ │ ☐ │ RFA-STR-0041 │ Beam Design Rev.A │ ✅APPROV│ 08 มี.ค. │[👁️]│ │
|
||||
│ │ ☐ │ RFA-STR-0040 │ Slab Detail Rev.A | ❌REJECT│ 05 มี.ค. │[✏️]│ │
|
||||
│ └────────┴─────────────┴──────────────────────┴────────┴──────────┘ │
|
||||
│ │
|
||||
│ [< 1 2 >] แสดง 10/15 [ส่งออก Excel] │
|
||||
│ │
|
||||
│ ⚠️ หมายเหตุ RBAC: │
|
||||
│ - DRAFT → เห็นเฉพาะ originator organization │
|
||||
│ - สถานะอื่น → เห็นตาม project/contract scope │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Advanced Filters (Collapsible):
|
||||
┌─ กรองขั้นสูง ───────────────────────────────────────────────────┐
|
||||
│ 📅 วันที่สร้าง: [____] ถึง [____] │
|
||||
│ 👤 ผู้สร้าง: [ค้นหา...] │
|
||||
│ 📝 มีคำว่า: [ค้นหา...] │
|
||||
│ 🏷️ Tags: [foundation] [column] [beam] │
|
||||
│ [ค้นหา] [ล้าง] │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SCR-009: RFA Detail + Workflow
|
||||
|
||||
```
|
||||
@@ -548,8 +672,9 @@ User Edit Drawer (Slide in from right):
|
||||
/* Status Colors */
|
||||
--status-draft: hsl(48, 96%, 53%); /* Yellow */
|
||||
--status-submitted: hsl(217, 91%, 60%); /* Blue */
|
||||
--status-review: hsl(24, 95%, 53%); /* Orange */
|
||||
--status-fap: hsl(24, 95%, 53%); /* Orange */
|
||||
--status-approved: hsl(142, 71%, 45%); /* Green */
|
||||
--status-approved-wc: hsl(142, 71%, 35%); /* Green Dark */
|
||||
--status-rejected: hsl(0, 84%, 60%); /* Red */
|
||||
--status-cancelled: hsl(215, 14%, 55%); /* Gray */
|
||||
--status-overdue: hsl(0, 84%, 60%); /* Red (same as rejected) */
|
||||
@@ -579,6 +704,8 @@ font-family: 'Inter', 'Noto Sans Thai', sans-serif;
|
||||
| Component | Default | Hover | Active | Disabled | Error |
|
||||
| -------------- | ---------------- | ---------------- | ------------------- | --------------- | -------------- |
|
||||
| Button Primary | bg-primary | bg-primary-hover | scale-95 | opacity-50 | — |
|
||||
| Button Secondary| bg-surface | bg-muted | scale-95 | opacity-50 | — |
|
||||
| Button Danger | bg-red-500 | bg-red-600 | scale-95 | opacity-50 | — |
|
||||
| Input | border-gray-300 | border-primary | border-primary ring | border-gray-200 | border-red-500 |
|
||||
| Table Row | bg-surface | bg-muted | — | opacity-60 | bg-red-50 |
|
||||
| Badge | per status color | — | — | — | — |
|
||||
@@ -630,8 +757,9 @@ User พิมพ์ใน Form → debounce 2 วินาที → บัน
|
||||
|
||||
## 📝 Document Control
|
||||
|
||||
- **Version:** 1.0.0 | **Status:** DRAFT
|
||||
- **Created:** 2026-03-11 | **Owner:** Nattanin Peancharoen
|
||||
- **Version:** 1.8.1 | **Status:** updated
|
||||
- **Created:** 2026-03-11 | **Updated:** 2026-03-24 | **Owner:** Nattanin Peancharoen
|
||||
- **Changes:** Added SCR-008b~008d (Edit/Cancel/Search RFA), Updated routes to use UUID (ADR-019), Added new status colors and button variants, Sync with US-012a~012c and AC-RFA-007~009
|
||||
- **Next Step:** สร้าง High-fidelity Mockup ใน Figma ตามโครงสร้างนี้
|
||||
- **Figma Link:** [TBD — สร้างใน Figma Community หรือ Self-hosted Penpot]
|
||||
- **Classification:** Internal Use Only
|
||||
|
||||
Reference in New Issue
Block a user