This commit is contained in:
@@ -0,0 +1,460 @@
|
||||
# 📖 User Stories — LCBP3-DMS v1.8.0
|
||||
|
||||
---
|
||||
title: 'User Stories — All Modules'
|
||||
version: 1.0.0
|
||||
status: DRAFT
|
||||
owner: Nattanin Peancharoen (Product Owner)
|
||||
last_updated: 2026-03-11
|
||||
related:
|
||||
- specs/01-Requirements/01-01-objectives.md
|
||||
- specs/01-Requirements/01-05-acceptance-criteria.md
|
||||
- specs/01-Requirements/01-03-modules/
|
||||
---
|
||||
|
||||
## 📖 วิธีอ่าน
|
||||
|
||||
- **Format:** `As a [role] / I want to [goal] / So that [benefit]`
|
||||
- **Priority:** 🔴 M (Must) | 🟠 S (Should) | 🟡 C (Could) | ⚫ W (Won't-Now)
|
||||
- **SP:** Story Points (Fibonacci) — 1 SP ≈ ความซับซ้อนระดับ Login
|
||||
- **AC Link:** → `[AC-XXX-YYY]` อ้างอิง `01-05-acceptance-criteria.md`
|
||||
|
||||
---
|
||||
|
||||
## 👥 Epic 1: Authentication & User Management
|
||||
|
||||
### US-001 — Login เข้าระบบ
|
||||
**Priority:** 🔴 M | **SP:** 2 | **AC:** AC-AUTH-001, AC-AUTH-002
|
||||
|
||||
```
|
||||
As a ผู้ใช้งานทุกประเภท
|
||||
I want to login ด้วย Username + Password
|
||||
So that ฉันเข้าถึงระบบตามบทบาทของตนได้
|
||||
```
|
||||
**Done When:**
|
||||
- Login สำเร็จ → Dashboard | Password ผิด → Error กลางๆ
|
||||
- ผิดเกิน 5 ครั้งใน 1 นาที → 429 Rate Limit
|
||||
- Audit Log: `LOGIN_SUCCESS` / `LOGIN_FAILED` + IP
|
||||
|
||||
---
|
||||
|
||||
### US-002 — เปลี่ยนรหัสผ่านครั้งแรก
|
||||
**Priority:** 🔴 M | **SP:** 2 | **AC:** AC-AUTH-003
|
||||
|
||||
```
|
||||
As a ผู้ใช้งานใหม่ที่เพิ่งถูกสร้างโดย Admin
|
||||
I want to ถูกบังคับเปลี่ยนรหัสผ่านใน Login ครั้งแรก
|
||||
So that ฉันมีรหัสผ่านที่ฉันรู้คนเดียว
|
||||
```
|
||||
**Done When:**
|
||||
- Login ครั้งแรก → Redirect หน้าเปลี่ยน Password ทันที (ผ่านไม่ได้)
|
||||
- Password ใหม่ต้องผ่าน Policy (8+ ตัว, อักษรใหญ่-เล็ก-ตัวเลข)
|
||||
|
||||
---
|
||||
|
||||
### US-003 — จัดการ Profile ส่วนตัว
|
||||
**Priority:** 🟠 S | **SP:** 2
|
||||
|
||||
```
|
||||
As a ผู้ใช้งานทุกประเภท
|
||||
I want to แก้ไขข้อมูลส่วนตัวและเปลี่ยนรหัสผ่าน
|
||||
So that ฉันดูแล Account ของตัวเองได้
|
||||
```
|
||||
**Done When:**
|
||||
- แก้ไข ชื่อ, Email, ช่องทาง Notification ได้
|
||||
- เปลี่ยน Password ต้องยืนยัน Password เก่า
|
||||
|
||||
---
|
||||
|
||||
### US-004 — Superadmin สร้างองค์กร + Project + Contract
|
||||
**Priority:** 🔴 M | **SP:** 5 | **AC:** AC-ADMIN-001, AC-ADMIN-002
|
||||
|
||||
```
|
||||
As a Superadmin
|
||||
I want to สร้าง Organization, Project, Contract และผูกความสัมพันธ์กัน
|
||||
So that ระบบพร้อมให้แต่ละองค์กรเริ่มทำงานได้
|
||||
```
|
||||
**Done When:**
|
||||
- สร้าง Org → แต่งตั้ง Org Admin ได้ทันที
|
||||
- สร้าง Project → ผูก Organizations (หลายองค์กร)
|
||||
- สร้าง Contract → 1 Contractor ต่อ 1 Contract
|
||||
- กำหนด Document Number Template ต่อ Project
|
||||
|
||||
---
|
||||
|
||||
### US-005 — Org Admin จัดการ User ในองค์กร
|
||||
**Priority:** 🔴 M | **SP:** 3 | **AC:** AC-ADMIN-003
|
||||
|
||||
```
|
||||
As a Org Admin
|
||||
I want to เพิ่ม/แก้ไข/Deactivate User และกำหนด Role
|
||||
So that ทีมงานเข้าถึงระบบได้ตามหน้าที่
|
||||
```
|
||||
**Done When:**
|
||||
- เพิ่ม User → Email แจ้ง Credentials อัตโนมัติ
|
||||
- Deactivate ได้ (ไม่ Delete — Audit ยังอยู่)
|
||||
- เห็นเฉพาะ User ในองค์กรตัวเอง
|
||||
|
||||
---
|
||||
|
||||
### US-006 — Permission Isolation ระหว่าง Contractor
|
||||
**Priority:** 🔴 M | **SP:** 2 | **AC:** AC-ADMIN-004
|
||||
|
||||
```
|
||||
As a ระบบ
|
||||
I want to ป้องกัน Contractor A เห็นข้อมูล Contractor B
|
||||
So that ข้อมูลทางธุรกิจของแต่ละ Contractor เป็นความลับ
|
||||
```
|
||||
**Done When:**
|
||||
- Contractor A→ ไม่เห็น List เอกสาร B | พยายาม Access URL ตรงๆ → 403
|
||||
- Audit Log บันทึก Unauthorized Attempt
|
||||
|
||||
---
|
||||
|
||||
## 📨 Epic 2: Correspondence Management
|
||||
|
||||
### US-007 — สร้าง Correspondence Draft
|
||||
**Priority:** 🔴 M | **SP:** 5 | **AC:** AC-CORR-001
|
||||
|
||||
```
|
||||
As a Document Control
|
||||
I want to สร้าง Correspondence (Letter/RFI) ในสถานะ Draft พร้อมแนบไฟล์
|
||||
So that เตรียมเอกสารได้ก่อนส่งโดยองค์กรอื่นยังไม่เห็น
|
||||
```
|
||||
**Done When:**
|
||||
- Form: Subject, To (หลายองค์กร), CC, Doc Type, Attachments (PDF/ZIP)
|
||||
- Drag-and-Drop Multi-file | ClamAV Scan ทุกไฟล์
|
||||
- Auto-Save Draft → LocalStorage (กันข้อมูลสูญ)
|
||||
- ผู้ใช้นอกองค์กรไม่เห็น Draft
|
||||
|
||||
---
|
||||
|
||||
### US-008 — Submit Correspondence + Auto Number
|
||||
**Priority:** 🔴 M | **SP:** 5 | **AC:** AC-CORR-002
|
||||
|
||||
```
|
||||
As a Document Control
|
||||
I want to Submit Correspondence และให้ระบบออกเลขอัตโนมัติ
|
||||
So that เอกสารได้รับเลขที่ไม่ซ้ำและส่งถึงผู้รับทันที
|
||||
```
|
||||
**Done When:**
|
||||
- ออกเลขตาม Template (เช่น `LCBP3-สค.-กทท.-LETTER-0001-68`)
|
||||
- เลขไม่ซ้ำแม้ Submit พร้อมกัน (Redis Redlock)
|
||||
- สถานะ → SUBMITTED | Workflow Instance ถูกสร้าง
|
||||
- ผู้รับ → Email + In-App Notification
|
||||
|
||||
---
|
||||
|
||||
### US-009 — ดู Correspondence ใน Inbox
|
||||
**Priority:** 🔴 M | **SP:** 3 | **AC:** AC-CORR-003
|
||||
|
||||
```
|
||||
As a Document Control ขององค์กรผู้รับ
|
||||
I want to เห็น Correspondence ที่ส่งมาถึงองค์กรในรายการ
|
||||
So that ดำเนินการได้ทันที (สร้าง Circulation, ตอบกลับ)
|
||||
```
|
||||
**Done When:**
|
||||
- List แสดง Received/Sent แยก | PDF Viewer ในแอป (Streaming)
|
||||
- ดาวน์โหลดไฟล์แนบได้ (ถ้ามีสิทธิ์)
|
||||
|
||||
---
|
||||
|
||||
### US-010 — อ้างอิง + Tag เอกสาร
|
||||
**Priority:** 🟠 S | **SP:** 3 | **AC:** AC-CORR-004
|
||||
|
||||
```
|
||||
As a Document Control
|
||||
I want to อ้างอิงเอกสารเก่าและกำหนด Tag หลาย Tag
|
||||
So that จัดกลุ่มเอกสารและ Navigate ข้าม Thread ได้
|
||||
```
|
||||
**Done When:**
|
||||
- ค้นหาและเลือก Reference Documents | Link ระหว่างเอกสาร (คลิก Navigate)
|
||||
- กำหนด Tag หลาย Tag | ค้นหาได้จาก Tag
|
||||
|
||||
---
|
||||
|
||||
### US-011 — ยกเลิก Correspondence (Admin)
|
||||
**Priority:** 🟡 C | **SP:** 2 | **AC:** AC-CORR-005
|
||||
|
||||
```
|
||||
As a Org Admin / Superadmin
|
||||
I want to ยกเลิก Correspondence ที่ Submit แล้ว พร้อมระบุเหตุผล
|
||||
So that เอกสารที่ส่งผิดถูกระงับโดยมีหลักฐาน Audit
|
||||
```
|
||||
**Done When:**
|
||||
- ต้องกรอก cancel_reason | สถานะ → CANCELLED
|
||||
- Editor/Viewer ทำ Cancel ไม่ได้ → 403
|
||||
|
||||
---
|
||||
|
||||
## 📋 Epic 3: RFA Management
|
||||
|
||||
### US-012 — สร้าง RFA + Shop Drawing
|
||||
**Priority:** 🔴 M | **SP:** 8 | **AC:** AC-RFA-001
|
||||
|
||||
```
|
||||
As a Document Control ของ Contractor
|
||||
I want to สร้าง RFA พร้อม Upload Shop Drawing
|
||||
So that ยื่นขออนุมัติแบบก่อสร้างจากที่ปรึกษาได้อย่างเป็นระบบ
|
||||
```
|
||||
**Done When:**
|
||||
- Form: RFA Type, Discipline, Shop Drawing (PDF/DWG/ZIP)
|
||||
- 1 Shop Drawing Revision = 1 RFA เท่านั้น
|
||||
- ClamAV Scan | Draft (ไม่เห็นข้ามองค์กร)
|
||||
|
||||
---
|
||||
|
||||
### US-013 — Submit RFA ผ่าน Transmittal
|
||||
**Priority:** 🔴 M | **SP:** 8 | **AC:** AC-RFA-002, AC-TRM-001
|
||||
|
||||
```
|
||||
As a Document Control ของ Contractor
|
||||
I want to สร้าง Transmittal รวม RFA หลายฉบับ ส่งไปยังที่ปรึกษา
|
||||
So that ส่งเอกสารเป็นชุด ที่ปรึกษาได้รับทุกฉบับพร้อมกัน
|
||||
```
|
||||
**Done When:**
|
||||
- Transmittal → เลือก RFA หลายฉบับ | ออกเลขเองเป็น Correspondence
|
||||
- RFA แต่ละฉบับ → ออกเลขตาม Format `LCBP3-RFA-{DISCIPLINE}-{SEQ}`
|
||||
- ที่ปรึกษา → Notification
|
||||
|
||||
---
|
||||
|
||||
### US-014 — Review RFA (Approved / w.Comments / Rejected)
|
||||
**Priority:** 🔴 M | **SP:** 5 | **AC:** AC-RFA-003~005
|
||||
|
||||
```
|
||||
As a Engineer ของ Supervisor Organization
|
||||
I want to เปิดดู Shop Drawing และให้คำตอบ RFA
|
||||
So that Contractor ได้รับผลพิจารณาและดำเนินการต่อได้
|
||||
```
|
||||
**Done When:**
|
||||
- PDF Viewer Streaming | ปุ่ม: Approved / Approved w/Comments / Rejected
|
||||
- Comment บังคับสำหรับ Approved w/Comments และ Rejected
|
||||
- Originator → Notification | Workflow History บันทึกครบ
|
||||
|
||||
---
|
||||
|
||||
### US-015 — ยื่น RFA Revision ใหม่หลัง Reject
|
||||
**Priority:** 🟠 S | **SP:** 5 | **AC:** AC-RFA-006
|
||||
|
||||
```
|
||||
As a Document Control ของ Contractor
|
||||
I want to สร้าง RFA Revision ใหม่ (Rev.B) หลัง Rev.A ถูก Rejected
|
||||
So that แก้ไขและยื่น Shop Drawing เวอร์ชันใหม่ได้
|
||||
```
|
||||
**Done When:**
|
||||
- Rev.B ผูกกับ Shop Drawing Rev.B | Rev.A ยังดูได้
|
||||
- Revision Code เปลี่ยนตาม Sequence (A→B→C)
|
||||
|
||||
---
|
||||
|
||||
## 📐 Epic 4: Drawing Management
|
||||
|
||||
### US-016 — Upload Contract Drawing
|
||||
**Priority:** 🟠 S | **SP:** 5 | **AC:** AC-DRW-001
|
||||
|
||||
```
|
||||
As a Document Control ของ Design Consultant
|
||||
I want to Upload แบบคู่สัญญา (Contract Drawing) พร้อมกำหนดหมวดหมู่
|
||||
So that Contractor ใช้อ้างอิงใน Shop Drawing ได้
|
||||
```
|
||||
**Done When:**
|
||||
- Upload PDF → Drawing Number, Category, Discipline
|
||||
- Shop Drawing Link Reference กับ Contract Drawing ได้
|
||||
|
||||
---
|
||||
|
||||
### US-017 — Upload Shop Drawing + Revision Control
|
||||
**Priority:** 🟠 S | **SP:** 5 | **AC:** AC-DRW-002, AC-DRW-003
|
||||
|
||||
```
|
||||
As a Document Control ของ Contractor
|
||||
I want to Upload Shop Drawing พร้อม Reference Contract Drawing และจัดการ Revision
|
||||
So that ผู้ Review เห็น Revision ล่าสุด และ History ทุก Revision
|
||||
```
|
||||
**Done When:**
|
||||
- ค้นหาและเลือก Contract Drawing ที่ Reference
|
||||
- Rev.ใหม่ → Rev.เก่า Mark "Superseded" แต่ยังดูได้
|
||||
- 1 Revision = 1 RFA เท่านั้น (Constraint enforced)
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Epic 5: Workflow Engine
|
||||
|
||||
### US-018 — ดู Workflow Diagram ของเอกสาร
|
||||
**Priority:** 🟠 S | **SP:** 3 | **AC:** AC-WF-004
|
||||
|
||||
```
|
||||
As a ผู้ใช้งานที่มีสิทธิ์ดูเอกสาร
|
||||
I want to เห็น Workflow Diagram แบบ Visual
|
||||
So that รู้ทันทีว่าเอกสารอยู่ขั้นตอนไหน ใครถืออยู่
|
||||
```
|
||||
**Done When:**
|
||||
- Workflow Diagram แสดง State ปัจจุบัน (Highlight)
|
||||
- คลิก Step ที่ผ่านมา → Audit Log ย่อย (ใคร/เมื่อไหร่/Comment)
|
||||
- Step ที่ยังไม่ถึง → Disabled Style
|
||||
|
||||
---
|
||||
|
||||
### US-019 — Approve / Reject ผ่าน Workflow
|
||||
**Priority:** 🔴 M | **SP:** 5 | **AC:** AC-WF-002, AC-WF-003
|
||||
|
||||
```
|
||||
As a Reviewer ที่ถูก Assign ใน Workflow
|
||||
I want to Approve / Reject เอกสารในขั้นตอนที่ฉันรับผิดชอบ
|
||||
So that Workflow เดินหน้าหรือส่งกลับตามการตัดสินใจ
|
||||
```
|
||||
**Done When:**
|
||||
- เห็นปุ่ม Action เฉพาะ Step ที่เป็นของฉัน
|
||||
- Wrong Role → ปุ่มซ่อน / 403 ถ้าเรียก API ตรงๆ
|
||||
- ทุก Action → Workflow History + Timestamp
|
||||
|
||||
---
|
||||
|
||||
### US-020 — Force Proceed + Revert (Document Control)
|
||||
**Priority:** 🟡 C | **SP:** 3 | **AC:** AC-WF-005
|
||||
|
||||
```
|
||||
As a Document Control
|
||||
I want to บังคับข้ามหรือย้อน Workflow Step ในกรณีพิเศษ
|
||||
So that Workflow ที่ติดขัดถูก Unblock ได้อย่างมีหลักฐาน
|
||||
```
|
||||
**Done When:**
|
||||
- ปุ่ม "Force Proceed" / "Revert" เห็นได้เฉพาะ Document Control ขึ้นไป
|
||||
- ต้องกรอก reason | Audit Log: FORCE_PROCEED / REVERT
|
||||
|
||||
---
|
||||
|
||||
### US-021 — กำหนด Deadline ใน Workflow
|
||||
**Priority:** 🟡 C | **SP:** 3 | **AC:** AC-WF-006
|
||||
|
||||
```
|
||||
As a Document Control
|
||||
I want to กำหนด Deadline ให้แต่ละ Organization ใน Workflow
|
||||
So that ดำเนินการทันเวลา ไม่เกิดความล่าช้า
|
||||
```
|
||||
**Done When:**
|
||||
- กำหนด Due Date ต่อ Org ใน Workflow
|
||||
- เกิน Deadline → Dashboard Overdue Badge + Notification
|
||||
- 2 วันก่อน → Reminder Notification
|
||||
|
||||
---
|
||||
|
||||
## 📄 Epic 6: Circulation Sheet
|
||||
|
||||
### US-022 — สร้าง Circulation Sheet
|
||||
**Priority:** 🟠 S | **SP:** 5 | **AC:** AC-CIRC-001
|
||||
|
||||
```
|
||||
As a Document Control ภายในองค์กร
|
||||
I want to สร้างใบเวียนสำหรับ Correspondence พร้อมกำหนดผู้รับผิดชอบ
|
||||
So that งานถูก Assign ชัดเจนและมีหลักฐาน
|
||||
```
|
||||
**Done When:**
|
||||
- กำหนด Main / Action / Information Assignees (หลายคน)
|
||||
- Assignees → In-App + Email Notification
|
||||
- Internal Only (ไม่เห็นข้ามองค์กร)
|
||||
|
||||
---
|
||||
|
||||
### US-023 — ติดตาม Circulation Deadline + ปิด
|
||||
**Priority:** 🟠 S | **SP:** 3 | **AC:** AC-CIRC-002, AC-CIRC-003
|
||||
|
||||
```
|
||||
As a Assignee / Document Control
|
||||
I want to เห็น Deadline งานของฉันและปิด Circulation เมื่อเสร็จ
|
||||
So that ไม่พลาดงาน และ Track สถานะได้ชัดเจน
|
||||
```
|
||||
**Done When:**
|
||||
- Dashboard My Tasks แสดง Deadline + Overdue Badge
|
||||
- ปิด Circulation → สถานะ CLOSED + Timestamp
|
||||
- My Tasks ลบรายการที่ปิดแล้ว
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Epic 7: Search & Notifications
|
||||
|
||||
### US-024 — ค้นหาเอกสาร Full-text
|
||||
**Priority:** 🟠 S | **SP:** 5 | **AC:** AC-SRCH-001
|
||||
|
||||
```
|
||||
As a ผู้ใช้งานทุกประเภท
|
||||
I want to ค้นหาเอกสารด้วย Keyword ได้รวดเร็ว
|
||||
So that พบเอกสารที่ต้องการโดยไม่ต้องจำเลขที่แม่นยำ
|
||||
```
|
||||
**Done When:**
|
||||
- ผล Search < 500ms (Elasticsearch) | ค้นจาก เลขเอกสาร, Subject, Tag
|
||||
- แสดงเฉพาะเอกสารที่มีสิทธิ์เห็น
|
||||
|
||||
---
|
||||
|
||||
### US-025 — รับ Notification (Email + In-App)
|
||||
**Priority:** 🟠 S | **SP:** 5 | **AC:** AC-NOTIF-001, AC-NOTIF-002
|
||||
|
||||
```
|
||||
As a ผู้ใช้งาน
|
||||
I want to รับ Email และ In-App Notification เมื่อมี Event เกี่ยวข้องกับฉัน
|
||||
So that ไม่พลาดงานโดยไม่ต้องเช็คระบบตลอดเวลา
|
||||
```
|
||||
**Done When:**
|
||||
- Email ถูกส่งภายใน 5 นาที หลัง Event (BullMQ Queue)
|
||||
- Bell Icon Unread Count | คลิก → Navigate ไปเอกสาร
|
||||
- Retry 3 ครั้ง ถ้าส่งไม่ได้ → Dead Letter Queue
|
||||
|
||||
---
|
||||
|
||||
## 💾 Epic 8: File & Dashboard
|
||||
|
||||
### US-026 — Upload ไฟล์ + ดู PDF ในแอป
|
||||
**Priority:** 🟠 S | **SP:** 5 | **AC:** AC-STOR-001, AC-STOR-003
|
||||
|
||||
```
|
||||
As a Document Control / Reviewer
|
||||
I want to Upload ไฟล์หลายไฟล์และดู PDF ในแอปได้เลย
|
||||
So that ทำงานเร็วขึ้นและลดความเสี่ยงข้อมูลรั่วจาก Download
|
||||
```
|
||||
**Done When:**
|
||||
- Drag-and-Drop Multi-file | ClamAV Scan < 30s
|
||||
- In-App PDF Viewer (Range Requests Streaming)
|
||||
- ปุ่ม Download → Disabled สำหรับ Viewer-only
|
||||
|
||||
---
|
||||
|
||||
### US-027 — Dashboard KPI ส่วนตัว
|
||||
**Priority:** 🟠 S | **SP:** 5 | **AC:** AC-DASH-001
|
||||
|
||||
```
|
||||
As a ผู้ใช้งานทุกประเภท
|
||||
I want to เห็น Dashboard สรุปงานของฉันทันทีที่ Login
|
||||
So that รู้สถานะงานโดยไม่ต้องไล่ดูแต่ละ Module
|
||||
```
|
||||
**Done When:**
|
||||
- KPI Cards: Pending RFA, Pending Correspondence, Overdue Circulation
|
||||
- My Tasks Table: Circulation ที่ค้าง + Deadline
|
||||
- Filter ตาม Permission ของ User
|
||||
|
||||
---
|
||||
|
||||
## 📊 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** |
|
||||
|
||||
> **MVP Sprint Focus:** US-001~006, US-007~008, US-012~014, US-019 — ครอบคลุม Core Happy Path ทั้งหมด
|
||||
|
||||
---
|
||||
|
||||
## 📝 Document Control
|
||||
|
||||
- **Version:** 1.0.0 | **Status:** DRAFT
|
||||
- **Created:** 2026-03-11 | **Owner:** Nattanin Peancharoen
|
||||
- **Classification:** Internal Use Only
|
||||
@@ -0,0 +1,771 @@
|
||||
# ✅ Acceptance Criteria — LCBP3-DMS MVP (UAT)
|
||||
|
||||
---
|
||||
|
||||
title: 'Acceptance Criteria & UAT Test Scenarios'
|
||||
version: 1.8.0
|
||||
status: DRAFT — Pending Stakeholder Sign-off
|
||||
owner: Nattanin Peancharoen (Product Owner)
|
||||
last_updated: 2026-03-11
|
||||
related:
|
||||
- specs/01-Requirements/01-01-objectives.md
|
||||
- specs/01-Requirements/01-03-modules/
|
||||
- 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
|
||||
- specs/06-Decision-Records/ADR-016-security-authentication.md
|
||||
|
||||
---
|
||||
|
||||
## 📖 วิธีอ่านเอกสารนี้
|
||||
|
||||
แต่ละ Scenario ใช้รูปแบบ **Given / When / Then** พร้อม:
|
||||
- **ID**: รหัส Scenario ใช้อ้างอิง (AC-XXX-YYY)
|
||||
- **Priority**: 🔴 Blocker | 🟠 Critical | 🟡 Major | 🟢 Minor
|
||||
- **Role**: ผู้ใช้ที่ทดสอบ Scenario นี้
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Module 1: Authentication & Session Management
|
||||
|
||||
### AC-AUTH-001 — Login Success
|
||||
**Priority:** 🔴 Blocker | **Role:** ทุก Role
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | User มีบัญชีในระบบ และ Password ถูกต้อง |
|
||||
| **When** | กรอก Username + Password แล้วกด Login |
|
||||
| **Then** | ✅ ได้รับ JWT Access Token (15 min TTL) + Refresh Token (7 days) |
|
||||
| | ✅ ถูก Redirect ไปที่ Dashboard |
|
||||
| | ✅ Audit Log บันทึก `LOGIN_SUCCESS` พร้อม IP Address |
|
||||
|
||||
### AC-AUTH-002 — Login Failed (Wrong Password)
|
||||
**Priority:** 🔴 Blocker | **Role:** ทุก Role
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | User มีบัญชีในระบบ |
|
||||
| **When** | กรอก Password ผิด |
|
||||
| **Then** | ✅ แสดง Error "ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง" (ไม่บอกว่าอันไหนผิด) |
|
||||
| | ✅ Audit Log บันทึก `LOGIN_FAILED` |
|
||||
| | ✅ หลัง 5 ครั้งใน 1 นาที → Rate Limit 429 Too Many Requests |
|
||||
|
||||
### AC-AUTH-003 — First Login Force Password Change
|
||||
**Priority:** 🔴 Blocker | **Role:** ทุก Role (new user)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | User เพิ่งถูกสร้างโดย Admin (password_must_change = true) |
|
||||
| **When** | Login สำเร็จครั้งแรก |
|
||||
| **Then** | ✅ ถูก Redirect ไปยังหน้า "เปลี่ยนรหัสผ่าน" ทันที |
|
||||
| | ✅ ไม่สามารถเข้าถึงหน้าอื่นได้ จนกว่าจะเปลี่ยนรหัสผ่าน |
|
||||
| | ✅ Password ใหม่ต้องผ่าน Policy (ตัวใหญ่ + ตัวเล็ก + ตัวเลข + 8+ ตัวอักษร) |
|
||||
|
||||
### AC-AUTH-004 — Token Refresh
|
||||
**Priority:** 🟠 Critical | **Role:** ทุก Role
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Access Token หมดอายุ (15 min) แต่ Refresh Token ยังใช้งานได้ |
|
||||
| **When** | Frontend ตรวจพบ 401 Response ระหว่างการใช้งาน |
|
||||
| **Then** | ✅ Frontend auto-refresh token โดยผู้ใช้ไม่รู้สึก |
|
||||
| | ✅ Request เดิม Retry สำเร็จหลัง Token Refresh |
|
||||
|
||||
### AC-AUTH-005 — Logout
|
||||
**Priority:** 🟠 Critical | **Role:** ทุก Role
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | User กำลัง Login อยู่ |
|
||||
| **When** | กด Logout |
|
||||
| **Then** | ✅ Refresh Token ถูก Revoke ใน Database |
|
||||
| | ✅ Redis Permission Cache ถูกลบ |
|
||||
| | ✅ Redirect ไปหน้า Login |
|
||||
| | ✅ Audit Log บันทึก `LOGOUT` |
|
||||
|
||||
---
|
||||
|
||||
## 🏢 Module 2: User & Organization Management (Admin)
|
||||
|
||||
### AC-ADMIN-001 — Superadmin สร้าง Organization
|
||||
**Priority:** 🔴 Blocker | **Role:** Superadmin
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Login ด้วย Superadmin Account |
|
||||
| **When** | สร้าง Organization ใหม่ กรอกชื่อ + รหัสองค์กร |
|
||||
| **Then** | ✅ Organization ถูกสร้างในฐานข้อมูล |
|
||||
| | ✅ สามารถกำหนด Org Admin ได้ทันที |
|
||||
| | ✅ Audit Log บันทึก `ORGANIZATION_CREATED` |
|
||||
|
||||
### AC-ADMIN-002 — Superadmin สร้าง Project + Contract
|
||||
**Priority:** 🔴 Blocker | **Role:** Superadmin
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | มี Organization อย่างน้อย 1 ที่ |
|
||||
| **When** | สร้าง Project → สร้าง Contract ภายใน Project |
|
||||
| **Then** | ✅ Project ผูกกับ Organization ได้หลายองค์กร |
|
||||
| | ✅ Contract ผูกกับ Project (1 Contract ต่อ Contractor) |
|
||||
| | ✅ การตั้งค่า Document Number Format สำหรับ Project ทำได้ |
|
||||
|
||||
### AC-ADMIN-003 — Org Admin เพิ่ม User เข้า Organization
|
||||
**Priority:** 🟠 Critical | **Role:** Org Admin
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Login ด้วย Org Admin |
|
||||
| **When** | เพิ่ม User พร้อม Role (Editor/Viewer/Document Control) |
|
||||
| **Then** | ✅ User ได้รับ Email แจ้ง Credentials |
|
||||
| | ✅ User Login แล้วเห็น Dashboard ขององค์กรตัวเอง |
|
||||
| | ✅ Permission ถูก Cache ใน Redis (ภายใน 30 วินาที) |
|
||||
|
||||
### AC-ADMIN-004 — Permission Isolation ระหว่าง Contractor
|
||||
**Priority:** 🔴 Blocker | **Role:** Document Control (Contractor A)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | มี Contractor A (Contract 1) และ Contractor B (Contract 2) |
|
||||
| **When** | Contractor A Login แล้วพยายาม เข้าดู Document ของ Contractor B |
|
||||
| **Then** | ✅ ได้รับ 403 Forbidden |
|
||||
| | ✅ Contractor A ไม่เห็น Document ของ Contractor B ในรายการ |
|
||||
| | ✅ Audit Log บันทึกความพยายาม Unauthorized Access |
|
||||
|
||||
### AC-ADMIN-005 — Permission Cache Invalidation
|
||||
**Priority:** 🟠 Critical | **Role:** Superadmin
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | User กำลัง Login อยู่และมี Permission Cache ใน Redis |
|
||||
| **When** | Superadmin เปลี่ยน Role ของ User นั้น |
|
||||
| **Then** | ✅ Redis Cache ของ User นั้นถูกล้างทันที |
|
||||
| | ✅ Request ถัดไปของ User ใช้ Permission ใหม่ (ภายใน 1 request cycle) |
|
||||
|
||||
---
|
||||
|
||||
## 📨 Module 3: Correspondence Management
|
||||
|
||||
### AC-CORR-001 — สร้าง Correspondence (Draft)
|
||||
**Priority:** 🔴 Blocker | **Role:** Document Control
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Login ด้วย Document Control ขององค์กรใด |
|
||||
| **When** | สร้าง Correspondence ใหม่ (Letter/RFI) กรอก Subject, To, CC, แนบไฟล์ PDF |
|
||||
| **Then** | ✅ เอกสารถูกบันทึกในสถานะ `DRAFT` |
|
||||
| | ✅ ผู้ใช้ขององค์กรอื่น **ไม่เห็น** Draft นี้ |
|
||||
| | ✅ ผู้สร้างเห็นใน "เอกสารฉบับร่างของฉัน" |
|
||||
|
||||
### AC-CORR-002 — Submit Correspondence + Auto Document Number
|
||||
**Priority:** 🔴 Blocker | **Role:** Document Control
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | มี Correspondence ในสถานะ Draft พร้อม Attachment |
|
||||
| **When** | กด Submit |
|
||||
| **Then** | ✅ ระบบออกเลขเอกสารอัตโนมัติตาม Format Template (เช่น `LCBP3-สคฉ-กทท-LETTER-0001-68`) |
|
||||
| | ✅ เลขเอกสารไม่ซ้ำกัน แม้ Submit พร้อมกันหลาย Request |
|
||||
| | ✅ สถานะเปลี่ยนเป็น `SUBMITTED` |
|
||||
| | ✅ Workflow Instance ถูกสร้างใน `workflow_instances` |
|
||||
| | ✅ องค์กรผู้รับ (To) ได้รับแจ้งเตือน (Email + In-App) |
|
||||
|
||||
### AC-CORR-003 — ผู้รับ Correspondence
|
||||
**Priority:** 🔴 Blocker | **Role:** Document Control (Recipient Org)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Correspondence ถูก Submit มายังองค์กรเรา |
|
||||
| **When** | Document Control ขององค์กรผู้รับ เปิดดู |
|
||||
| **Then** | ✅ เห็นเอกสารใน Inbox/Received |
|
||||
| | ✅ สามารถสร้าง Circulation Sheet ได้ |
|
||||
| | ✅ สามารถดาวน์โหลดไฟล์แนบได้ |
|
||||
|
||||
### AC-CORR-004 — อ้างอิงเอกสารก่อนหน้า (References)
|
||||
**Priority:** 🟡 Major | **Role:** Document Control
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | มีเอกสาร Correspondence เก่าในระบบ |
|
||||
| **When** | สร้าง Correspondence ใหม่และอ้างอิงเอกสารเก่า |
|
||||
| **Then** | ✅ Link เชื่อมระหว่างเอกสารทั้งสอง |
|
||||
| | ✅ สามารถคลิก Navigate ไปดูเอกสารที่อ้างถึงได้ |
|
||||
|
||||
### AC-CORR-005 — Cancel Correspondence (Admin Only)
|
||||
**Priority:** 🟡 Major | **Role:** Org Admin / Superadmin
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Correspondence ถูก Submit แล้ว (สถานะ SUBMITTED+) |
|
||||
| **When** | Admin กด Cancel พร้อมระบุเหตุผล |
|
||||
| **Then** | ✅ สถานะเปลี่ยนเป็น `CANCELLED` |
|
||||
| | ✅ ต้องระบุ `cancel_reason` (ไม่ยอม Empty) |
|
||||
| | ✅ Audit Log บันทึกพร้อมเหตุผล |
|
||||
| | ✅ User ระดับ Viewer/Editor ทำ Cancel ไม่ได้ → 403 |
|
||||
|
||||
---
|
||||
|
||||
## 📋 Module 4: RFA Management
|
||||
|
||||
### AC-RFA-001 — สร้าง RFA + แนบ Shop Drawing
|
||||
**Priority:** 🔴 Blocker | **Role:** Document Control (Contractor)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Login ด้วย Document Control ของ Contractor |
|
||||
| **When** | สร้าง RFA ใหม่ — กรอก RFA Type, Discipline, แนบ Shop Drawing (PDF/DWG/ZIP) |
|
||||
| **Then** | ✅ RFA ถูกบันทึกในสถานะ `DRAFT` |
|
||||
| | ✅ Shop Drawing ผูกกับ RFA (1 Revision = 1 RFA) |
|
||||
| | ✅ ไฟล์ถูก Scan ด้วย ClamAV — ปฏิเสธไฟล์ที่ติด Virus |
|
||||
|
||||
### AC-RFA-002 — Submit RFA + Auto Number
|
||||
**Priority:** 🔴 Blocker | **Role:** Document Control (Contractor)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | RFA Draft พร้อม Shop Drawing |
|
||||
| **When** | กด Submit |
|
||||
| **Then** | ✅ เลขที่ RFA ถูกออกอัตโนมัติตาม Format (`LCBP3-RFA-STR-0001`) |
|
||||
| | ✅ เลขไม่ reset ตามปี (RFA = No reset policy) |
|
||||
| | ✅ สถานะ = `SUBMITTED` |
|
||||
| | ✅ Workflow Routing เริ่มทำงาน (ส่งไปยัง Reviewer) |
|
||||
|
||||
### AC-RFA-003 — Review RFA (Approved)
|
||||
**Priority:** 🔴 Blocker | **Role:** Engineer/Reviewer (Supervisor Org)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | RFA อยู่ในสถานะรอ Review ที่องค์กรเรา |
|
||||
| **When** | Engineer คลิก "Approved" |
|
||||
| **Then** | ✅ สถานะ RFA เปลี่ยนเป็น `APPROVED` |
|
||||
| | ✅ Originator (Contractor) ได้รับแจ้งเตือน |
|
||||
| | ✅ Workflow History บันทึก Action + Timestamp + User |
|
||||
|
||||
### AC-RFA-004 — Review RFA (Approved with Comments)
|
||||
**Priority:** 🟠 Critical | **Role:** Engineer/Reviewer
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | RFA อยู่ในสถานะรอ Review |
|
||||
| **When** | Engineer คลิก "Approved with Comments" + กรอก Comment |
|
||||
| **Then** | ✅ สถานะ = `APPROVED_WITH_COMMENTS` |
|
||||
| | ✅ Comment ถูกบันทึกใน Workflow History |
|
||||
| | ✅ Originator เห็น Comment ได้ |
|
||||
|
||||
### AC-RFA-005 — Review RFA (Rejected)
|
||||
**Priority:** 🟠 Critical | **Role:** Engineer/Reviewer
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | RFA อยู่ในสถานะรอ Review |
|
||||
| **When** | Engineer คลิก "Rejected" + ระบุเหตุผล |
|
||||
| **Then** | ✅ สถานะ = `REJECTED` |
|
||||
| | ✅ เหตุผลการ Reject บันทึกครบถ้วน |
|
||||
| | ✅ Contractor สามารถยื่น RFA Revision ใหม่ได้ |
|
||||
|
||||
### AC-RFA-006 — Revision RFA
|
||||
**Priority:** 🟠 Critical | **Role:** Document Control (Contractor)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | RFA Rev.A ถูก Rejected แล้ว |
|
||||
| **When** | Contractor สร้าง RFA Revision ใหม่ (Rev.B) |
|
||||
| **Then** | ✅ Rev.B ผูกกับ shop_drawing revision ใหม่ |
|
||||
| | ✅ เลขที่เอกสารเดิม — Revision Code เปลี่ยน (เช่น `-B`) |
|
||||
| | ✅ Rev.A ยังอ่านได้ (ไม่ถูกลบ) |
|
||||
|
||||
---
|
||||
|
||||
## 📐 Module 5: Drawing Management
|
||||
|
||||
### AC-DRW-001 — Upload Contract Drawing
|
||||
**Priority:** 🟠 Critical | **Role:** Document Control (Design Consultant)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Login ด้วย Document Control ที่มีสิทธิ์ Contract Drawing |
|
||||
| **When** | Upload แบบคู่สัญญา (PDF) พร้อมระบุ หมวดหมู่ / Drawing Number |
|
||||
| **Then** | ✅ Drawing ถูกบันทึกในระบบ |
|
||||
| | ✅ สามารถอ้างอิงจาก Shop Drawing ได้ |
|
||||
| | ✅ ไม่สามารถแก้ไขได้โดยไม่มีสิทธิ์ |
|
||||
|
||||
### AC-DRW-002 — Upload Shop Drawing + Link to Contract Drawing
|
||||
**Priority:** 🟠 Critical | **Role:** Document Control (Contractor)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | มี Contract Drawing ในระบบแล้ว |
|
||||
| **When** | Upload Shop Drawing พร้อมระบุ Referenced Contract Drawing |
|
||||
| **Then** | ✅ Shop Drawing ผูก Reference กับ Contract Drawing |
|
||||
| | ✅ สามารถ Navigate ไปดู Contract Drawing ที่อ้างถึงได้ |
|
||||
|
||||
### AC-DRW-003 — Shop Drawing Revision Control
|
||||
**Priority:** 🟠 Critical | **Role:** Document Control
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Shop Drawing Rev.A มีอยู่แล้ว |
|
||||
| **When** | Upload Shop Drawing Rev.B |
|
||||
| **Then** | ✅ Rev.B ถือเป็น Current Revision |
|
||||
| | ✅ Rev.A ยังสามารถดูได้ (ไม่ถูกลบ) |
|
||||
| | ✅ 1 Shop Drawing Revision ผูกกับ RFA ได้ 1 ฉบับเท่านั้น |
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Module 6: Unified Workflow Engine
|
||||
|
||||
### AC-WF-001 — Workflow Instance Creation
|
||||
**Priority:** 🔴 Blocker | **Role:** ระบบ (Auto)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Document ถูก Submit |
|
||||
| **When** | ระบบสร้าง Workflow Instance |
|
||||
| **Then** | ✅ `workflow_instances` record ถูกสร้าง |
|
||||
| | ✅ `current_state` = Initial State ตาม DSL |
|
||||
| | ✅ `entity_type` และ `entity_id` ถูกต้อง |
|
||||
|
||||
### AC-WF-002 — Workflow State Transition (Happy Path)
|
||||
**Priority:** 🔴 Blocker | **Role:** ตาม Workflow Role
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Workflow อยู่ใน State A |
|
||||
| **When** | User ที่มีสิทธิ์ทำ Action ที่กำหนดใน DSL |
|
||||
| **Then** | ✅ State เปลี่ยนเป็น State B ตาม Transition Rules |
|
||||
| | ✅ `workflow_histories` บันทึก from_state, to_state, action, user_id, timestamp |
|
||||
| | ✅ Event Notifications ถูก Dispatch (ถ้า DSL กำหนด) |
|
||||
|
||||
### AC-WF-003 — Workflow Unauthorized Transition
|
||||
**Priority:** 🔴 Blocker | **Role:** User ไม่ถูก Role
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Workflow รอ Approve โดย Role X |
|
||||
| **When** | User ที่เป็น Role Y (ไม่ใช่ X) พยายาม Approve |
|
||||
| **Then** | ✅ ได้รับ 403 Forbidden |
|
||||
| | ✅ State ไม่เปลี่ยน |
|
||||
|
||||
### AC-WF-004 — Workflow Visualization (UI)
|
||||
**Priority:** 🟡 Major | **Role:** ทุก Role ที่มีสิทธิ์ดูเอกสาร
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Workflow กำลังดำเนินการอยู่ |
|
||||
| **When** | เปิดดูหน้ารายละเอียดเอกสาร |
|
||||
| **Then** | ✅ แสดง Workflow Diagram พร้อม State ปัจจุบัน |
|
||||
| | ✅ State ที่ผ่านมาแล้วแสดง History (คลิกดูรายละเอียดได้) |
|
||||
| | ✅ State ที่ยังไม่ถึง Disabled |
|
||||
|
||||
### AC-WF-005 — Force Proceed (Document Control Override)
|
||||
**Priority:** 🟡 Major | **Role:** Document Control
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Workflow ติดอยู่ที่ State ใด State หนึ่ง |
|
||||
| **When** | Document Control กด "Force Proceed" พร้อมระบุเหตุผล |
|
||||
| **Then** | ✅ Workflow ข้ามไป State ถัดไป |
|
||||
| | ✅ Audit Log บันทึก `FORCE_PROCEED` + reason + user |
|
||||
|
||||
### AC-WF-006 — Workflow Deadline & Notification
|
||||
**Priority:** 🟡 Major | **Role:** Document Control
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Workflow ถูกกำหนด Deadline สำหรับ Organization |
|
||||
| **When** | เวลาผ่าน Deadline ไปแล้ว |
|
||||
| **Then** | ✅ ระบบส่ง Reminder Notification ให้ผู้รับผิดชอบ |
|
||||
| | ✅ Dashboard แสดง "Overdue" indicator |
|
||||
|
||||
---
|
||||
|
||||
## 📧 Module 7: Transmittals Management
|
||||
|
||||
### AC-TRM-001 — สร้าง Transmittal (ส่ง RFA หลายฉบับพร้อมกัน)
|
||||
**Priority:** 🟠 Critical | **Role:** Document Control
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | มี RFA Draft หลายฉบับต้องส่งให้ที่ปรึกษา |
|
||||
| **When** | สร้าง Transmittal แนบ RFA หลายฉบับ |
|
||||
| **Then** | ✅ Transmittal ผูกกับ RFA ทุกฉบับ |
|
||||
| | ✅ Transmittal เป็นส่วนหนึ่งใน Correspondence (มีเลขเอกสาร) |
|
||||
| | ✅ ผู้รับเห็น Transmittal พร้อม RFA ที่แนบ |
|
||||
|
||||
---
|
||||
|
||||
## 📄 Module 8: Circulation Sheet Management
|
||||
|
||||
### AC-CIRC-001 — สร้าง Circulation Sheet
|
||||
**Priority:** 🟠 Critical | **Role:** Document Control (ภายในองค์กร)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Correspondence เข้ามาในองค์กร |
|
||||
| **When** | Document Control สร้าง Circulation Sheet กำหนด Main/Action/Info Assignees |
|
||||
| **Then** | ✅ Circulation ถูกสร้าง ผูกกับ Correspondence |
|
||||
| | ✅ Assignees ได้รับแจ้งเตือน (In-App + Email) |
|
||||
| | ✅ ผู้ใช้นอกองค์กรไม่เห็น Circulation Sheet นี้ |
|
||||
|
||||
### AC-CIRC-002 — กำหนด Deadline + แจ้งเตือนล่วงหน้า
|
||||
**Priority:** 🟡 Major | **Role:** Document Control
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Circulation ถูกกำหนด Deadline ให้ Main Assignee |
|
||||
| **When** | เหลืออีก 2 วันก่อน Deadline |
|
||||
| **Then** | ✅ ระบบส่งแจ้งเตือน Reminder |
|
||||
| | ✅ Dashboard แสดง "ใกล้ Deadline" badge |
|
||||
|
||||
### AC-CIRC-003 — ปิด Circulation
|
||||
**Priority:** 🟠 Critical | **Role:** Document Control
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | ดำเนินการตอบกลับ Originator แล้ว |
|
||||
| **When** | กด "ปิด Circulation" |
|
||||
| **Then** | ✅ Circulation สถานะ = `CLOSED` |
|
||||
| | ✅ Audit Log บันทึก closed_by + timestamp |
|
||||
|
||||
---
|
||||
|
||||
## 🔢 Module 9: Document Numbering System
|
||||
|
||||
### AC-DN-001 — Auto Number Generation (Concurrent Safe)
|
||||
**Priority:** 🔴 Blocker | **Role:** ระบบ (Auto)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | User 2 คนกด Submit พร้อมกัน ใน Project/Type เดียวกัน |
|
||||
| **When** | ทั้งสองส่ง Request พร้อมกัน |
|
||||
| **Then** | ✅ เลขเอกสารไม่ซ้ำกัน (Redis Redlock + DB Optimistic Lock) |
|
||||
| | ✅ Response Time < 100ms สำหรับ Generation |
|
||||
| | ✅ ทั้งสอง Request สำเร็จ — ไม่มี Error |
|
||||
|
||||
> **Test Method:** Load Test ด้วย 50 concurrent requests ไปที่ `POST /document-numbering/reserve` — ตรวจสอบว่าเลขไม่ซ้ำ
|
||||
|
||||
### AC-DN-002 — Cancelled Number ไม่ถูกนำกลับมาใช้
|
||||
**Priority:** 🔴 Blocker | **Role:** ระบบ
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | เลขที่ 0012 ถูก Reserved แต่ Document ถูก Cancel ก่อน Confirm |
|
||||
| **When** | มีการ Submit Document ถัดไป |
|
||||
| **Then** | ✅ เลขที่ถัดไปจะเป็น 0013 (ข้าม 0012) |
|
||||
| | ✅ เลข 0012 อยู่ใน `document_number_reservations` สถานะ `CANCELLED` |
|
||||
|
||||
### AC-DN-003 — Number Format Template
|
||||
**Priority:** 🟡 Major | **Role:** Superadmin
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | กำหนด Format Template: `{PROJECT}-{ORIGINATOR}-{RECIPIENT}-{CORR_TYPE}-{SEQ:4}-{YY}` |
|
||||
| **When** | Submit Document ครั้งแรกของปีสำหรับ Pair นั้น |
|
||||
| **Then** | ✅ เลขออกมาถูก Format (เช่น `LCBP3-สค.-กทท.-LETTER-0001-68`) |
|
||||
| | ✅ Preview ตัวอย่างเลขได้ก่อน Save Template |
|
||||
|
||||
### AC-DN-004 — Yearly Reset
|
||||
**Priority:** 🟡 Major | **Role:** ระบบ (Cron)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Correspondence ใช้ Yearly Reset Policy |
|
||||
| **When** | ปีใหม่เปลี่ยน (Cron Job ทำงาน) |
|
||||
| **Then** | ✅ Counter เริ่มนับใหม่จาก 0001 |
|
||||
| | ✅ เลขของปีก่อนยังคงอยู่ในระบบ (ไม่ถูกลบ) |
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Module 10: Search & Discovery
|
||||
|
||||
### AC-SRCH-001 — Full-text Search
|
||||
**Priority:** 🟠 Critical | **Role:** ทุก Role
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | มีเอกสารในระบบ (Indexed ใน Elasticsearch) |
|
||||
| **When** | พิมพ์ค้นหา Keyword ในช่อง Search |
|
||||
| **Then** | ✅ ผล Search ปรากฏภายใน 500ms |
|
||||
| | ✅ ค้นหาได้จาก: เลขเอกสาร, Subject, Tag |
|
||||
| | ✅ แสดงเฉพาะเอกสารที่ User มีสิทธิ์เห็น |
|
||||
|
||||
### AC-SRCH-002 — Advanced Filter
|
||||
**Priority:** 🟡 Major | **Role:** ทุก Role
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | อยู่ในหน้า Correspondence List |
|
||||
| **When** | Filter ด้วย Document Type + Date Range + Status |
|
||||
| **Then** | ✅ รายการ Filter ถูกต้อง |
|
||||
| | ✅ URL อัปเดตให้ Shareable (Query Params) |
|
||||
|
||||
---
|
||||
|
||||
## 📧 Module 11: Notifications
|
||||
|
||||
### AC-NOTIF-001 — Email Notification (Document Submit)
|
||||
**Priority:** 🟠 Critical | **Role:** ระบบ (Auto)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Document ถูก Submit มายังองค์กร |
|
||||
| **When** | Workflow Transition เกิดขึ้น |
|
||||
| **Then** | ✅ Email ถูกส่งไปยัง Recipient ภายใน 5 นาที |
|
||||
| | ✅ Email มี: เลขเอกสาร, Subject, ลิงก์ไปยังเอกสาร |
|
||||
| | ✅ BullMQ Job อยู่ใน Queue (สามารถ Monitor ได้) |
|
||||
|
||||
### AC-NOTIF-002 — In-App Notification
|
||||
**Priority:** 🟡 Major | **Role:** ทุก Role
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | มี Action เกิดขึ้นที่เกี่ยวข้องกับ User |
|
||||
| **When** | User เปิดแอป |
|
||||
| **Then** | ✅ Bell Icon แสดง Unread Count |
|
||||
| | ✅ คลิกดูรายการ Notifications ได้ |
|
||||
| | ✅ คลิกที่ Notification นำทางไปเอกสารที่เกี่ยวข้อง |
|
||||
|
||||
### AC-NOTIF-003 — Notification Retry on Failure
|
||||
**Priority:** 🟡 Major | **Role:** ระบบ
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Email Server ไม่สามารถส่งได้ชั่วคราว |
|
||||
| **When** | BullMQ Job ส่งไม่สำเร็จ |
|
||||
| **Then** | ✅ Retry ด้วย Exponential Backoff (3 ครั้ง) |
|
||||
| | ✅ เมื่อ Retry ครบแล้วยังล้มเหลว → Dead Letter Queue |
|
||||
| | ✅ In-App Notification ยังส่งได้ (Fallback) |
|
||||
|
||||
---
|
||||
|
||||
## 📎 Module 12: File Storage & Security
|
||||
|
||||
### AC-STOR-001 — File Upload (Two-Phase Storage)
|
||||
**Priority:** 🔴 Blocker | **Role:** Document Control
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | User อัปโหลดไฟล์ PDF ขนาด 50MB |
|
||||
| **When** | เลือกไฟล์ + อัปโหลด |
|
||||
| **Then** | ✅ ไฟล์ถูก Upload ไปยัง Temp Storage ก่อน |
|
||||
| | ✅ ClamAV Scan ในเวลา < 30 วินาที |
|
||||
| | ✅ หากผ่าน Scan → ย้ายไปยัง Permanent Storage เมื่อ Document Confirmed |
|
||||
| | ✅ หากไม่ผ่าน Scan → ปฏิเสธพร้อมแสดง Security Warning |
|
||||
|
||||
### AC-STOR-002 — File Type Restriction
|
||||
**Priority:** 🔴 Blocker | **Role:** Document Control
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | User พยายาม Upload ไฟล์ .exe หรือ .js |
|
||||
| **When** | เลือกไฟล์นอก Whitelist |
|
||||
| **Then** | ✅ Frontend Block ก่อน Upload |
|
||||
| | ✅ Backend ยืนยันซ้ำ (Defense in Depth) — 400 Bad Request |
|
||||
|
||||
### AC-STOR-003 — Secure PDF Viewer (No Download)
|
||||
**Priority:** 🟡 Major | **Role:** Viewer
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | User มีสิทธิ์ดูเอกสารแต่ไม่มีสิทธิ์ Download |
|
||||
| **When** | คลิกดูเอกสาร PDF |
|
||||
| **Then** | ✅ เปิดใน In-App PDF Viewer (ไม่ต้อง Download) |
|
||||
| | ✅ ปุ่ม Download ถูก Disable |
|
||||
| | ✅ Range Requests (Streaming) ใช้งานได้ |
|
||||
|
||||
---
|
||||
|
||||
## 📊 Module 13: Dashboard & Audit Log
|
||||
|
||||
### AC-DASH-001 — Dashboard KPI Cards
|
||||
**Priority:** 🟡 Major | **Role:** ทุก Role
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Login เสร็จ |
|
||||
| **When** | เข้าหน้า Dashboard |
|
||||
| **Then** | ✅ KPI Cards แสดง: จำนวน Correspondence, RFA Pending, งานของฉัน, Overdue |
|
||||
| | ✅ "My Tasks" แสดง Circulation ที่ตัวเองต้องทำ |
|
||||
| | ✅ ข้อมูลถูกต้องตามสิทธิ์ของตัวเอง |
|
||||
|
||||
### AC-AUDIT-001 — Audit Log Coverage
|
||||
**Priority:** 🔴 Blocker | **Role:** Superadmin
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | ดำเนินการ Action ต่างๆ ในระบบ (Create, Update, Submit, Approve) |
|
||||
| **When** | ตรวจสอบ Audit Log |
|
||||
| **Then** | ✅ ทุก Action มีบันทึกใน `audit_logs` |
|
||||
| | ✅ บันทึกมี: user_id, action, entity_type, entity_id, ip_address, timestamp |
|
||||
| | ✅ ไม่สามารถแก้ไขหรือลบ Audit Log ได้ (Read-only) |
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Section 14: Security Acceptance Criteria
|
||||
|
||||
### AC-SEC-001 — SQL Injection Prevention
|
||||
**Priority:** 🔴 Blocker | **Role:** QA (Security Test)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | ช่อง Input ใดๆ ในระบบ |
|
||||
| **When** | ใส่ SQL Injection payload เช่น `'; DROP TABLE users; --` |
|
||||
| **Then** | ✅ คำขอถูกปฏิเสธหรือ Sanitized โดยไม่ทำงาน |
|
||||
| | ✅ Database ปลอดภัย ไม่เกิด Error จาก Injection |
|
||||
|
||||
### AC-SEC-002 — XSS Prevention
|
||||
**Priority:** 🔴 Blocker | **Role:** QA (Security Test)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | ช่อง Input เช่น Subject, Comment |
|
||||
| **When** | ใส่ `<script>alert('XSS')</script>` |
|
||||
| **Then** | ✅ Script ไม่ถูก Execute ใน Browser |
|
||||
| | ✅ แสดงเป็น Plaintext หรือถูก Escaped |
|
||||
|
||||
### AC-SEC-003 — Authorization Boundary (IDOR Protection)
|
||||
**Priority:** 🔴 Blocker | **Role:** QA (Security Test)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | User A รู้ Document ID ของ User B |
|
||||
| **When** | User A เรียก `GET /correspondences/:id` ของ User B โดยตรง |
|
||||
| **Then** | ✅ ได้รับ 403 Forbidden (ไม่ใช่ 404) |
|
||||
| | ✅ ข้อมูลของ User B ไม่ถูกเปิดเผย |
|
||||
|
||||
### AC-SEC-004 — Rate Limiting on Auth Endpoint
|
||||
**Priority:** 🔴 Blocker | **Role:** QA (Security Test)
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | ไม่มี Session อยู่ |
|
||||
| **When** | เรียก `POST /auth/login` เกิน 5 ครั้งใน 1 นาที จาก IP เดียว |
|
||||
| **Then** | ✅ ครั้งที่ 6+ ได้รับ 429 Too Many Requests |
|
||||
| | ✅ Audit Log บันทึก Rate Limit Event |
|
||||
|
||||
### AC-SEC-005 — Security Headers
|
||||
**Priority:** 🟠 Critical | **Role:** QA
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | ระบบทำงานบน HTTPS |
|
||||
| **When** | ตรวจสอบ HTTP Response Headers |
|
||||
| **Then** | ✅ `X-Content-Type-Options: nosniff` |
|
||||
| | ✅ `X-Frame-Options: DENY` |
|
||||
| | ✅ `Strict-Transport-Security` present |
|
||||
| | ✅ `Content-Security-Policy` defined |
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Section 15: Performance Acceptance Criteria
|
||||
|
||||
### AC-PERF-001 — API Response Time
|
||||
**Priority:** 🟠 Critical
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Test Condition** | 50 concurrent users, Normal workload |
|
||||
| **Then** | ✅ P90 Response Time < 200ms สำหรับ CRUD operations |
|
||||
| | ✅ P90 Search Query < 500ms |
|
||||
| | ✅ File Upload 50MB < 30 seconds |
|
||||
|
||||
> **Test Tool:** k6 หรือ Apache JMeter
|
||||
> **Test Script:** `specs/05-Engineering-Guidelines/performance-test-script.js` (TODO: สร้าง)
|
||||
|
||||
### AC-PERF-002 — Concurrent Users
|
||||
**Priority:** 🟠 Critical
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Test Condition** | 100 concurrent active users |
|
||||
| **Then** | ✅ ระบบไม่ crash หรือ Error Rate > 1% |
|
||||
| | ✅ Memory ไม่เกิน 80% ของ Container Limit |
|
||||
| | ✅ CPU ไม่เกิน 80% sustained |
|
||||
|
||||
### AC-PERF-003 — Document Number Concurrent
|
||||
**Priority:** 🔴 Blocker
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Test Condition** | 50 concurrent POST `/document-numbering/reserve` สำหรับ Project/Type เดียวกัน |
|
||||
| **Then** | ✅ เลขเอกสารไม่ซ้ำกันทั้ง 50 Request |
|
||||
| | ✅ ทุก Request สำเร็จ (ไม่มี 5xx Error) |
|
||||
|
||||
---
|
||||
|
||||
## 💾 Section 16: Data Integrity & Recovery
|
||||
|
||||
### AC-DATA-001 — Backup & Restore
|
||||
**Priority:** 🔴 Blocker | **Role:** DevOps
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | Production Database มีข้อมูล 1 วันทำการ |
|
||||
| **When** | ทดสอบ Restore จาก Backup ล่าสุด |
|
||||
| **Then** | ✅ Restore สำเร็จภายใน RTO < 4 ชั่วโมง |
|
||||
| | ✅ ข้อมูลสมบูรณ์ ไม่มี Data Loss เกิน RPO < 1 ชั่วโมง |
|
||||
| | ✅ ระบบทำงานปกติหลัง Restore |
|
||||
|
||||
### AC-DATA-002 — Orphan File Prevention
|
||||
**Priority:** 🟠 Critical | **Role:** ระบบ
|
||||
|
||||
| | Description |
|
||||
|---|---|
|
||||
| **Given** | User อัปโหลดไฟล์ไปยัง Temp แล้ว Cancel Document ก่อน Confirm |
|
||||
| **When** | Cleanup Job ทำงาน |
|
||||
| **Then** | ✅ ไฟล์ใน Temp Storage ถูกลบ |
|
||||
| | ✅ Permanent Storage ไม่มี Orphan Files |
|
||||
|
||||
---
|
||||
|
||||
## ✅ UAT Sign-off Checklist
|
||||
|
||||
### Pre-UAT Conditions
|
||||
- [ ] ระบบ Deploy บน Staging Environment (ใช้ Docker Compose เหมือน Production)
|
||||
- [ ] Seed Data ตาม `lcbp3-v1.8.0-seed-basic.sql` และ `seed-permissions.sql`
|
||||
- [ ] Test Users ทุก Role ถูกสร้าง (Superadmin, Org Admin, Document Control, Editor, Viewer)
|
||||
- [ ] Email + LINE Notify Test Mode เปิดใช้งาน
|
||||
|
||||
### Go-Live Criteria (ต้องผ่านทั้งหมด)
|
||||
|
||||
| # | Criteria | Status |
|
||||
|---|----------|--------|
|
||||
| 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) ผ่าน | ⬜ |
|
||||
| 5 | AC-WF-001 ~ AC-WF-003 (Workflow Engine Core) ผ่าน | ⬜ |
|
||||
| 6 | AC-DN-001 (Concurrent Number) ผ่าน | ⬜ |
|
||||
| 7 | AC-STOR-001 (Two-Phase Storage + ClamAV) ผ่าน | ⬜ |
|
||||
| 8 | AC-SEC-001 ~ AC-SEC-004 (Security) ผ่านทั้งหมด | ⬜ |
|
||||
| 9 | AC-PERF-001 (Response Time) ผ่าน | ⬜ |
|
||||
| 10 | AC-DATA-001 (Backup & Restore DR Test) ผ่าน | ⬜ |
|
||||
| 11 | AC-AUDIT-001 (Audit Log Coverage) ผ่าน | ⬜ |
|
||||
| 12 | ไม่มี Bug Priority P0/P1 ค้างอยู่ | ⬜ |
|
||||
|
||||
### UAT Participant Sign-off
|
||||
|
||||
| Organization | Representative | Signature | Date |
|
||||
|-------------|----------------|-----------|------|
|
||||
| กทท. (Owner) | | | |
|
||||
| สค. (Admin) | | | |
|
||||
| TEAM (Design Consultant) | | | |
|
||||
| คคง. (Supervisor) | | | |
|
||||
| ผรม. (Contractor Rep.) | | | |
|
||||
| NAP (Developer) | Nattanin P. | | |
|
||||
|
||||
---
|
||||
|
||||
## 📝 Document Control
|
||||
|
||||
- **Version:** 1.0.0
|
||||
- **Status:** DRAFT — Pending Stakeholder Sign-off
|
||||
- **Created:** 2026-03-11
|
||||
- **Owner:** Nattanin Peancharoen (Product Owner / System Architect)
|
||||
- **Next Review:** Prior to UAT Start
|
||||
- **Classification:** Internal Use Only
|
||||
|
||||
---
|
||||
|
||||
> [!NOTE]
|
||||
> เอกสารนี้ต้องได้รับการ Sign-off จาก Stakeholder ทุกฝ่ายก่อนเริ่ม UAT
|
||||
> ดู Gap 5 (Stakeholder Sign-off) ใน `po-analysis.md` สำหรับ Process การอนุมัติ
|
||||
@@ -0,0 +1,642 @@
|
||||
# 🛡️ Module Edge Cases & Business Rules — LCBP3-DMS v1.8.0
|
||||
|
||||
---
|
||||
title: 'Edge Cases, Business Rules, and Anti-Bug Specifications'
|
||||
version: 1.0.0
|
||||
status: DRAFT
|
||||
owner: Nattanin Peancharoen (Product Owner / System Architect)
|
||||
last_updated: 2026-03-11
|
||||
related:
|
||||
- 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/03-Data-and-Storage/lcbp3-v1.8.0-schema-02-tables.sql
|
||||
---
|
||||
|
||||
> [!IMPORTANT]
|
||||
> เอกสารนี้ระบุ **Edge Cases ที่ต้อง Implement และ Test อย่างชัดเจน** เพื่อป้องกัน Bug ในระบบ Prod
|
||||
> ทุก Edge Case มี **Expected Behavior** ที่ Developer และ QA ต้องยึดถือ
|
||||
|
||||
---
|
||||
|
||||
## 📐 วิธีอ่าน
|
||||
|
||||
- **EC-[MODULE]-[NNN]** = Edge Case ID
|
||||
- **Severity:** 🔴 Critical | 🟠 High | 🟡 Medium
|
||||
- **Type:** `Data Integrity` | `Security` | `Concurrency` | `UX` | `Business Rule`
|
||||
|
||||
---
|
||||
|
||||
## Module 1: Document Numbering Edge Cases
|
||||
|
||||
### EC-DN-001 — Concurrent Submission (Race Condition)
|
||||
**Severity:** 🔴 Critical | **Type:** Concurrency, Data Integrity
|
||||
|
||||
**Scenario:** User A และ User B กด Submit Correspondence พร้อมกันทุก millisecond สำหรับ Project/Type/Sender/Receiver เดียวกัน
|
||||
|
||||
**Expected Behavior:**
|
||||
- ทั้งสองได้รับเลขเอกสาร **ต่างกัน** (เช่น 0001 และ 0002)
|
||||
- ไม่มีเลข Duplicate ในระบบ
|
||||
- API ทั้งสองตอบ 201 Created สำเร็จ
|
||||
|
||||
**Implementation Rule:**
|
||||
```
|
||||
1. Redis Redlock acquire บน counterKey ก่อน
|
||||
2. ถ้า Lock ไม่ได้ใน 5 วินาที → 503 Service Unavailable (Retry-After: 3s)
|
||||
3. DB SELECT FOR UPDATE อีกชั้น (Defense in Depth)
|
||||
4. Increment counter → COMMIT → Release Lock
|
||||
5. ห้ามใช้ AUTO_INCREMENT ของ DB โดยตรงสำหรับเลขเอกสาร
|
||||
```
|
||||
|
||||
**Test Method:** Load Test 50 concurrent POST `/document-numbering/reserve` → Assert DISTINCT count = 50
|
||||
|
||||
---
|
||||
|
||||
### EC-DN-002 — Yearly Reset Boundary Condition
|
||||
**Severity:** 🟠 High | **Type:** Business Rule, Data Integrity
|
||||
|
||||
**Scenario A:** Document ถูก Submit เวลา 23:59:59 วันที่ 31 ธันวาคม
|
||||
**Scenario B:** Cron Job Reset Counter ทำงานตอนเที่ยงคืน แต่มี Document ในสถานะ RESERVED อยู่
|
||||
|
||||
**Expected Behavior (A):**
|
||||
- ได้รับเลขของปีเก่า (counter ปีเก่า) — เวลา Submit คือที่กำหนด
|
||||
- ถ้า Confirm หลังเที่ยงคืน → เลขยังเป็นของปีเก่า (ใช้เวลา Reserve ไม่ใช่ Confirm)
|
||||
|
||||
**Expected Behavior (B):**
|
||||
- Cron Job ต้อง **Skip** เลขที่อยู่ใน RESERVED state — ไม่ Reset Counter จนกว่า Reservation จะ Expire หรือ Confirmed
|
||||
- ถ้า Reset รันก่อน Expiry: Counter ใหม่เริ่ม 0001 แต่ Reserved เลขยังคงอยู่ (ไม่ถูก Overwrite)
|
||||
|
||||
**Implementation Rule:**
|
||||
```
|
||||
- Cron Job ติด Lock เดียวกับ Reserve Process ก่อน Reset
|
||||
- Reset scope = 'YEAR_2025' → Counter Key ใหม่ = 'YEAR_2026'
|
||||
- ไม่ Delete counter เก่า — แค่ Key ใหม่
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### EC-DN-003 — Cancelled/Voided Number Must Not Reuse
|
||||
**Severity:** 🔴 Critical | **Type:** Business Rule, Data Integrity
|
||||
|
||||
**Scenario:** Document ถูก Submit → ได้เลข 0005 → Admin Cancel Document → User Submit ใหม่
|
||||
|
||||
**Expected Behavior:**
|
||||
- เลขถัดไปต้อง **0006** ไม่ใช่ 0005
|
||||
- เลข 0005 อยู่ใน `document_number_reservations` สถานะ CANCELLED ตลอดไป
|
||||
- ไม่มีการ Reuse เลขที่ถูก Cancel เด็ดขาด
|
||||
|
||||
**Business Rule:** "เลขที่ออกแล้วต้องไปข้างหน้าเท่านั้น — ห้ามถอยหลัง"
|
||||
|
||||
---
|
||||
|
||||
### EC-DN-004 — Reservation TTL Expired Cleanup
|
||||
**Severity:** 🟠 High | **Type:** Data Integrity, UX
|
||||
|
||||
**Scenario:** User Reserve เลข (TTL 5 นาที) แต่ Browser ปิดก่อน Confirm
|
||||
|
||||
**Expected Behavior:**
|
||||
- หลัง 5 นาที → `document_number_reservations.status` เปลี่ยนเป็น EXPIRED (by Cron/TTL)
|
||||
- Counter ไม่ถูก Decrement (เลขนั้นหายไปถาวร — ฟัน-หลอ-เลข เป็นที่ยอมรับ)
|
||||
- ถ้า User กลับมา Confirm Token ที่ Expired → 410 Gone (Token expired)
|
||||
|
||||
**Implementation Rule:**
|
||||
```sql
|
||||
-- Cron ทุก 1 นาที
|
||||
UPDATE document_number_reservations
|
||||
SET status = 'EXPIRED'
|
||||
WHERE status = 'RESERVED' AND expires_at < NOW();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### EC-DN-005 — Idempotency Key Duplicate Submission
|
||||
**Severity:** 🟠 High | **Type:** Concurrency, UX
|
||||
|
||||
**Scenario:** Network ไม่เสถียร → User คลิก Submit 2 ครั้ง → Frontend ส่ง POST 2 ครั้งด้วย Idempotency-Key เดียวกัน
|
||||
|
||||
**Expected Behavior:**
|
||||
- Request แรก → ออกเลขใหม่ → 201 Created
|
||||
- Request ที่สอง (same Idempotency-Key) → **Return เลขเดิม** → 200 OK (ไม่ออกเลขใหม่)
|
||||
- ไม่ว่า Request ที่สองจะมาเร็วแค่ไหน
|
||||
|
||||
**Implementation Rule:** Cache Idempotency-Key ใน Redis (TTL 24h) → ถ้า Key เจอ → Return Cached Response
|
||||
|
||||
---
|
||||
|
||||
## Module 2: Workflow Engine Edge Cases
|
||||
|
||||
### EC-WF-001 — Concurrent Approval (Parallel Steps)
|
||||
**Severity:** 🔴 Critical | **Type:** Concurrency, Business Rule
|
||||
|
||||
**Scenario:** Workflow มี Parallel Approval (Engineer A **และ** Engineer B ต้อง Approve พร้อมกัน)
|
||||
Engineer A Approve พร้อมกับ Engineer B Approve ใน millisecond เดียวกัน
|
||||
|
||||
**Expected Behavior:**
|
||||
- Workflow System บันทึกทั้งสอง Action อย่างถูกต้อง
|
||||
- State เปลี่ยนเป็น "Approved" ก็ต่อเมื่อ **ทุก Parallel Branch** Complete แล้ว
|
||||
- ไม่เกิด State Corruption (เช่น State ถูก Override โดย Action หนึ่ง)
|
||||
|
||||
**Implementation Rule:**
|
||||
```
|
||||
- DB Transaction Isolation: SERIALIZABLE สำหรับ State Transition
|
||||
- Check: all parallel branches completed → ถ้าใช่ → advance to next state
|
||||
- ถ้าไม่ใช่ → บันทึก partial approval เท่านั้น
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### EC-WF-002 — Action on Wrong Workflow State
|
||||
**Severity:** 🔴 Critical | **Type:** Security, Business Rule
|
||||
|
||||
**Scenario A:** Reviewer พยายาม Approve เอกสารที่ถูก Cancel แล้ว
|
||||
**Scenario B:** Reviewer Approve เอกสารที่ Approve ไปแล้ว (Double-click)
|
||||
|
||||
**Expected Behavior (A):**
|
||||
- `GET /correspondences/:id` → status: CANCELLED → ปุ่ม Approve ไม่แสดง (UI)
|
||||
- ถ้าโจมตีตรงๆ ผ่าน API → 422 Unprocessable Entity (Invalid state transition)
|
||||
|
||||
**Expected Behavior (B):**
|
||||
- `workflow_state_transitions` ตรวจสอบ current_state + action ก่อน
|
||||
- ถ้า Action ไม่ Valid สำหรับ State ปัจจุบัน → 409 Conflict (Already processed)
|
||||
- Idempotency: ถ้า User กด Approve ซ้ำด้วย Action เดียวกัน → Return เดิม ไม่ Error
|
||||
|
||||
---
|
||||
|
||||
### EC-WF-003 — Force Proceed on Final State
|
||||
**Severity:** 🟠 High | **Type:** Business Rule, UX
|
||||
|
||||
**Scenario:** Document Control กด "Force Proceed" บนเอกสารที่อยู่ใน APPROVED (Final State) แล้ว
|
||||
|
||||
**Expected Behavior:**
|
||||
- ถ้าไม่มี Next State ใน DSL → ปุ่ม Force Proceed ไม่แสดง (UI)
|
||||
- ถ้าเรียก API ตรงๆ → 422 (No next state available from current state)
|
||||
|
||||
---
|
||||
|
||||
### EC-WF-004 — Workflow Definition Changed During Execution
|
||||
**Severity:** 🟡 Medium | **Type:** Business Rule, Data Integrity
|
||||
|
||||
**Scenario:** Admin แก้ไข Workflow DSL ขณะที่มี Workflow Instance กำลังดำเนินการอยู่
|
||||
|
||||
**Expected Behavior:**
|
||||
- Workflow Instance ที่กำลังเดินอยู่ **ใช้ DSL เวอร์ชันที่สร้าง Instance** (Snapshot at creation)
|
||||
- Instance ใหม่ที่สร้างหลังจากนั้นใช้ DSL เวอร์ชันใหม่
|
||||
- ไม่มีการ Interrupt Instance ที่กำลังเดินอยู่
|
||||
|
||||
**Implementation Rule:**
|
||||
```
|
||||
workflow_instances.workflow_definition_snapshot (JSON) — บันทึก DSL ณ เวลาสร้าง
|
||||
ไม่ Reference workflow_definitions.id โดยตรงสำหรับ Active Instances
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### EC-WF-005 — Deadline Passed — No Action Taken
|
||||
**Severity:** 🟡 Medium | **Type:** Business Rule, UX
|
||||
|
||||
**Scenario:** Deadline ของ Organization ผ่านไปแล้ว แต่ User ยังไม่ Approve
|
||||
|
||||
**Expected Behavior:**
|
||||
- Workflow **ไม่ Auto-advance** (ต้องการ Human Decision เสมอ)
|
||||
- Dashboard แสดง "Overdue" Badge (สีแดง)
|
||||
- Notification Reminder ส่งซ้ำตาม Schedule (ไม่ใช่ตลอดเวลา — Anti-Spam)
|
||||
- Document Control สามารถ Force Proceed ได้ (กรณีฉุกเฉิน)
|
||||
|
||||
---
|
||||
|
||||
## Module 3: File Storage Edge Cases
|
||||
|
||||
### EC-STOR-001 — File Upload During Network Interruption
|
||||
**Severity:** 🟠 High | **Type:** UX, Data Integrity
|
||||
|
||||
**Scenario:** User Upload ไฟล์ 50MB ผ่าน Wi-Fi แล้วเน็ตหลุดระหว่าง Upload
|
||||
|
||||
**Expected Behavior:**
|
||||
- Partial upload ไม่ถูก Save ใน Temp Storage
|
||||
- User เห็น Error: "การอัปโหลดล้มเหลว กรุณาลองใหม่" + ปุ่ม Retry
|
||||
- Draft ข้อมูล Form (ที่ไม่ใช่ไฟล์) ยังอยู่ใน LocalStorage (Auto-saved)
|
||||
- ถ้า Retry → อัปโหลดใหม่ทั้งหมด (ไม่มี Resume Upload ใน MVP)
|
||||
|
||||
---
|
||||
|
||||
### EC-STOR-002 — Virus Detected in Uploaded File
|
||||
**Severity:** 🔴 Critical | **Type:** Security
|
||||
|
||||
**Scenario:** User พยายาม Upload ไฟล์ที่ ClamAV ตรวจพบ Malware
|
||||
|
||||
**Expected Behavior:**
|
||||
- ClamAV Scan ใน Temp Storage → พบ → ลบไฟล์ออกจาก Temp ทันที
|
||||
- API ตอบ 422 Unprocessable Entity: `{ "error": "FILE_VIRUS_DETECTED", "filename": "..." }`
|
||||
- Audit Log บันทึก: `VIRUS_DETECTED` + filename + user_id + ip_address
|
||||
- Security Metric Counter ใน Dashboard เพิ่มขึ้น
|
||||
- ไม่ดำเนินการ Submit Document ต่อ (ไม่ว่าไฟล์อื่นจะผ่านแล้ว)
|
||||
|
||||
---
|
||||
|
||||
### EC-STOR-003 — File Type Mismatch (MIME Sniffing Attack)
|
||||
**Severity:** 🔴 Critical | **Type:** Security
|
||||
|
||||
**Scenario:** Attacker เปลี่ยน Extension ไฟล์ `malware.exe` → `document.pdf` แล้ว Upload
|
||||
|
||||
**Expected Behavior:**
|
||||
- Backend ตรวจ MIME Type จาก **File Content** (ไม่ใช่ Extension)
|
||||
- ถ้า MIME Type ไม่ตรงกับ Whitelist (PDF, DWG, ZIP, DOCX) → 400 Bad Request
|
||||
- ถ้า Extension กับ MIME Type ไม่ตรงกัน → 400 Bad Request: "File type mismatch"
|
||||
- Audit Log บันทึก Security Event
|
||||
|
||||
**Whitelist:**
|
||||
```
|
||||
PDF: application/pdf
|
||||
DWG: application/acad, image/vnd.dwg
|
||||
ZIP: application/zip, application/x-zip-compressed
|
||||
DOCX: application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
XLSX: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### EC-STOR-004 — Orphan File Cleanup (Document Cancelled Before Confirm)
|
||||
**Severity:** 🟠 High | **Type:** Data Integrity, Storage
|
||||
|
||||
**Scenario:** User Reserve Document Number → อัปโหลดไฟล์ไป Temp → Cancel Document → ออกจากหน้า
|
||||
|
||||
**Expected Behavior:**
|
||||
- Temp files ต้องถูกลบออกจาก Storage ภายใน 1 ชั่วโมง (Cleanup Cron)
|
||||
- ไม่มี Orphan Files ใน Temp Storage เกิน TTL
|
||||
- Permanent Storage ไม่มีไฟล์ที่ไม่มี Document Reference
|
||||
|
||||
**Implementation Rule:**
|
||||
```typescript
|
||||
// Cron ทุกชั่วโมง
|
||||
// ลบ Temp files ที่ older than 1 hour และ ไม่ได้ถูก Confirm
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### EC-STOR-005 — Duplicate File Upload Detection
|
||||
**Severity:** 🟡 Medium | **Type:** UX, Storage
|
||||
|
||||
**Scenario:** User อัปโหลดไฟล์เดิมซ้ำสองครั้ง (ลืมว่าอัปโหลดแล้ว)
|
||||
|
||||
**Expected Behavior:**
|
||||
- **ไม่ Block** การ Upload ซ้ำ — เก็บเป็น 2 Attachment แยกกัน
|
||||
- แสดง Warning (ไม่ใช่ Error): "ไฟล์นี้อาจถูกอัปโหลดแล้ว — ชื่อเดียวกัน"
|
||||
- User สามารถลบ Duplicate ออกก่อน Submit
|
||||
|
||||
---
|
||||
|
||||
## Module 4: RFA & Drawing Edge Cases
|
||||
|
||||
### EC-RFA-001 — 1 Shop Drawing Revision = Max 1 RFA Constraint
|
||||
**Severity:** 🔴 Critical | **Type:** Business Rule, Data Integrity
|
||||
|
||||
**Scenario:** Document Control พยายามสร้าง RFA ที่สอง สำหรับ Shop Drawing Revision เดิม
|
||||
|
||||
**Expected Behavior:**
|
||||
- ตรวจสอบ: `rfas WHERE shop_drawing_revision_id = X AND status NOT IN ('REJECTED', 'CANCELLED')`
|
||||
- ถ้ามี Active RFA อยู่แล้ว → 409 Conflict: "Shop Drawing Revision นี้มี RFA อยู่แล้ว"
|
||||
- UI: Disable ปุ่ม "สร้าง RFA" ถ้า Revision มี Active RFA แล้ว
|
||||
|
||||
**Exception:** ถ้า RFA ก่อนหน้าถูก REJECTED หรือ CANCELLED → สร้างใหม่ได้
|
||||
|
||||
---
|
||||
|
||||
### EC-RFA-002 — RFA Revision While Previous Still Pending
|
||||
**Severity:** 🟠 High | **Type:** Business Rule
|
||||
|
||||
**Scenario:** RFA Rev.A ยัง Pending Review อยู่ แต่ Contractor พยายามสร้าง Rev.B
|
||||
|
||||
**Expected Behavior:**
|
||||
- ถ้า Rev.A ยังไม่มีคำตอบสุดท้าย (REJECTED/APPROVED/APPROVED_WITH_COMMENTS) → Block
|
||||
- 409 Conflict: "ต้องรอคำตอบของ Revision ก่อนหน้าก่อน"
|
||||
- ไม่อนุญาตให้มี 2 Active Revision พร้อมกัน
|
||||
|
||||
---
|
||||
|
||||
### EC-RFA-003 — Shop Drawing Uploaded to Wrong Category
|
||||
**Severity:** 🟡 Medium | **Type:** Business Rule, UX
|
||||
|
||||
**Scenario:** User เลือก Discipline = "Structural" แต่ Upload Shop Drawing ที่เป็น Electrical
|
||||
|
||||
**Expected Behavior (MVP):**
|
||||
- ไม่มี Auto-detection (AI Classification เป็น Phase 3)
|
||||
- Validation: Discipline ต้องเลือก (ไม่มี Default)
|
||||
- เตือนผู้ใช้ให้ตรวจสอบก่อน Submit (Review Mode)
|
||||
- Reviewer ที่ Reject สามารถระบุเหตุผล "Wrong Discipline" ได้
|
||||
|
||||
---
|
||||
|
||||
### EC-RFA-004 — Transmittal Contains Mixed-Status RFAs
|
||||
**Severity:** 🟠 High | **Type:** Business Rule
|
||||
|
||||
**Scenario:** Transmittal ถูกสร้างโดยรวม RFA บางฉบับที่ยัง DRAFT และบางฉบับที่ READY
|
||||
|
||||
**Expected Behavior:**
|
||||
- Transmittal Submit ได้เฉพาะเมื่อ **ทุก RFA ใน Transmittal** อยู่ในสถานะ READY (ไม่ใช่ DRAFT)
|
||||
- ถ้ามี DRAFT อยู่ → 422: "RFA [เลข] ยังอยู่ใน Draft กรุณา Submit ก่อน"
|
||||
- UI: แสดง Status ของแต่ละ RFA ใน Transmittal ก่อน Submit
|
||||
|
||||
---
|
||||
|
||||
## Module 5: Authentication & Session Edge Cases
|
||||
|
||||
### EC-AUTH-001 — Token Refresh Race Condition
|
||||
**Severity:** 🔴 Critical | **Type:** Concurrency, Security
|
||||
|
||||
**Scenario:** Browser Tab A และ Tab B ทำ API Call พร้อมกันด้วย Access Token ที่ Expired
|
||||
ทั้งสองตรวจพบ 401 และพยายาม Refresh Token พร้อมกัน
|
||||
|
||||
**Expected Behavior:**
|
||||
- ใช้ **Single Refresh Promise Pattern**: Tab แรกที่ Refresh สำเร็จ → Tab ที่สองใช้ Token ใหม่ (ไม่ Refresh ซ้อน)
|
||||
- ถ้า Tab ที่สอง Refresh ก็ได้ Token ใหม่เหมือนกัน → ถือว่า OK (Refresh Token ยังใช้ได้)
|
||||
- Refresh Token ถูก Rotate ทุกครั้งที่ใช้ (Refresh Token Rotation)
|
||||
|
||||
**Implementation:** Frontend Singleton Refresh Promise ใน Axios Interceptor
|
||||
|
||||
---
|
||||
|
||||
### EC-AUTH-002 — Permission Changed While User is Logged In
|
||||
**Severity:** 🔴 Critical | **Type:** Security, Business Rule
|
||||
|
||||
**Scenario:** Admin เปลี่ยน Role ของ User จาก Document Control → Viewer ขณะที่ User กำลัง Login อยู่
|
||||
|
||||
**Expected Behavior:**
|
||||
- Redis Permission Cache ของ User ถูกล้าง **ทันที** (ไม่รอ TTL)
|
||||
- Access Token เดิมยังใช้ได้จนหมดอายุ (15 นาที) — เป็นที่ยอมรับ
|
||||
- **Request ถัดไปหลัง Token Refresh** → Permission ใหม่มีผล
|
||||
- Maximum Lag: 15 นาที (= Access Token TTL)
|
||||
|
||||
---
|
||||
|
||||
### EC-AUTH-003 — Concurrent Login (Same Account, Multiple Devices)
|
||||
**Severity:** 🟡 Medium | **Type:** Security, Business Rule
|
||||
|
||||
**Scenario:** User Login จาก 2 Device พร้อมกัน (PC และ Tablet)
|
||||
|
||||
**Expected Behavior (MVP):**
|
||||
- อนุญาต (Session ทั้งสองทำงาน Independent)
|
||||
- แต่ละ Device มี Refresh Token แยกกัน
|
||||
- Logout จาก Device หนึ่ง → Revoke เฉพาะ Refresh Token ของ Device นั้น
|
||||
|
||||
**Future Enhancement (Phase 2):**
|
||||
- Option: "Logout จาก Device อื่นทั้งหมด"
|
||||
|
||||
---
|
||||
|
||||
### EC-AUTH-004 — Account Deactivated While Logged In
|
||||
**Severity:** 🔴 Critical | **Type:** Security
|
||||
|
||||
**Scenario:** Admin Deactivate User Account ขณะที่ User กำลัง Login อยู่
|
||||
|
||||
**Expected Behavior:**
|
||||
- Redis: Blacklist User ID (ทุก Token ของ User นั้นถือว่า Invalid ทันที)
|
||||
- Request ถัดไปของ User → 401 Unauthorized: "Account has been deactivated"
|
||||
- User ถูก Redirect ไปหน้า Login พร้อม Message ชัดเจน
|
||||
|
||||
**Implementation:**
|
||||
```typescript
|
||||
// ใน JWT Guard: ตรวจ Redis Blacklist ก่อน Validate Token
|
||||
const isBlacklisted = await redis.get(`user:blacklist:${userId}`);
|
||||
if (isBlacklisted) throw new UnauthorizedException('Account deactivated');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Module 6: Permission & RBAC Edge Cases
|
||||
|
||||
### EC-PERM-001 — Direct Object Reference (IDOR Attack)
|
||||
**Severity:** 🔴 Critical | **Type:** Security
|
||||
|
||||
**Scenario:** User A รู้ ID ของเอกสาร User B (เช่น `/correspondences/12345`) แล้วเรียกตรงๆ
|
||||
|
||||
**Expected Behavior:**
|
||||
- CASL AbilityGuard ตรวจสอบทั้ง Action และ Resource Owner
|
||||
- ถ้าไม่มีสิทธิ์ → **403 Forbidden** (ไม่ใช่ 404 — เพราะ 404 บอกว่ามีอยู่แต่หาไม่เจอ)
|
||||
- **Exception:** ถ้าต้องการซ่อน Existence ของ Document → Return 404
|
||||
- ทุก API ต้องผ่าน Permission Check โดยไม่มีข้อยกเว้น
|
||||
|
||||
---
|
||||
|
||||
### EC-PERM-002 — Super Admin Impersonation Prevention
|
||||
**Severity:** 🔴 Critical | **Type:** Security
|
||||
|
||||
**Scenario:** User พยายาม Forge JWT payload เพิ่ม role: 'SUPERADMIN'
|
||||
|
||||
**Expected Behavior:**
|
||||
- JWT ถูก Sign ด้วย Secret ที่ไม่เปิดเผย → Signature ไม่ตรง → 401 Invalid token
|
||||
- Role ไม่ถูก Read จาก Token โดยตรงสำหรับ Permission Check — ต้อง Verify จาก DB/Redis
|
||||
- JWT payload ใช้แค่ `user_id` → ดึง Permission จาก Redis Cache/DB
|
||||
|
||||
---
|
||||
|
||||
### EC-PERM-003 — Organization Switch Mid-session
|
||||
**Severity:** 🟡 Medium | **Type:** Business Rule, UX
|
||||
|
||||
**Scenario (ถ้ามี):** User เป็นสมาชิกในหลาย Organization (กรณี Consultant ที่ทำงานหลายโครงการ)
|
||||
|
||||
**Expected Behavior:**
|
||||
- User เห็นเฉพาะ Data ขององค์กรที่ Login อยู่ (Active Context)
|
||||
- ถ้าต้องการดูอีก Org → ต้อง "Switch Organization" (Session Context เปลี่ยน)
|
||||
- ไม่มี Cross-org Data Leak แม้ User เป็นสมาชิกทั้งสอง Org
|
||||
|
||||
---
|
||||
|
||||
## Module 7: Correspondence Edge Cases
|
||||
|
||||
### EC-CORR-001 — Cancel Correspondence with Downstream Circulation
|
||||
**Severity:** 🔴 Critical | **Type:** Business Rule, Data Integrity
|
||||
|
||||
**Scenario:** Correspondence ถูก Submit → ผู้รับสร้าง Circulation แล้ว → Originator ขอ Cancel
|
||||
|
||||
**Expected Behavior:**
|
||||
- ต้องแจ้งเตือน Admin ว่า "มี Circulation ที่เปิดอยู่ [X รายการ] สำหรับเอกสารนี้"
|
||||
- ต้องยืนยันก่อน Cancel: "การ Cancel จะส่งผลให้ Circulation ที่เกี่ยวข้องถูกปิดทั้งหมด"
|
||||
- เมื่อ Confirm → Correspondence = CANCELLED + Circulation ที่เกี่ยวข้อง = FORCE_CLOSED
|
||||
- Audit Log บันทึกทั้งหมด (CANCELLED + FORCE_CLOSED + reason + user)
|
||||
|
||||
---
|
||||
|
||||
### EC-CORR-002 — Reply to Cancel Correspondence
|
||||
**Severity:** 🟡 Medium | **Type:** Business Rule
|
||||
|
||||
**Scenario:** Document Control พยายามสร้าง Correspondence เพื่อ Reply ต่อ Correspondence ที่ถูก Cancel
|
||||
|
||||
**Expected Behavior:**
|
||||
- Reply ทำได้ — Reference ถึง CANCELLED เอกสารได้ (เพื่อ acknowledge การยกเลิก)
|
||||
- UI แสดง Warning: "กำลัง Reply ต่อเอกสารที่ถูกยกเลิกแล้ว"
|
||||
- ไม่ Block การ Reply (เป็น Business Decision ไม่ใช่ Technical Constraint)
|
||||
|
||||
---
|
||||
|
||||
### EC-CORR-003 — Correspondence to Self (Same Organization)
|
||||
**Severity:** 🟡 Medium | **Type:** Business Rule
|
||||
|
||||
**Scenario:** User พยายามสร้าง Correspondence ที่ Sender และ Receiver เป็นองค์กรเดียวกัน
|
||||
|
||||
**Expected Behavior:**
|
||||
- External Correspondence (Letter/RFI) → Block: "ไม่สามารถส่งหาตัวเองได้"
|
||||
- Internal Communication → ใช้ Circulation Sheet แทน (ไม่ใช่ Correspondence)
|
||||
- UI Validation + Backend Validation (Double Check)
|
||||
|
||||
---
|
||||
|
||||
## Module 8: Circulation Edge Cases
|
||||
|
||||
### EC-CIRC-001 — Assignee Deactivated Before Completing Task
|
||||
**Severity:** 🟠 High | **Type:** Business Rule, UX
|
||||
|
||||
**Scenario:** User ถูก Deactivate หลังจากถูก Assign ใน Circulation แต่ก่อน Respond
|
||||
|
||||
**Expected Behavior:**
|
||||
- Circulation ยัง Active อยู่ — ไม่หยุดอัตโนมัติ
|
||||
- Document Control เห็น Warning: "Assignee [ชื่อ] ไม่ Active แล้ว"
|
||||
- Document Control สามารถ Re-assign ไปยัง User อื่นได้
|
||||
- Audit Log บันทึก Re-assign Event
|
||||
|
||||
---
|
||||
|
||||
### EC-CIRC-002 — Multi-Assignee: Partial Response
|
||||
**Severity:** 🟡 Medium | **Type:** Business Rule, UX
|
||||
|
||||
**Scenario:** Circulation มี Action Assignees 3 คน — 2 คน Respond แล้ว แต่ 1 คนยังไม่ Respond
|
||||
|
||||
**Expected Behavior (MVP):**
|
||||
- Document Control เห็นสถานะ "2/3 ตอบกลับแล้ว"
|
||||
- Document Control สามารถ Force Close ได้ (พร้อมระบุเหตุผล)
|
||||
- ถ้า Force Close → ทุก Partial Response ถูกบันทึก + หมายเหตุว่า Force Closed
|
||||
|
||||
---
|
||||
|
||||
### EC-CIRC-003 — Circulation Deadline = Today (Edge of Day)
|
||||
**Severity:** 🟡 Medium | **Type:** Business Rule, UX
|
||||
|
||||
**Scenario:** Deadline ถูกกำหนด = "วันนี้" แต่ User ดูตอนบ่ายสอง
|
||||
|
||||
**Expected Behavior:**
|
||||
- ถ้า Deadline = วันที่ X → หมดเขตเมื่อ X เวลา 23:59:59 (ไม่ใช่ 00:00:00)
|
||||
- Reminder: ส่ง Notification เวลา 08:00 ของวัน Deadline
|
||||
- Overdue Badge ขึ้นเมื่อ `NOW() > deadline_date + 1 day` (วันถัดไป 00:00)
|
||||
|
||||
---
|
||||
|
||||
## Module 9: Search & Elasticsearch Edge Cases
|
||||
|
||||
### EC-SRCH-001 — Search Index Lag (Eventual Consistency)
|
||||
**Severity:** 🟡 Medium | **Type:** Data Consistency, UX
|
||||
|
||||
**Scenario:** Document ถูก Submit แล้ว → User ค้นหาทันที แต่ไม่เจอ
|
||||
|
||||
**Expected Behavior:**
|
||||
- Index อาจ Lag 5–30 วินาที (BullMQ Async Job)
|
||||
- UI แสดง "เอกสารอาจใช้เวลาสักครู่ก่อนปรากฏในผลค้นหา"
|
||||
- **ไม่ถือว่า Bug** — เป็น By Design (Eventual Consistency)
|
||||
- User สามารถ Navigate ไปยังเอกสารได้ทันทีผ่าน Notification Link (ไม่ต้องรอ Search)
|
||||
|
||||
---
|
||||
|
||||
### EC-SRCH-002 — Permission-filtered Search Results
|
||||
**Severity:** 🔴 Critical | **Type:** Security
|
||||
|
||||
**Scenario:** Contractor A ค้นหา Keyword ที่มีใน Document ของ Contractor B
|
||||
|
||||
**Expected Behavior:**
|
||||
- Elasticsearch Index ต้องมี `organization_id` / `contract_id` Field
|
||||
- ทุก Search Query ต้อง Filter ด้วย `must: [{ term: { visible_to_org: userOrgId } }]`
|
||||
- Contractor A **ไม่เห็น** Document ของ Contractor B ในผลค้นหา
|
||||
- **ห้าม Filter ที่ Application Layer เท่านั้น** → ต้อง Filter ที่ Query Level
|
||||
|
||||
---
|
||||
|
||||
### EC-SRCH-003 — Special Characters in Search Query
|
||||
**Severity:** 🟡 Medium | **Type:** Security, UX
|
||||
|
||||
**Scenario:** User ค้นหาด้วย `คคง. สค. - 2025` (มี `-`, `.`, ช่องว่าง)
|
||||
|
||||
**Expected Behavior:**
|
||||
- ไม่ Crash — Elasticsearch รองรับ Special Characters
|
||||
- Sanitize Query ก่อนส่ง (กัน Elasticsearch Injection)
|
||||
- ผล Search ยังคง Relevance สูง
|
||||
|
||||
---
|
||||
|
||||
## Module 10: Notifications Edge Cases
|
||||
|
||||
### EC-NOTIF-001 — Notification Flood Prevention
|
||||
**Severity:** 🟠 High | **Type:** UX, Anti-Spam
|
||||
|
||||
**Scenario:** Workflow มีหลาย Step ที่เปลี่ยนเร็ว → ส่ง Notification ทุก State Change → User ได้รับ Email 10 ฉบับในนาทีเดียว
|
||||
|
||||
**Expected Behavior:**
|
||||
- **Notification Debounce/Batch:** รวม Notifications ภายใน 5 นาทีเป็น Summary Email เดียว
|
||||
- ถ้าเปลี่ยน State 5 ครั้งใน 5 นาที → Email เดียว: "เอกสาร X มี 5 การเปลี่ยนแปลง"
|
||||
- In-App Notifications ยังแสดงทุกรายการ (ไม่ Batch)
|
||||
|
||||
---
|
||||
|
||||
### EC-NOTIF-002 — User Unsubscribed from EMAIL but still needs In-App
|
||||
**Severity:** 🟡 Medium | **Type:** UX, Business Rule
|
||||
|
||||
**Scenario:** User ปิด Email Notification แต่ยังต้องการ In-App Notification
|
||||
|
||||
**Expected Behavior:**
|
||||
- Notification Settings: แยก Toggle สำหรับ Email / LINE / In-App
|
||||
- Core Workflow Assignments (ที่ User ต้อง Action) → **ไม่สามารถ Disable** ทุก Channel ได้
|
||||
- ต้องมี In-App อย่างน้อย 1 Channel สำหรับ Action Required Notifications
|
||||
|
||||
---
|
||||
|
||||
## 📊 Edge Case Summary by Module
|
||||
|
||||
| Module | Critical | High | Medium | Total |
|
||||
|--------|----------|------|--------|-------|
|
||||
| Document Numbering | 2 | 2 | 1 | 5 |
|
||||
| Workflow Engine | 2 | 1 | 2 | 5 |
|
||||
| File Storage | 2 | 2 | 1 | 5 |
|
||||
| RFA & Drawing | 1 | 2 | 1 | 4 |
|
||||
| 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** |
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Strategy for Edge Cases
|
||||
|
||||
### สำหรับ Unit Tests (Backend)
|
||||
```typescript
|
||||
// ตัวอย่าง: EC-DN-001 — Concurrent Number Generation
|
||||
describe('DocumentNumberingService - Concurrency', () => {
|
||||
it('should generate unique numbers for concurrent requests', async () => {
|
||||
const promises = Array.from({ length: 50 }, () =>
|
||||
service.reserve({ projectId: 1, typeId: 2, orgId: 3 })
|
||||
);
|
||||
const results = await Promise.all(promises);
|
||||
const numbers = results.map(r => r.documentNumber);
|
||||
const unique = new Set(numbers);
|
||||
expect(unique.size).toBe(50); // ไม่มีซ้ำ
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### สำหรับ Integration Tests
|
||||
- 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
|
||||
|
||||
### สำหรับ 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
|
||||
|
||||
---
|
||||
|
||||
## 📝 Document Control
|
||||
|
||||
- **Version:** 1.0.0 | **Status:** DRAFT
|
||||
- **Created:** 2026-03-11 | **Owner:** Nattanin Peancharoen
|
||||
- **Next Review:** Pre-UAT (T-2 สัปดาห์ก่อน Go-Live)
|
||||
- **Classification:** Internal Use Only — Developer & QA Reference
|
||||
@@ -0,0 +1,627 @@
|
||||
# 🖼️ UI/UX Wireframes & Screen Inventory — LCBP3-DMS v1.8.0
|
||||
|
||||
---
|
||||
title: 'UI/UX Screen Inventory, Navigation Map, and Wireframes'
|
||||
version: 1.0.0
|
||||
status: DRAFT
|
||||
owner: Nattanin Peancharoen (Product Owner)
|
||||
last_updated: 2026-03-11
|
||||
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
|
||||
---
|
||||
|
||||
> [!NOTE]
|
||||
> Wireframes ในเอกสารนี้เป็น **Low-fidelity ASCII/Text Wireframes** เพื่อสื่อสาร Layout และ Component Hierarchy
|
||||
> สำหรับ High-fidelity Design ให้ใช้ Figma หรือ Shadcn/UI Components ตาม ADR-012
|
||||
|
||||
---
|
||||
|
||||
## 1. 🗺️ Navigation Map (Site Map)
|
||||
|
||||
```
|
||||
[🔓 Public]
|
||||
│
|
||||
└── /login → หน้า Login (Anonymous)
|
||||
└── /login/forgot-password → ลืมรหัสผ่าน
|
||||
└── /login/change-password → เปลี่ยนรหัสผ่านครั้งแรก (Force)
|
||||
|
||||
[🔒 Authenticated — App Shell (Sidebar + Navbar)]
|
||||
│
|
||||
├── /dashboard → หน้าหลัก (My Tasks + KPI)
|
||||
│
|
||||
├── /correspondences → รายการ Correspondence
|
||||
│ ├── /correspondences/new → สร้างใหม่
|
||||
│ └── /correspondences/:id → รายละเอียด + Workflow
|
||||
│
|
||||
├── /rfas → รายการ RFA
|
||||
│ ├── /rfas/new → สร้างใหม่
|
||||
│ └── /rfas/:id → รายละเอียด + Workflow
|
||||
│
|
||||
├── /transmittals → รายการ Transmittal
|
||||
│ ├── /transmittals/new → สร้างใหม่ (รวม RFAs)
|
||||
│ └── /transmittals/:id → รายละเอียด
|
||||
│
|
||||
├── /drawings → Drawing Management
|
||||
│ ├── /drawings/contract → Contract Drawings
|
||||
│ │ ├── /drawings/contract/new → Upload ใหม่
|
||||
│ │ └── /drawings/contract/:id → รายละเอียด
|
||||
│ └── /drawings/shop → Shop Drawings
|
||||
│ ├── /drawings/shop/new → Upload ใหม่
|
||||
│ └── /drawings/shop/:id → รายละเอียด + RFA History
|
||||
│
|
||||
├── /circulations → Circulation Sheets (Internal)
|
||||
│ ├── /circulations/new → สร้างใหม่
|
||||
│ └── /circulations/:id → รายละเอียด + Assignees
|
||||
│
|
||||
├── /search → Full-text Search
|
||||
│
|
||||
├── /notifications → รายการ Notifications
|
||||
│
|
||||
├── /profile → ข้อมูลส่วนตัว + ตั้งค่า
|
||||
│
|
||||
[🔒 Admin Routes]
|
||||
│
|
||||
├── /admin/users → จัดการ Users (Org Admin+)
|
||||
│ ├── /admin/users/new → เพิ่ม User
|
||||
│ └── /admin/users/:id/edit → แก้ไข User + Role
|
||||
│
|
||||
├── /admin/organizations → จัดการ Orgs (Superadmin)
|
||||
│ └── /admin/organizations/new
|
||||
│
|
||||
├── /admin/projects → จัดการ Projects (Superadmin)
|
||||
│ └── /admin/projects/:id/contracts
|
||||
│
|
||||
├── /admin/doc-numbering → Document Number Config (Superadmin)
|
||||
│
|
||||
└── /admin/audit-logs → Audit Log Viewer (Superadmin + OrgAdmin)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 🧩 App Shell Layout
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ NAVBAR │
|
||||
│ [🏗️ LCBP3-DMS] [Project: LCBP3 ▼] [🔔 3] [👤 สมชาย ▼] │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────┬──────────────────────────────────────────────────┐
|
||||
│ SIDEBAR │ MAIN CONTENT AREA │
|
||||
│ │ │
|
||||
│ 📊 Dashboard │ │
|
||||
│ 📨 Corres. │ [Page Content Here] │
|
||||
│ 📋 RFA │ │
|
||||
│ 📦 Transmit │ │
|
||||
│ 📐 Drawings │ │
|
||||
│ 📄 Circulat. │ │
|
||||
│ 🔍 Search │ │
|
||||
│ │ │
|
||||
│ ─────────── │ │
|
||||
│ [Admin ▼] │ │
|
||||
│ 👥 Users │ │
|
||||
│ 🏢 Orgs │ │
|
||||
│ ⚙️ Config │ │
|
||||
└──────────────┴──────────────────────────────────────────────────┘
|
||||
|
||||
Mobile: Sidebar → Collapsible Hamburger Drawer (ตาม UI-Rule 5.11)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 📋 Screen Inventory
|
||||
|
||||
| Screen ID | Route | ชื่อหน้า | Primary Role | Priority |
|
||||
|-----------|-------|---------|-------------|---------|
|
||||
| SCR-001 | `/login` | Login | ทุก Role | 🔴 Must |
|
||||
| SCR-002 | `/login/change-password` | Force Password Change | ทุก Role | 🔴 Must |
|
||||
| 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-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-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-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 |
|
||||
| SCR-016 | `/circulations` | Circulation List | Doc Control | 🟠 Should |
|
||||
| SCR-017 | `/circulations/new` | Create Circulation | Doc Control | 🟠 Should |
|
||||
| SCR-018 | `/circulations/:id` | Circulation Detail | ทุก Role | 🟠 Should |
|
||||
| SCR-019 | `/search` | Search Results | ทุก Role | 🟠 Should |
|
||||
| SCR-020 | `/notifications` | Notification Center | ทุก Role | 🟡 Could |
|
||||
| SCR-021 | `/profile` | Profile & Settings | ทุก Role | 🟠 Should |
|
||||
| SCR-022 | `/admin/users` | User Management | Org Admin+ | 🔴 Must |
|
||||
| SCR-023 | `/admin/organizations` | Organization Management | Superadmin | 🔴 Must |
|
||||
| SCR-024 | `/admin/projects` | Project & Contract Mgmt | Superadmin | 🔴 Must |
|
||||
| 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)
|
||||
|
||||
---
|
||||
|
||||
## 4. 🖼️ Wireframes — Key Screens
|
||||
|
||||
### SCR-001: Login Page
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ 🏗️ LCBP3-DMS │
|
||||
│ ท่าเรือแหลมฉบัง เฟส 3 │
|
||||
│ Document Management System │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ ชื่อผู้ใช้ (Username) │ │
|
||||
│ │ [________________________________] │ │
|
||||
│ │ │ │
|
||||
│ │ รหัสผ่าน (Password) │ │
|
||||
│ │ [________________________________] [👁️] │ │
|
||||
│ │ │ │
|
||||
│ │ [ เข้าสู่ระบบ (Login) ] ← Primary │ │
|
||||
│ │ │ │
|
||||
│ │ [ลืมรหัสผ่าน?] │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ❌ Error Banner (แสดงเมื่อ Login ผิด): │
|
||||
│ [⚠️ ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง] │
|
||||
│ │
|
||||
│ v1.8.0 | Internal Use Only │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
|
||||
Component Rules:
|
||||
- Error Toast: แสดงทับ Form (ไม่บอกว่าอันไหนผิด — Security)
|
||||
- Rate Limit: หลัง 5 ครั้ง → ปุ่ม Disabled 60 วินาที + Countdown
|
||||
- Password: Toggle Show/Hide icon
|
||||
- Auto-focus: Username field on load
|
||||
- Enter key: Submit form
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SCR-003: Dashboard
|
||||
|
||||
```
|
||||
┌─ Dashboard ─────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ 📊 ภาพรวม — [สมชาย จาก สค.] วันนี้ 11 มี.ค. 2569 │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ 📨 Corres. │ │ 📋 RFA │ │ ⏰ Overdue │ │ 🔒 Security │ │
|
||||
│ │ │ │ │ │ │ │ │ │
|
||||
│ │ Pending │ │ Pending │ │ Tasks │ │ Files │ │
|
||||
│ │ [12] │ │ [5] │ │ [3] │ │ Scanned │ │
|
||||
│ │ │ │ │ │ │ │ [847] │ │
|
||||
│ │ ← ↑3 จากเมื่อ │ │ ← ↓1 จากเมื่อ │ │ ⚠️ เกินกำหนด │ │ 0 Threats │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
│ │
|
||||
│ ═══ งานของฉัน (My Tasks) ════════════════════════════════════════ │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────────────────┐ │
|
||||
│ │ [Filter: ทั้งหมด ▼] [Status: Active ▼] 🔍 [ค้นหา...] │ │
|
||||
│ ├────────┬──────────────────┬──────────┬──────────┬────────────┤ │
|
||||
│ │ ประเภท │ เลขที่/Subject │ หน้าที่ │ กำหนด │ การดำเนินการ│ │
|
||||
│ ├────────┼──────────────────┼──────────┼──────────┼────────────┤ │
|
||||
│ │ 📄 RFA │ LCBP3-RFA-STR.. │ Approve │⚠️12 มี.ค.│ [ดำเนินการ]│ │
|
||||
│ │ 📨 Cir │ สค.-กทท.-001... │ Review │ 15 มี.ค. │ [ดำเนินการ]│ │
|
||||
│ │ 📨 Cir │ สค.-กทท.-002... │ Info │ 20 มี.ค. │ [ดำเนินการ]│ │
|
||||
│ ├────────┴──────────────────┴──────────┴──────────┴────────────┤ │
|
||||
│ │ แสดง 3 จาก 12 รายการ [ดูทั้งหมด →] │ │
|
||||
│ └──────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Mobile (Card View):
|
||||
┌───────────────────────┐
|
||||
│ 📄 RFA │
|
||||
│ LCBP3-RFA-STR-0042 │
|
||||
│ หน้าที่: Approve │
|
||||
│ ⚠️ กำหนด: 12 มี.ค. │
|
||||
│ [ดำเนินการ →] │
|
||||
└───────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SCR-004: Correspondence List
|
||||
|
||||
```
|
||||
┌─ Correspondence ────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ [+ สร้างใหม่] [📥 รับเข้า (12)] [📤 ส่งออก (8)] [ทั้งหมด (20)] │
|
||||
│ │
|
||||
│ [ Filter: ประเภท ▼ ] [ Filter: สถานะ ▼ ] [ Filter: วันที่ ▼ ] │
|
||||
│ 🔍 [ค้นหาเอกสาร... ] [ล้าง Filter] │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │☐ │ เลขที่เอกสาร │ Subject │ ผู้ส่ง │วันที่│สถานะ │ │
|
||||
│ ├──┼─────────────────────┼────────────┼────────┼──────┼───────┤ │
|
||||
│ │☐ │ LCBP3-สค-กทท-L-001 │ ขอแบบงาน. │ สค. │11มีค│✅ ปิด │ │
|
||||
│ │☐ │ LCBP3-กทท-สค-L-002 │ ตอบรับ... │ กทท. │10มีค│🔄 ดำเนิน│ │
|
||||
│ │☐⚠️│ LCBP3-สค-กทท-L-003 │ ขอข้อมูล.. │ สค. │08มีค│⏰ เกิน │ │
|
||||
│ │ │ ... │ │ │ │ │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ [< 1 2 3 >] แสดง 15/47 รายการ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Status Badges:
|
||||
🟡 Draft | 🔵 Submitted | 🔄 In Review | ✅ Closed | ❌ Cancelled | ⏰ Overdue
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SCR-005: Create Correspondence (Form)
|
||||
|
||||
```
|
||||
┌─ สร้าง Correspondence ─────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ Step 1: ข้อมูลทั่วไป ●─────── Step 2: แนบไฟล์ ○─── Step 3: ตรวจสอบ ○│
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────────┐ │
|
||||
│ │ ประเภทเอกสาร* │ จาก (Originator)* │ │
|
||||
│ │ [Letter ▼] │ [สค. (กำหนดอัตโนมัติ)] │ │
|
||||
│ │ │ │ │
|
||||
│ │ ถึง (To)* │ สำเนา (CC) │ │
|
||||
│ │ [เลือกองค์กร ▼][+ เพิ่ม]│ [เลือกองค์กร ▼][+ เพิ่ม] │ │
|
||||
│ │ Tag: กทท. × │ │ │
|
||||
│ │ │ │ │
|
||||
│ │ Subject* │ │
|
||||
│ │ [_____________________________________________] │ │
|
||||
│ │ ○ ตัวอักษรที่เหลือ: 200 │ │
|
||||
│ │ │ │
|
||||
│ │ เอกสารอ้างอิง (References) │ │
|
||||
│ │ [🔍 ค้นหาเลขที่เอกสาร... ] [+ เพิ่ม] │ │
|
||||
│ │ หมวดหมู่ (Tags) │ │
|
||||
│ │ [🔍 ค้นหา Tag...] [construction] × [rfa] × │ │
|
||||
│ │ │ │
|
||||
│ │ หมายเหตุ (Remark) │ │
|
||||
│ │ [_____________________________________________] │ │
|
||||
│ │ [_____________________________________________] │ │
|
||||
│ └───────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ⚠️ Auto-save: บันทึกล่าสุด 13:28:45 │
|
||||
│ │
|
||||
│ [← ยกเลิก] [บันทึก Draft] [ต่อไป: แนบไฟล์ →] │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SCR-005b: File Attachment Step
|
||||
|
||||
```
|
||||
┌─ สร้าง Correspondence — แนบไฟล์ ───────────────────────────────────┐
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ 📎 ลากและวางไฟล์ที่นี่ หรือ [เลือกไฟล์] │ │
|
||||
│ │ │ │
|
||||
│ │ รองรับ: PDF, DWG, ZIP, DOCX, XLSX (สูงสุด 100MB/ไฟล์) │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ไฟล์ที่แนบ: │
|
||||
│ ┌────────────────────────────────────────────────────────────┐ │
|
||||
│ │ ☑️ เอกสารหลัก │ 📄 drawing-v2.pdf │ 2.3MB │ ✅ Scan OK│[🗑️]│
|
||||
│ │ ☐ เอกสารหลัก │ 📐 detail.dwg │ 1.1MB │ 🔄 Scanning│[🗑️]│
|
||||
│ │ ☐ เอกสารหลัก │ 📦 supporting-docs.zip │ 5.8MB │ ✅ Scan OK│[🗑️]│
|
||||
│ └────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ℹ️ ☑️ = เอกสารหลัก (Main Document) — เลือกได้ 1 ไฟล์ │
|
||||
│ │
|
||||
│ ❌ Error File: │
|
||||
│ ┌────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 🚨 malware-test.pdf │ ❌ VIRUS DETECTED — ไฟล์ถูกปฏิเสธ │ │
|
||||
│ └────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [← ย้อนกลับ] [บันทึก Draft] [ต่อไป: ตรวจสอบ →] │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SCR-006: Correspondence Detail + Workflow
|
||||
|
||||
```
|
||||
┌─ LCBP3-สค.-กทท.-LETTER-0001-68 ────────────────────────────────────┐
|
||||
│ Subject: ขอข้อมูลแบบก่อสร้างเพิ่มเติม │
|
||||
│ ส่งโดย: สค. → ถึง: กทท. วันที่: 11 มี.ค. 2569 │
|
||||
│ Status: 🔄 IN REVIEW │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────────────────┐ │
|
||||
│ │ TAB: [ข้อมูล] [📎 เอกสารแนบ (3)] [🔄 Workflow] [📋 Circulation]│ │
|
||||
│ └──────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ═══ Workflow Diagram ════════════════════════════════════════════ │
|
||||
│ │
|
||||
│ ✅ Submit ──→ 🔄 Review ──→ ○ ปิด │
|
||||
│ (สค.) (กทท.) (สค.) │
|
||||
│ 11 มี.ค. กำลังดำเนินการ รอ │
|
||||
│ [คลิกดู Log] [คลิกดูรายละเอียด] │
|
||||
│ │
|
||||
│ ═══ Action Panel (แสดงเฉพาะ Step ที่ Active) ══════════════════ │
|
||||
│ ┌──────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 📋 งานของคุณ: Review เอกสารนี้และตอบกลับ │ │
|
||||
│ │ │ │
|
||||
│ │ Comment / หมายเหตุ: │ │
|
||||
│ │ [___________________________________________________] │ │
|
||||
│ │ [___________________________________________________] │ │
|
||||
│ │ │ │
|
||||
│ │ [❌ ปฏิเสธ] [✅ รับทราบ] [📩 ตอบกลับ] │ │
|
||||
│ └──────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Admin Only: [⚡ Force Proceed →] [↩️ Revert ←] │
|
||||
└──────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Workflow Step Popup (คลิก Step ที่ผ่านแล้ว):
|
||||
┌─────────────────────────────────┐
|
||||
│ ✅ Submit — 11 มี.ค. 2569 │
|
||||
│ โดย: สมชาย ก. (สค.) │
|
||||
│ เวลา: 09:32 น. │
|
||||
│ IP: 192.168.1.10 │
|
||||
│ Comment: - │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SCR-008: Create RFA (Form)
|
||||
|
||||
```
|
||||
┌─ สร้าง RFA ────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ Step 1: ข้อมูล RFA ●── Step 2: Shop Drawing ○── Step 3: Transmittal ○│
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────────┐ │
|
||||
│ │ ประเภท RFA* │ สาขา (Discipline)* │ │
|
||||
│ │ [Shop Drawing ▼] │ [Structural (STR) ▼] │ │
|
||||
│ │ │ │
|
||||
│ │ ⚠️ เลขที่ RFA (Auto-generated) │ │
|
||||
│ │ Preview: LCBP3-RFA-STR-0043 (จะออกเมื่อ Submit) │ │
|
||||
│ │ │ │
|
||||
│ │ Contract Drawing ที่อ้างอิง │ │
|
||||
│ │ [🔍 ค้นหาแบบคู่สัญญา... ] [+ เลือก] │ │
|
||||
│ │ → CD-STR-001: Foundation Plan × │ │
|
||||
│ │ │ │
|
||||
│ │ หมายเหตุ (Remark) │ │
|
||||
│ │ [____________________________________________] │ │
|
||||
│ └────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [← ยกเลิก] [บันทึก Draft] [ต่อไป: แนบแบบ →] │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SCR-009: RFA Detail + Workflow
|
||||
|
||||
```
|
||||
┌─ LCBP3-RFA-STR-0042 ───────────────────────────────────────────────┐
|
||||
│ ประเภท: Shop Drawing | สาขา: Structural | Revision: A │
|
||||
│ ยื่นโดย: ผรม.1 → ผ่าน Transmittal: LCBP3-TRM-0015 │
|
||||
│ Status: 🔄 UNDER REVIEW (คคง.) │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ TAB: [ข้อมูล] [📎 Shop Drawing] [🔄 Workflow] [📝 Revision] │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ═══ Shop Drawing Viewer ════════════════════════════════════════ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ [ 📄 PDF Viewer — Streaming ] │ │
|
||||
│ │ │ │
|
||||
│ │ ⬅️ หน้า 2/15 ➡️ 🔍 80% [⬇️ ดาวน์โหลด] ← (ถ้ามี)│ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ═══ Action Panel (เฉพาะ Reviewer) ════════════════════════════ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ ผลการพิจารณา: │ │
|
||||
│ │ ○ Approved ● Approved with Comments ○ Rejected │ │
|
||||
│ │ │ │
|
||||
│ │ Comment (บังคับเมื่อ AW/C หรือ Rejected): │ │
|
||||
│ │ [พบข้อผิดพลาดในรายละเอียด Connection Plate ...] │ │
|
||||
│ │ │ │
|
||||
│ │ [ยกเลิก] [✅ ยืนยันผลการพิจารณา]│ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Workflow Diagram สำหรับ RFA:
|
||||
✅ Draft → ✅ Submitted → 🔄 TEAM Review → 🔄 คคง. Review → ○ APPROVED
|
||||
(parallel) (sequential)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SCR-017: Create Circulation Sheet
|
||||
|
||||
```
|
||||
┌─ สร้างใบเวียน (Circulation Sheet) ─────────────────────────────────┐
|
||||
│ อ้างอิง: LCBP3-กทท-สค-LETTER-0012 — ขอข้อมูลงวดงานที่ 3 │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────────┐ │
|
||||
│ │ ผู้รับผิดชอบหลัก (Main — ต้องดำเนินการ)* │ │
|
||||
│ │ [🔍 ค้นหาชื่อผู้ใช้... ] [+ เพิ่ม] │ │
|
||||
│ │ → [👤 สมชาย ก. (หัวหน้า)] × [📅 กำหนด: 15 มี.ค.] │ │
|
||||
│ │ │ │
|
||||
│ │ ผู้ดำเนินการ (Action — ร่วมดำเนินการ) │ │
|
||||
│ │ [🔍 ค้นหาชื่อผู้ใช้... ] [+ เพิ่ม] │ │
|
||||
│ │ → [👤 วิชัย ส. (วิศวกร)] × [📅 กำหนด: 20 มี.ค.] │ │
|
||||
│ │ │ │
|
||||
│ │ รับทราบ (Information — เพื่อทราบเท่านั้น) │ │
|
||||
│ │ [🔍 ค้นหาชื่อผู้ใช้... ] [+ เพิ่ม] │ │
|
||||
│ │ → [👤 มานะ พ. (ผจก.)] × │ │
|
||||
│ │ │ │
|
||||
│ │ หมายเหตุ / คำสั่งการ │ │
|
||||
│ │ [โปรดตรวจสอบและเตรียมข้อมูลงวดงานที่ 3...] │ │
|
||||
│ └────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [← ยกเลิก] [✅ สร้างและส่ง Notify] │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SCR-022: User Management (Admin)
|
||||
|
||||
```
|
||||
┌─ จัดการผู้ใช้งาน ───────────────────────────────────────────────────┐
|
||||
│ องค์กร: สค. (สำนักงานโครงการ) [+ เพิ่ม User ใหม่] │
|
||||
│ │
|
||||
│ 🔍 [ค้นหาชื่อ / อีเมล...] [Role: ทั้งหมด ▼] [สถานะ: Active ▼] │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────────────────┐ │
|
||||
│ │ ชื่อ │ Username │ Role │ Status │ │ │
|
||||
│ ├───────────────────┼─────────────┼────────────────┼────────┼───┤ │
|
||||
│ │ สมชาย กิตติ │ somchai.k │ Document Ctrl │ ✅ │[⚙️]│ │
|
||||
│ │ วิชัย สมศรี │ wichai.s │ Editor │ ✅ │[⚙️]│ │
|
||||
│ │ มานะ พงษ์ดี │ mana.p │ Org Admin │ ✅ │[⚙️]│ │
|
||||
│ │ สมหญิง รักดี │ somying.r │ Viewer │ ⛔ │[⚙️]│ │
|
||||
│ └──────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
User Edit Drawer (Slide in from right):
|
||||
┌──────────────────────────┐
|
||||
│ แก้ไขผู้ใช้งาน │
|
||||
│ ──────────────────── │
|
||||
│ ชื่อ: [สมชาย กิตติ ] │
|
||||
│ Email: [somchai@... ] │
|
||||
│ Role: [Document Ctrl ▼] │
|
||||
│ Status: ✅ Active [Toggle]│
|
||||
│ │
|
||||
│ [รีเซ็ตรหัสผ่าน] │
|
||||
│ [❌ ยกเลิก] [✅ บันทึก] │
|
||||
└──────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SCR-025: Document Number Config (Superadmin)
|
||||
|
||||
```
|
||||
┌─ ตั้งค่าเลขที่เอกสาร ────────────────────────────────────────────────┐
|
||||
│ Project: LCBP3 [+ เพิ่ม Format ใหม่] │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ ประเภท │ Format Template │ Reset │ Actn │ │
|
||||
│ ├─────────────────┼────────────────────────────────┼────────┼──────┤ │
|
||||
│ │ Letter │ {PROJECT}-{ORIG}-{RECP}-L-{SEQ:4}-{YY}│ Yearly│[✏️]│ │
|
||||
│ │ RFI │ {PROJECT}-{ORIG}-{RECP}-I-{SEQ:4}-{YY}│ Yearly│[✏️]│ │
|
||||
│ │ RFA-Shop Dwg │ {PROJECT}-RFA-{DISC}-{SEQ:4} │ Never │[✏️]│ │
|
||||
│ │ Transmittal │ {PROJECT}-{ORIG}-{RECP}-T-{SEQ:4}-{YY}│ Yearly│[✏️]│ │
|
||||
│ └─────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Edit Format Inline: │
|
||||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Template: [{PROJECT}-{ORIG}-{RECP}-L-{SEQ:4}-{YY} ] │ │
|
||||
│ │ Preview: [LCBP3-สค.-กทท.-L-0001-68] │ │
|
||||
│ │ ✅ Format ถูกต้อง │ │
|
||||
│ │ [ยกเลิก] [✅ บันทึก] │ │
|
||||
│ └─────────────────────────────────────────────────────────────────┘ │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 🎨 Design System Reference
|
||||
|
||||
### Color Tokens
|
||||
```css
|
||||
/* Primary — ใช้กับ Action Buttons, Links */
|
||||
--primary: hsl(221, 83%, 53%); /* Blue-600 */
|
||||
--primary-hover: hsl(221, 83%, 45%);
|
||||
|
||||
/* Status Colors */
|
||||
--status-draft: hsl(48, 96%, 53%); /* Yellow */
|
||||
--status-submitted: hsl(217, 91%, 60%); /* Blue */
|
||||
--status-review: hsl(24, 95%, 53%); /* Orange */
|
||||
--status-approved: hsl(142, 71%, 45%); /* Green */
|
||||
--status-rejected: hsl(0, 84%, 60%); /* Red */
|
||||
--status-cancelled: hsl(215, 14%, 55%); /* Gray */
|
||||
--status-overdue: hsl(0, 84%, 60%); /* Red (same as rejected) */
|
||||
|
||||
/* Background */
|
||||
--bg-base: hsl(222, 47%, 11%); /* Dark Navy (dark mode base) */
|
||||
--bg-surface: hsl(222, 47%, 16%); /* Card surface */
|
||||
--bg-muted: hsl(215, 28%, 17%); /* Muted sections */
|
||||
```
|
||||
|
||||
### Typography
|
||||
```css
|
||||
font-family: 'Inter', 'Noto Sans Thai', sans-serif;
|
||||
|
||||
/* Scale */
|
||||
--text-xs: 0.75rem; /* 12px — Badge, Caption */
|
||||
--text-sm: 0.875rem; /* 14px — Table cell, Label */
|
||||
--text-base:1rem; /* 16px — Body */
|
||||
--text-lg: 1.125rem; /* 18px — Subheading */
|
||||
--text-xl: 1.25rem; /* 20px — Page title */
|
||||
--text-2xl: 1.5rem; /* 24px — Dashboard KPI */
|
||||
```
|
||||
|
||||
### Component States
|
||||
| Component | Default | Hover | Active | Disabled | Error |
|
||||
|-----------|---------|-------|--------|----------|-------|
|
||||
| Button Primary | bg-primary | bg-primary-hover | 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 | — | — | — | — |
|
||||
|
||||
---
|
||||
|
||||
## 6. 📱 Responsive Breakpoints
|
||||
|
||||
| Breakpoint | Width | Behavior |
|
||||
|-----------|-------|---------|
|
||||
| `sm` | < 640px | Mobile: Sidebar → Drawer, Table → Cards |
|
||||
| `md` | 640-1024px | Tablet: Collapsed Sidebar |
|
||||
| `lg` | > 1024px | Desktop: Full Sidebar |
|
||||
|
||||
**Mobile-specific Rules (UI-Rule 5.11):**
|
||||
- ตาราง → Card View อัตโนมัติ
|
||||
- Sidebar → Collapsible Hamburger Drawer
|
||||
- Action Panel → Bottom Sheet แทน Inline Panel
|
||||
|
||||
---
|
||||
|
||||
## 7. ⚡ Interaction Patterns
|
||||
|
||||
### Optimistic Updates (UI-Rule 5.10)
|
||||
```
|
||||
User กด "Approve" → UI เปลี่ยนสถานะทันที (ไม่รอ API)
|
||||
↓
|
||||
API ตอบกลับ Success → ยืนยัน UI ที่เปลี่ยนแล้ว
|
||||
↓ (ถ้า API ล้มเหลว)
|
||||
Rollback UI → แสดง Toast Error: "เกิดข้อผิดพลาด กรุณาลองใหม่"
|
||||
```
|
||||
|
||||
### Auto-save Draft (UI-Rule 5.12)
|
||||
```
|
||||
User พิมพ์ใน Form → debounce 2 วินาที → บันทึกลง localStorage
|
||||
ปิด Browser → เปิดใหม่ → แสดง Banner: "พบ Draft ที่บันทึกไว้ [กู้คืน] [ทิ้ง]"
|
||||
```
|
||||
|
||||
### File Upload Progress
|
||||
```
|
||||
เลือกไฟล์ → แสดง Progress Bar → ClamAV Scan → ✅/❌
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Document Control
|
||||
|
||||
- **Version:** 1.0.0 | **Status:** DRAFT
|
||||
- **Created:** 2026-03-11 | **Owner:** Nattanin Peancharoen
|
||||
- **Next Step:** สร้าง High-fidelity Mockup ใน Figma ตามโครงสร้างนี้
|
||||
- **Figma Link:** [TBD — สร้างใน Figma Community หรือ Self-hosted Penpot]
|
||||
- **Classification:** Internal Use Only
|
||||
@@ -19,6 +19,9 @@ This directory contains the functional and non-functional requirements for the L
|
||||
1. [Objectives & Goals](./01-01-objectives.md) - Project objectives and success criteria
|
||||
2. [System Architecture & Technology](../02-Architecture/README.md) - High-level architecture requirements
|
||||
3. [Functional Requirements](./01-02-modules/01-02-00-index.md) - Detailed feature specifications
|
||||
4. **[📖 User Stories](./01-04-user-stories.md)** - 27 User Stories (8 Epics, MoSCoW priority, AC links)
|
||||
5. **[🛡️ Edge Cases & Business Rules](./01-06-edge-cases-and-rules.md)** - 37 Edge Cases ป้องกัน Bug
|
||||
6. **[🖼️ UI/UX Wireframes](./01-07-ui-wireframes.md)** - 26 Screens, Navigation Map, Design System
|
||||
|
||||
### Functional Areas
|
||||
|
||||
@@ -55,10 +58,12 @@ This directory contains the functional and non-functional requirements for the L
|
||||
|
||||
### Cross-Cutting Concerns
|
||||
|
||||
4. [Access Control & RBAC](./01-01-business-rules/01-01-01-rbac-matrix.md) - 4-level hierarchical RBAC
|
||||
5. [UI/UX Requirements](./01-01-business-rules/01-01-03-ui-ux-rules.md) - User interface specifications
|
||||
6. [Non-Functional Requirements](./01-01-business-rules/01-01-04-non-functional-rules.md) - Performance, security, scalability
|
||||
7. [Testing Requirements](./01-01-business-rules/01-01-05-testing-rules.md) - Test strategy and coverage
|
||||
4. [Access Control & RBAC](./01-01-business-rules/01-02-01-rbac-matrix.md) - 4-level hierarchical RBAC
|
||||
5. [UI/UX Requirements](./01-02-business-rules/01-02-03-ui-ux-rules.md) - User interface specifications
|
||||
6. [Non-Functional Requirements](./01-02-business-rules/01-02-04-non-functional-rules.md) - Performance, security, scalability
|
||||
7. [Testing Requirements](./01-02-business-rules/01-02-05-testing-rules.md) - Test strategy and coverage
|
||||
8. **[✅ Acceptance Criteria (UAT)](./01-05-acceptance-criteria.md)** - MVP Go-Live criteria, UAT Scenarios, Sign-off checklist
|
||||
9. **[🎓 Training Plan](../00-Overview/00-06-training-plan.md)** - Training Curriculum, Change Management (see also `00-Overview/`)
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user