# 3.2 การจัดการเอกสารโต้ตอบ (Correspondence Management)

---

title: 'Functional Requirements: Correspondence Management'
version: 1.8.3
status: implemented
owner: Nattanin Peancharoen
last_updated: 2026-03-31
related:

- specs/01-requirements/01-01-objectives.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
- specs/01-requirements/01-03-modules/01-03-06-unified-workflow.md
- specs/01-requirements/01-03-modules/01-03-08-circulation-sheet.md
- specs/01-requirements/01-06-edge-cases-and-rules.md (EC-CORR-001 ถึง EC-CORR-003)
- specs/03-Data-and-Storage/03-01-data-dictionary.md
- specs/01-requirements/01-02-business-rules/01-02-01-rbac-matrix.md

---

## 3.2.1. วัตถุประสงค์

เอกสารโต้ตอบ (Correspondence) คือ **โครงสร้างข้อมูลหลัก (Parent)** ของเอกสารทุกประเภทในระบบ — ทั้ง RFA, RFI, Transmittal, Letter ฯลฯ เป็นการสื่อสารระหว่างองค์กร-องค์กร ภายในโครงการ (Project) รองรับผู้รับหลัก (TO) และผู้รับสำเนา (CC) ได้หลายองค์กร

---

## 3.2.2. โครงสร้างข้อมูล (Database Tables)

| Table | บทบาท |
|---|---|
| `correspondences` | ข้อมูล Master: เลขเอกสาร, type, project, originator — ไม่เปลี่ยนตาม revision |
| `correspondence_revisions` | ประวัติแต่ละ Revision: subject, body, status, due_date |
| `correspondence_recipients` | ผู้รับ TO/CC (M:N กับ organizations) |
| `correspondence_references` | การอ้างอิงข้ามเอกสาร (M:N) |
| `correspondence_tags` | Tags ที่ติดกับเอกสาร (M:N) |
| `correspondence_revision_attachments` | ไฟล์แนบต่อ Revision (M:N กับ attachments) |
| `correspondence_types` | Master: ประเภทเอกสาร (Global) |
| `correspondence_status` | Master: สถานะเอกสาร (Global) |

**ข้อสำคัญ:** `correspondence_number` ต้อง UNIQUE ภายใน Project เดียวกัน (`uq_corr_no_per_project`)

---

## 3.2.3. ประเภทเอกสาร (correspondence_types)

ประเภทเป็น Global Master — จัดการโดย Superadmin เท่านั้น:

| type_code | ชื่อ | มี Extension Table |
|---|---|---|
| `RFA` | Request for Approval | ✅ `rfas` + `rfa_revisions` |
| `RFI` | Request for Information | ❌ (ใช้ `details` JSON) |
| `TRANSMITTAL` | Transmittal | ❌ (ใช้ `details` JSON) |
| `EMAIL` | Email | ❌ |
| `INSTRUCTION` | Instruction | ❌ |
| `LETTER` | Letter | ❌ |
| `MEMO` | Memorandum | ❌ |
| `MOM` | Minutes of Meeting | ❌ |
| `NOTICE` | Notice | ❌ |
| `OTHER` | Other | ❌ |

ไฟล์แนบรองรับ **PDF, ZIP**

---

## 3.2.4. Fields ที่ต้องกรอกเมื่อสร้าง Correspondence

| Field | Required | หมายเหตุ |
|---|---|---|
| Project | ✅ | UUID |
| Correspondence Type | ✅ | INT id (Global) |
| Subject | ✅ | ขั้นต่ำ 5 ตัวอักษร — เก็บใน `correspondence_revisions` |
| To Organization | ✅ | UUID — `recipient_type = 'TO'` (≥ 1) |
| CC Organizations | ❌ | UUID[] — `recipient_type = 'CC'` |
| Discipline | ❌ | INT — กรองตาม Contract |
| Body | ❌ | เนื้อหา — เก็บใน `correspondence_revisions` |
| Description | ❌ | คำอธิบาย Revision |
| Remarks | ❌ | หมายเหตุ |
| Document Date | ❌ | วันที่ในเอกสาร |
| Due Date | ❌ | กำหนดส่งคืน |
| Tags | ❌ | UUID[] — จัดกลุ่มเพื่อค้นหาขั้นสูง |
| References | ❌ | UUID[] — อ้างอิงเอกสารฉบับก่อนหน้า |
| Attachments | ❌ | PDF/ZIP — ผ่าน ClamAV scan |
| Is Internal | ❌ | `is_internal_communication = 1` → ใช้ Circulation แทน |

### Document Number Preview

ระบบแสดง Preview เลขเอกสารแบบ Real-time ก่อน Submit เมื่อกรอกครบ: Project + Type + Discipline + To Organization โดยเรียก `POST /api/correspondences/preview-number`

### Frontend Routing & Filtering (v1.8.3)

- รายการเอกสารใช้หน้าเดียวที่ `/correspondences`
- กรองประเภทผ่าน query string `?type=<TYPE_CODE>` เช่น `/correspondences?type=RFA`
- เส้นทาง list เดิมของ RFA (`/rfas` และ `/rfa`) redirect มาหน้าเดียวข้างต้น
- หน้า RFA เฉพาะทาง `/rfas/new`, `/rfas/[uuid]`, `/rfas/[uuid]/edit` ยังแยกจาก Correspondence เพื่อรองรับ extension logic

### UX Flow Diagram (v1.8.3)

- หน้า `/correspondences` มีปุ่ม `UX Flow` เพื่อแสดง lifecycle ของ Correspondence
- เนื้อหาครอบคลุม Master-Revision pattern, two-phase attachment, และ RFA extension path
- เอกสารอ้างอิง implementation อยู่ที่ `specs/01-requirements/01-03-modules/01-03-02a-correspondence-rfa-unified-ux-flow.md`

---

## 3.2.5. การสร้างและสิทธิ์ (RBAC)

| การกระทำ | Role ที่อนุญาต | หมายเหตุ |
|---|---|---|
| สร้าง Correspondence (Draft) | Document Control, Org Admin, Superadmin | ภายในองค์กรตัวเอง |
| Submit Correspondence | Document Control, Org Admin, Superadmin | เปลี่ยนสถานะ DRAFT → SUB* |
| แก้ไข/ถอนกลับ/ยกเลิก หลัง Submit | **Org Admin ขึ้นไปเท่านั้น** พร้อมระบุเหตุผล | — |
| ดู Correspondence ที่ Draft | เฉพาะคนในองค์กรเดียวกัน | องค์กรอื่นมองไม่เห็น |
| ดู Correspondence ที่ Submitted แล้ว | ทุกคนที่มีสิทธิ์ใน Project | รวม TO และ CC org |
| จัดการ Correspondence Types (Master) | Superadmin | Global |

---

## 3.2.6. Status Codes (correspondence_status)

สถานะแบ่งตามหมวดและ Actor:

| หมวด | status_code | ชื่อ |
|---|---|---|
| **Draft** | `DRAFT` | Draft — มองเห็นเฉพาะ Originator Org |
| **Submitted** | `SUBOWN` | Submitted to Owner |
| | `SUBDSN` | Submitted to Designer |
| | `SUBCSC` | Submitted to CSC |
| | `SUBCON` | Submitted to Contractor |
| | `SUBOTH` | Submitted to Others |
| **Reply** | `REPOWN` | Reply by Owner |
| | `REPDSN` | Reply by Designer |
| | `REPCSC` | Reply by CSC |
| | `REPCON` | Reply by Contractor |
| | `REPOTH` | Reply by Others |
| **Resubmitted** | `RSBOWN` | Resubmitted by Owner |
| | `RSBDSN` | Resubmitted by Designer |
| | `RSBCSC` | Resubmitted by CSC |
| | `RSBCON` | Resubmitted by Contractor |
| **Closed** | `CLBOWN` | Closed by Owner |
| | `CLBDSN` | Closed by Designer |
| | `CLBCSC` | Closed by CSC |
| | `CLBCON` | Closed by Contractor |
| **Canceled** | `CCBOWN` | Canceled by Owner |
| | `CCBDSN` | Canceled by Designer |
| | `CCBCSC` | Canceled by CSC |
| | `CCBCON` | Canceled by Contractor |

---

## 3.2.7. การอ้างอิงและ Tags

- **References** (`correspondence_references`): M:N — เอกสารหนึ่งอ้างถึงได้หลายฉบับ ทิศทางเดียว (src → tgt)
- **Tags** (`correspondence_tags` + `tags`): M:N — Tag ผูกกับ Project หรือ Global (project_id = NULL)
- ทั้งสองอย่างใช้ค้นหาขั้นสูงใน Elasticsearch Index

---

## 3.2.8. Revision Model

- 1 Correspondence Master → หลาย Revision (1:N)
- `is_current = TRUE` มีได้เพียง 1 แถวต่อ correspondence (UNIQUE constraint)
- `revision_number`: 0-based integer สำหรับ sorting
- `revision_label`: กำหนดตามประเภทเอกสารดังนี้:
  | Type | Initial Label | ลำดับถัดไป | Format |
  |------|--------------|------------|--------|
  | **RFA, RFI** | `A` | B, C, D... | Alphabet |
  | **LETTER, MEMO, TRANSMITTAL, EMAIL, INSTRUCTION, NOTICE, MOM, OTHER** | `null` | 1, 2, 3... | Numeric |

**หมายเหตุ:** Shop Drawing และ As-Built Drawing ใช้ revision label แยกตามกฎของ Drawing Module (numeric '0', '1', '2'... หรือ user กำหนดเอง)

---

## 3.2.9. Workflow (Unified Workflow)

Correspondence ใช้ Unified Workflow Engine — ดูรายละเอียดที่ `01-03-06-unified-workflow.md`

เมื่อ Correspondence ถูก Submit → ผู้รับ (TO/CC) สามารถสร้าง **Circulation Sheet** เพื่อมอบหมายงานภายในองค์กร (ดู `01-03-08-circulation-sheet.md`)

---

## 3.2.10. Business Rules และ Edge Cases

| รหัส | กฎ | Severity |
|---|---|---|
| **EC-CORR-001** | Cancel Correspondence ที่มี Circulation เปิดอยู่ → ต้องยืนยันก่อน + Force Close Circulation ทั้งหมด + Audit Log | 🔴 Critical |
| **EC-CORR-002** | Reply ต่อ Correspondence ที่ถูก Cancel → ทำได้แต่ UI ต้องแสดง Warning | 🟡 Medium |
| **EC-CORR-003** | Originator และ Recipient เป็นองค์กรเดียวกัน → Block (ใช้ Circulation แทน) | 🟡 Medium |

ดูรายละเอียดครบที่ `01-06-edge-cases-and-rules.md` หมวด "Module 7: Correspondence Edge Cases"

---

## 3.2.11. Implementation Status (v1.8.2)

| Feature | Status | หมายเหตุ |
|---|---|---|
| Create/Update/List/Detail Correspondence | ✅ Done | Phase 1 |
| File Attachments (two-phase upload) | ✅ Done | Phase 2 |
| Recipients (TO/CC), Submit Workflow | ✅ Done | Phase 3 |
| Elasticsearch Indexing | ✅ Done | Phase 4 |
| Cancel + In-App Notifications (cancel/submit) | ✅ Done | Phase 4 |
| Reference Selector (outgoing/incoming) | ✅ Done | Phase 5 |
| Tag Manager (assign/remove tags) | ✅ Done | Phase 5–6 |
| Search `/search` — status filter + pagination | ✅ Done | Phase 6.1 |
| Circulation Status Card in detail sidebar | ✅ Done | Phase 6.2 |
| Revision History UI (timeline) | ✅ Done | Phase 6.3 |
| Due Date Reminder (`@Cron` daily at 08:00) | ✅ Done | Phase 6.4 |
| Email notification via Nodemailer/BullMQ | ✅ Done | Phase 7.1 — type `'EMAIL'` → NotificationProcessor sends Nodemailer |
| Unit tests (service layer ≥ 80%) | ✅ Done | Phase 7.2 — 8 backend + 5 frontend tests |
| Bulk operations (bulk cancel/export) | ✅ Done | Phase 7.3 — `POST /bulk-cancel`, `GET /export-csv`, CSV button |
