Prepare to version 1.5 use spec-kit

This commit is contained in:
admin
2025-11-30 13:58:46 +07:00
parent c302c5f9b1
commit ce795b26e2
169 changed files with 34584 additions and 26464 deletions

377
infrastructure/backup/1.bak Normal file
View File

@@ -0,0 +1,377 @@
ผมได้ตรวจสอบไฟล์ `FullStackJS_Guidelines01.md` และ `01_lcbp3_v1_1_0.sql` ของคุณแล้ว และได้อัปเดตไฟล์ Guidelines (Markdown) ให้สอดคล้องกับโครงสร้างฐานข้อมูล (SQL) ที่คุณกำหนดไว้อย่างสมบูรณ์ครับ
การเปลี่ยนแปลงที่สำคัญคือ:
1. **การจัดการ UI (UI Conflict):** แก้ไขความขัดแย้งในไฟล์เดิมที่ระบุทั้ง **Tailwind/Shadcn** และ **Bootstrap** ผมได้รวมศูนย์การพัฒนา UI ไปที่ **Tailwind/Shadcn** ตามที่ระบุไว้ในโปรไฟล์นักพัฒนา (Frontend Developer Profile) และลบส่วนของ Bootstrap ที่ซ้ำซ้อนออกไป
2. **DMS-Specific Conventions:** อัปเดตส่วนนี้ทั้งหมดเพื่อให้ตรงกับสคีม SQL ของคุณ
* เปลี่ยนชื่อโปรเจกต์อ้างอิงเป็น **LCBP3-DMS**
* ปรับปรุงแผนผัง **Domain Modules** ให้สะท้อนโครงสร้างจริง (เช่น `correspondences` เป็นศูนย์กลาง, เพิ่ม `circulations`)
* อัปเดตตาราง **AuditLog** ให้ตรงกับฟิลด์ใน SQL (เช่น เพิ่ม `entity_type`, `details_json`, `ip_address`)
* อัปเดตตัวอย่าง **RBAC Permissions** ให้ตรงกับสิทธิ์ที่มีในตาราง `permissions` ของคุณ
* ชี้แจง
เรื่อง **File Handling** ว่าตาราง `attachments` จะเชื่อมโยงผ่าน `correspondence_id`
* อัปเดตส่วน **Reporting** เพื่ออ้างอิงถึง `VIEWS` (เช่น `v_current_rfas`) ที่คุณได้สร้างไว้ใน SQL
* ย้ายส่วน **"Recommended Enhancements"** (เช่น soft delete, indexes) ที่มีอยู่แล้วใน SQL ไปยังส่วนใหม่ชื่อ **"Implemented Standards"** เพื่อสะท้อนว่างานส่วนนี้เสร็จแล้ว
นี่คือไฟล์ `FullStackJS_Guidelines01.md` ฉบับที่อัปเดตแล้วครับ:
-----
# FullStackJS Development Guidelines
## 🧠 General Philosophy
Unified best practices for **NestJS Backend**, **NextJS Frontend**, and **Tailwind-based UI/UX** development in TypeScript environments.
Focus on **clarity**, **maintainability**, **consistency**, and **accessibility** across the entire stack.
-----
## ⚙️ TypeScript General Guidelines
### Basic Principles
- Use **English** for all code and documentation.
- Explicitly type all variables, parameters, and return values.
- Avoid `any`; create custom types or interfaces.
- Use **JSDoc** for public classes and methods.
- Export only **one main symbol** per file.
- Avoid blank lines within functions.
### Naming Conventions
| Entity | Convention | Example |
|:--|:--|:--|
| Classes | PascalCase | `UserService` |
| Variables & Functions | camelCase | `getUserInfo` |
| Files & Folders | kebab-case | `user-service.ts` |
| Environment Variables | UPPERCASE | `DATABASE_URL` |
| Booleans | Verb + Noun | `isActive`, `canDelete`, `hasPermission` |
Use full words — no abbreviations — except for standard ones (`API`, `URL`, `req`, `res`, `err`, `ctx`).
-----
## 🧩 Functions
- Write short, single-purpose functions (\<20 lines).
- Use **early returns** to reduce nesting.
- Use **map**, **filter**, **reduce** instead of loops when suitable.
- Prefer **arrow functions** for short logic, **named functions** otherwise.
- Use **default parameters** over null checks.
- Group multiple parameters into a single object (RO-RO pattern).
- Return typed objects, not primitives.
- Maintain a single abstraction level per function.
-----
## 🧱 Data Handling
- Encapsulate data in composite types.
- Use **immutability** with `readonly` and `as const`.
- Perform validations in classes or DTOs, not within business functions.
- Always validate data using typed DTOs.
-----
## 🧰 Classes
- Follow **SOLID** principles.
- Prefer **composition over inheritance**.
- Define **interfaces** for contracts.
- Keep classes focused and small (\<200 lines, \<10 methods, \<10 properties).
-----
## 🚨 Error Handling
- Use exceptions for unexpected errors.
- Catch only to fix or add context; otherwise, use global error handlers.
- Always provide meaningful error messages.
-----
## 🧪 Testing (General)
- Use the **ArrangeActAssert** pattern.
- Use descriptive test variable names (`inputData`, `expectedOutput`).
- Write **unit tests** for all public methods.
- Mock external dependencies.
- Add **acceptance tests** per module using GivenWhenThen.
-----
# 🏗️ Backend (NestJS)
### Principles
- **Modular architecture**:
- One module per domain.
- Controller → Service → Repository (Model) structure.
- DTOs validated with **class-validator**.
- Use **MikroORM** (or TypeORM/Prisma) for persistence, aligning with the MariaDB schema.
- Encapsulate reusable code in a **common module** (`@app/common`):
- Configs, decorators, DTOs, guards, interceptors, notifications, shared services, types, validators.
### Core Functionalities
- Global **filters** for exception handling.
- **Middlewares** for request handling.
- **Guards** for permissions and RBAC.
- **Interceptors** for response transformation and logging.
### Testing
- Use **Jest** for testing.
- Test each controller and service.
- Add `admin/test` endpoint as a smoke test.
-----
# 🖥️ Frontend (NextJS / React / UI)
### Developer Profile
Senior-level TypeScript + React/NextJS engineer.
Expert in **TailwindCSS**, **Shadcn/UI**, and **Radix** for UI development.
### Code Implementation Guidelines
- Use **early returns** for clarity.
- Always style with **TailwindCSS** classes.
- Prefer `class:` conditional syntax (or `clsx` utility) over ternary operators in class strings.
- Use **const arrow functions** for components and handlers.
- Event handlers start with `handle...` (e.g., `handleClick`, `handleSubmit`).
- Include accessibility attributes:
`tabIndex="0"`, `aria-label`, `onKeyDown`, etc.
- Ensure all code is **complete**, **tested**, and **DRY**.
- Always import required modules explicitly.
### UI/UX with React
- Use **semantic HTML**.
- Apply **responsive Tailwind** classes (`sm:`, `md:`, `lg:`).
- Maintain visual hierarchy with typography and spacing.
- Use **Shadcn** components (Button, Input, Card, etc.) for consistent UI.
- Keep components small and focused.
- Use utility classes for quick styling (spacing, colors, text, etc.).
- Ensure **ARIA compliance** and semantic markup.
### Form Validation & Errors
- Use client-side libraries like `zod` and `react-hook-form`.
- Show errors with **alert components** or inline messages.
- Include labels, placeholders, and feedback messages.
-----
# 🔗 Full Stack Integration Guidelines
| Aspect | Backend (NestJS) | Frontend (NextJS) | UI Layer (Tailwind/Shadcn) |
|:--|:--|:--|:--|
| API | REST / GraphQL Controllers | API hooks via fetch/axios/SWR | Components consuming data |
| Validation | `class-validator` DTOs | `zod` / `react-hook-form` | Shadcn form/input states |
| Auth | Guards, JWT | NextAuth / cookies | Auth UI states (loading, signed in) |
| Errors | Global filters | Toasts / modals | Alerts / feedback text |
| Testing | Jest (unit/e2e) | Vitest / Playwright | Visual regression |
| Styles | Scoped modules (if needed) | Tailwind / Shadcn | Tailwind utilities |
| Accessibility | Guards + filters | ARIA attributes | Semantic HTML |
-----
# 🗂️ DMS-Specific Conventions (LCBP3-DMS)
This section extends the general FullStackJS guidelines for the **LCBP3-DMS** project, focusing on document approval workflows (Correspondence, RFA, Drawing, Contract, Transmittal, Circulation).
## 🧱 Backend Domain Modules
Use a modular domain structure reflecting the SQL schema. `correspondences` should act as the central hub.
```
src/
├─ modules/
│ ├─ correspondences/ (Core: Master documents, Revisions, Attachments)
│ ├─ rfas/ (RFA logic, Revisions, Workflows, Items)
│ ├─ drawings/ (ShopDrawings, ContractDrawings, Categories)
│ ├─ circulations/ (Internal circulation, Templates, Assignees)
│ ├─ transmittals/ (Transmittal logic, Items)
│ ├─ projects-contracts/ (Projects, Contracts, Organizations, Parties)
│ ├─ users-auth/ (Users, Roles, Permissions, Auth)
│ ├─ audit-log/
│ └─ common/
```
### Naming Convention
| Entity | Example (from SQL) |
|:--|:--|
| Table | `correspondences`, `rfa_revisions`, `contract_parties` |
| Column | `correspondence_id`, `created_by`, `is_current` |
| DTO | `CreateRfaDto`, `UpdateCorrespondenceDto` |
| Controller | `rfas.controller.ts` |
| Service | `correspondences.service.ts` |
-----
## 🧩 RBAC & Permission Control
Use decorators to enforce access rights, referencing permissions from the `permissions` table.
```ts
@RequirePermission('rfas.respond') // Must match a 'permission_code'
@Put(':id')
updateRFA(@Param('id') id: string) {
return this.rfaService.update(id);
}
```
### Roles
- **SUPER\_ADMIN**: Full system access (from `roles` table).
- **ADMIN**: Organization-level access.
- **EDITOR**: Module-specific write access.
- **VIEWER**: Read-only access.
### Example Permissions (from `permissions` table)
- `rfas.view`, `rfas.create`, `rfas.respond`, `rfas.delete`
- `drawings.view`, `drawings.upload`, `drawings.delete`
- `corr.view`, `corr.manage`
- `transmittals.manage`
- `cirs.manage`
- `project_parties.manage`
Seed mapping between roles and permissions via seeder scripts (as seen in SQL file).
-----
## 🧾 AuditLog Standard
Log all CRUD and mapping operations to the `audit_logs` table.
| Field | Type (from SQL) | Description |
|:--|:--|:--|
| `audit_id` | `BIGINT` | Primary Key |
| `user_id` | `INT` | User performing the action (FK -\> users) |
| `action` | `VARCHAR(100)` | `rfa.create`, `correspondence.update`, `login.success` |
| `entity_type`| `VARCHAR(50)` | Table/module name, e.g., 'rfa', 'correspondence' |
| `entity_id` | `VARCHAR(50)` | Primary ID of the affected record |
| `details_json`| `JSON` | Contextual data (e.g., changed fields) |
| `ip_address` | `VARCHAR(45)` | Actor's IP address |
| `user_agent` | `VARCHAR(255)`| Actor's User Agent |
| `created_at` | `TIMESTAMP` | UTC timestamp |
Example implementation:
```ts
await this.auditLogService.log({
userId: user.id,
action: 'rfa.update_status',
entityType: 'rfa_revisions',
entityId: rfaRevision.id,
detailsJson: { from: 'DFT', to: 'FAP' },
ipAddress: req.ip,
});
```
-----
## 📂 File Handling
### File Upload Standard
- Centralize all uploads via the `attachments` table.
- Upload path (convention): `/storage/{year}/{month}/`
- Stored filename: Use `stored_filename` (e.g., UUID or hash) to prevent conflicts. `original_filename` is for display.
- Allowed types: `pdf, dwg, docx, xlsx, zip`
- Max size: **50 MB**
- Store outside webroot.
- Serve via secure endpoint `/files/:attachment_id/download`.
### Access Control
File access is not direct. The `/files/:attachment_id/download` endpoint must:
1. Find the `attachment` record.
2. Get its `correspondence_id`.
3. Verify the user has permission to view that specific `correspondence` (or its related RFA, Transmittal, etc.).
-----
## 📊 Reporting & Exports
### Reporting Views (from SQL)
Reports should be built primarily from the pre-defined database Views:
- `v_current_correspondences`: For all current non-RFA document revisions.
- `v_current_rfas`: For all current RFA revisions and their master data.
- `v_contract_parties_all`: For auditing project/contract/organization relationships.
These views serve as the primary source for server-side reporting and data exports.
### Export Rules
- Export formats: CSV, Excel, PDF.
- Provide print view.
- Include source entity link (e.g., `/rfas/:id`).
-----
## 🧮 Frontend: DataTable & Form Patterns
### DataTable (ServerSide)
- Endpoint: `/api/{module}?page=1&pageSize=20&sort=...&filter=...`
- Must support: pagination, sorting, search, filters.
- Always display latest revision inline (for RFA/Drawing).
### Form Standards
- Dependent dropdowns must be implemented (as supported by schema):
- Project → Contract Drawing Volumes
- Contract Drawing Category → Sub-Category
- RFA (Shop Drawing type) → Linkable Shop Drawing Revisions
- File upload: preview + validation (via `attachments` logic).
- Submit via API with toast feedback.
-----
## 🧭 Dashboard & Activity Feed
### Dashboard Cards
- Show latest Correspondences, RFAs, Circulations.
- Include KPI summaries (e.g., "RFAs Pending Approval").
- Include quick links to modules.
### Activity Feed
- Display recent `audit_logs` actions (10 latest) relevant to the user.
<!-- end list -->
```ts
// Example API response
[
{ user: 'editor01', action: 'Updated RFA (LCBP3C1-RFA-001)', time: '2025-11-04T09:30Z' }
]
```
-----
## ✅ Implemented Standards (from SQL v1.1.0)
This section confirms that the following best practices are already part of the database design and should be leveraged, not re-implemented.
- ✅ **Soft Delete:** Implemented via `deleted_at` columns on key tables (e.g., `correspondences`, `rfas`, `project_parties`). Logic must filter for `deleted_at IS NULL`.
- ✅ **Database Indexes:** The schema is heavily indexed on foreign keys and common query columns (e.g., `idx_rr_rfa`, `idx_cor_project`, `idx_cr_is_current`) for performance.
- ✅ **RBAC Structure:** A comprehensive `users`, `roles`, `permissions`, `user_roles`, and `user_project_roles` system is in place.
- ✅ **Data Seeding:** Master data (roles, permissions, organization\_roles, initial users, project parties) is included in the schema script.
## 🧩 Recommended Enhancements (Future)
- ✅ Implement Fulltext search on fields like `correspondence_revisions.title` or `details`.
- ✅ Create a background job (using **n8n** as noted in SQL comments) for RFA deadline reminders based on `due_date`.
- ✅ Add a periodic cleanup job for `attachments` that are not linked to any `correspondence_id` (orphaned files).
-----

View File

@@ -0,0 +1,777 @@
# 📝 0. Project Title: Document Management System (DMS) Web Application for Laem Chabang Port Development Project, Phase 3
## 0. Project
### 📌 0.1 Project Overview / Description
- ระบบ Document Management System (DMS) เป็นเว็บแอปพลิเคชันที่ออกแบบมาเพื่อจัดการเอกสารภายในโครงการอย่างมีประสิทธิภาพ
- โดยมีฟังก์ชันหลักในการอัปโหลด จัดเก็บ ค้นหา แชร์ และควบคุมสิทธิ์การเข้าถึงเอกสาร
- ระบบนี้จะช่วยลดการใช้เอกสารกระดาษ เพิ่มความปลอดภัยในการจัดเก็บข้อมูล
- เพิ่มความสะดวกในการทำงานร่วมกันระหว่างองกรณ์
### 🎯 0.2 Objectives
- พัฒนาระบบที่สามารถจัดการเอกสารได้อย่างเป็นระบบ
- ลดความซ้ำซ้อนในการจัดเก็บเอกสาร
- เพิ่มความปลอดภัยในการเข้าถึงและจัดการเอกสาร
- รองรับการทำงานร่วมกันแบบออนไลน์
### 📦 0.3 Scope of Work
ระบบจะครอบคลุมฟีเจอร์หลักดังนี้:
- การลงทะเบียนและเข้าสู่ระบบ ของผู้ใช้งาน
- การอัปโหลดและจัดเก็บเอกสารในรูปแบบต่าง ๆ (PDF, DOCX, XLSX ฯลฯ)
- การจัดหมวดหมู่และแท็กเอกสาร
- การค้นหาเอกสารด้วยคำสำคัญหรือฟิลเตอร์
- การกำหนดสิทธิ์การเข้าถึงเอกสาร (เช่น อ่านอย่างเดียว, แก้ไข, ลบ)
- การบันทึกประวัติการใช้งานเอกสาร (Audit Trail)
- การมอบหมายงานให้กับผู้เกี่ยวข้อง และแจ้งเตือนเมื่อมีการมอบหมายงาน
- การแจ้งเตือนเมื่อถึงกำหนดวันที่ต้องส่งเอกสารต่อให้ ผู้เกี่ยวข้องอื่นๆ
- การแจ้งเตือนเมื่อมีการเปลี่ยนแปลงเอกสาร
### 👥 0.4 Target Users
- พนักงานภายใน ขององค์กร
- พนักงานควบคุมเอกสาร (Document Control)/ ผู้ดูแลระบบขององค์กร (admin)
- ผู้จัดการฝ่ายเอกสาร ขององค์กร
- ผู้จัดการโครงการ ขององค์กร
- คณะกรรมการ ของโครงการ
- ผู้ดูแลระบบ IT ของโครงการ (superadmin)
### 📈 0.5 Expected Outcomes
- ลดเวลาในการค้นหาเอกสารลงอย่างน้อย 50%
- ลดเวลาในการจัดทำรายงานเอกสาร ประจำวัน, ประจำสัปดาห์, ประจำเดือน, ประจำปี และ รายงานเอกสารทั้งโครงการ
- ลดการใช้เอกสารกระดาษในองค์กร
- เพิ่มความปลอดภัยในการจัดเก็บข้อมูล
- รองรับการทำงานแบบ Remote Work
### 📘 0.6 Requirements Use Cases
#### 📘 Use Case: Upload Document
Actor: พนักงานควบคุมเอกสาร (Document Control)
Description: พนักงานควบคุมเอกสารสามารถอัปโหลดเอกสารเข้าสู่ระบบเพื่อจัดเก็บและใช้งานในภายหลัง
Preconditions: พนักงานควบคุมเอกสารต้องเข้าสู่ระบบก่อน
Main Flow:
พนักงานควบคุมเอกสารเลือกเมนู “อัปโหลดเอกสาร”
เลือกไฟล์จากเครื่องคอมพิวเตอร์
กรอกข้อมูลประกอบ เช่น ชื่อเอกสาร หมวดหมู่ แท็ก
กดปุ่ม “อัปโหลด”
ระบบบันทึกเอกสารและแสดงผลการอัปโหลดสำเร็จ
Postconditions: เอกสารถูกจัดเก็บในระบบและสามารถค้นหาได้
#### 📘 Use Case: Assign Users to Document
Actor: พนักงานควบคุมเอกสาร (Document Control)
Description: พนักงานควบคุมเอกสารสามารถ มอบหมายงานให้กับ Users
Preconditions: พนักงานควบคุมเอกสารต้องเข้าสู่ระบบก่อน, เอกสารต้องอัปโหลดเรียบร้อยแล้ว
Main Flow:
พนักงานควบคุมเอกสารเลือกเมนู “มอบหมายงาน”
เลือกเอกสารในระบบ
เลือก Users กำหนดวันสิ้นสุดงาน
กดปุ่ม “มอบหมายงาน”
ระบบบันทึกเอกสารและแสดงผลการมอบหมายงานสำเร็จ
Postconditions: งานที่มอยหมาย จัดเก็บในระบบและสามารถค้นหาได้
#### 📘 Use Case: Search Document
Actor: ผู้ใช้งานทั่วไป
Description: ผู้ใช้งานสามารถค้นหาเอกสารจากระบบด้วยคำสำคัญหรือฟิลเตอร์
Preconditions: ผู้ใช้งานต้องเข้าสู่ระบบ
Main Flow:
ผู้ใช้งานกรอกคำค้นหรือเลือกฟิลเตอร์ (หมวดหมู่, วันที่, ผู้สร้าง, ผู้ได้รับมอบหมายงาน, สถานะ, title, subject)
กดปุ่ม “ค้นหา”
ระบบแสดงรายการเอกสารที่ตรงกับเงื่อนไข
Postconditions: ผู้ใช้งานสามารถเปิดดูหรือดาวน์โหลดเอกสารที่ค้นพบได้
#### 📘 Use Case: Manage Access
Actor: ผู้ดูแลระบบโครงการ (superadmin) / ผู้ดูแลระบบขององค์กร (admin)
Description: ผู้ดูแลระบบสามารถกำหนดสิทธิ์การเข้าถึงเอกสารให้กับผู้ใช้งาน
Preconditions: ผู้ดูแลระบบต้องเข้าสู่ระบบ
Main Flow:
ผู้ดูแลระบบเลือกเอกสาร
กด “จัดการสิทธิ์”
เลือกผู้ใช้งานและกำหนดสิทธิ์ (อ่าน, แก้ไข, ลบ)
กด “บันทึก”
Postconditions: สิทธิ์การเข้าถึงเอกสารถูกปรับตามที่กำหนด
#### 📘 Use Case: View Document History
Actor: ผู้ใช้งานทั่วไป / ผู้ดูแลระบบ
Description: ผู้ใช้งานสามารถดูประวัติการใช้งานเอกสาร เช่น การแก้ไข การดาวน์โหลด
Preconditions: ผู้ใช้งานต้องมีสิทธิ์เข้าถึงเอกสาร
Main Flow:
ผู้ใช้งานเปิดเอกสาร
เลือก “ดูประวัติ”
ระบบแสดงรายการกิจกรรมที่เกี่ยวข้องกับเอกสาร
Postconditions: ผู้ใช้งานสามารถตรวจสอบการเปลี่ยนแปลงย้อนหลังได้
### 🔄 0.7 Workflow อัตโนมัติในระบบ DMS
✅ ประโยชน์ของ Workflow อัตโนมัติใน DMS
- ลดภาระงานซ้ำ ๆ ของผู้ใช้งาน
- เพิ่มความปลอดภัยและการควบคุมเอกสาร
- เพิ่มความเร็วในการดำเนินงาน
- ลดข้อผิดพลาดจากการทำงานด้วยมือ
#### 🧩 Workflow: 1. Document treat Workflow
กรณี: เมื่อมีการอัปโหลดเอกสารต้องได้รับการมอบหมายงานให้กับ พนักงานภายในองค์กรณ์
ขั้นตอนอัตโนมัติ:
1. ผู้ใช้งานอัปโหลดเอกสารและเลือก “มอบหมายงาน”
2. ระบบส่งแจ้งเตือนไปยังผู้ได้รับมอบหมายงาน
3. ผู้อนุมัติสามารถตรวจสอบและกด “ตรวจสอบแล้ว”
4. ระบบบันทึกสถานะเอกสารและ ส่งต่อ ไปยัง องกรณือื่น ตามลำดับ เมื่อได้ผลและจัดทำเอกสารตอบแล้ว จึงแจ้งผลกลับไปยังผู้ส่ง
#### 📥 Workflow: 2. Auto Tagging & Categorization
กรณี: เอกสารที่อัปโหลดมีชื่อหรือเนื้อหาที่ตรงกับหมวดหมู่ที่กำหนดไว้
ขั้นตอนอัตโนมัติ:
เมื่ออัปโหลดเอกสาร ระบบวิเคราะห์ชื่อไฟล์หรือเนื้อหา
ระบบกำหนดหมวดหมู่และแท็กให้โดยอัตโนมัติ เช่น “ใบเสนอราคา” → หมวด “การเงิน”
ผู้ใช้งานสามารถแก้ไขได้หากต้องการ
#### 🔐 Workflow: 3. Access Control Workflow
กรณี: เอกสารที่มีความลับสูงต้องจำกัดการเข้าถึง
ขั้นตอนอัตโนมัติ:
เมื่ออัปโหลดเอกสารที่มีคำว่า “ลับ” หรือ “Confidential”
ระบบกำหนดสิทธิ์เริ่มต้นให้เฉพาะผู้ใช้งานระดับผู้จัดการขึ้นไป
ระบบแจ้งเตือนผู้ดูแลระบบให้ตรวจสอบสิทธิ์เพิ่มเติม
#### 📤 Workflow: 4. Expiry & Archiving Workflow
กรณี: เอกสารที่มีอายุการใช้งาน เช่น สัญญา หรือใบอนุญาต
ขั้นตอนอัตโนมัติ:
เมื่ออัปโหลดเอกสาร ผู้ใช้งานระบุวันหมดอายุ
ระบบแจ้งเตือนก่อนหมดอายุล่วงหน้า เช่น 30 วัน
เมื่อถึงวันหมดอายุ ระบบย้ายเอกสารไปยังหมวด “Archive” โดยอัตโนมัติ
#### 📊 Workflow: 5. Audit Trail & Notification Workflow
กรณี: มีการแก้ไขหรือดาวน์โหลดเอกสารสำคัญ
ขั้นตอนอัตโนมัติ:
ทุกการกระทำกับเอกสาร (เปิด, แก้ไข, ลบ) จะถูกบันทึกใน Audit Log
หากเอกสารถูกแก้ไขโดยผู้ใช้งานที่ไม่ใช่เจ้าของ ระบบแจ้งเตือนเจ้าของเอกสารทันที
## 🛠️ 1. DMS Architecture Deep Dive (Backend + Frontend)
### 1.1 Executive Summary
- Reverse proxy (Nginx/NPM) เผยแพร่ Frontend (Next.js) และ Backend (Node.js/Express) ผ่าน HTTPS (HSTS)
- Backend เชื่อม MariaDB 10.11 (ข้อมูลหลัก DMS) และแยก n8n + Postgres 16 สำหรับ workflow
- RBAC/ABAC ถูกบังคับใช้งานใน middleware + มีชุด SQL (tables → triggers → procedures → views → seed)
- ไฟล์จริง (PDF/DWG) เก็บนอก webroot ที่ /share/dmsdata พร้อมมาตรฐานการตั้งชื่อ+โฟลเดอร์
- Dev/Prod แยกชัดเจนผ่าน Docker multistage + dockercompose + โฟลเดอร์ persist logs/config/certs
### 1.2 Runtime Topology & Trust Boundaries
```text
Internet Clients (Browser)
│ HTTPS 443 (HSTS) [QNAP mgmt = 8443]
┌─────────────────────────────────────────────────────┐
│ Reverse Proxy Layer │
│ ├─ Nginx (Alpine) or Nginx Proxy Manager (NPM) │
│ ├─ TLS (LE cert; SAN multisubdomain) │
│ └─ Routes: │
│ • /, /_next/* → Frontend (Next.js :3000) │
│ • /api/* → Backend (Express :3001) │
│ • /pma/* → phpMyAdmin │
│ • /n8n/* → n8n (Workflows) │
└─────────────────────────────────────────────────────┘
│ │
│ └──────────┐
▼ │
Frontend (Next.js) │
│ Cookie-based Auth (HttpOnly) │
▼ ▼
Backend (Node/Express ESM) ─────────► MariaDB 10.11
│ │
└────────────────────────────────────┘
Project data (.pdf/.dwg) @ /share/dms-data
n8n (workflows) ──► Postgres 16 (separate DB for automations)
```
==Trust Boundaries==
- Public zone: Internet ↔ Reverse proxy
- App zone: Reverse proxy ↔ FE/BE containers (internal Docker network)
- # Data zone: Backend ↔ Databases (MariaDB, Postgres) + /share/dms-data
### 1.3 Frontend: Next.js (ESM) / React.js
#### 1.3.1 Stack & Key libs
- Next.js (App Router), React, ESM
- Tailwind CSS, PostCSS, shadcn/ui (components.json)
- Fetch API (credentials include) → Cookie Auth (HttpOnly)
#### 1.3.2 Directory Layout
```text
/frontend/
├─ app/
│ ├─ login/
│ ├─ dashboard/
│ ├─ users/
│ ├─ correspondences/
│ ├─ health/
│ └─ layout.tsx / page.tsx (ตาม App Router)
├─ public/
├─ Dockerfile (multi-stage: dev/prod)
├─ package.json
├─ next.config.js
└─ ...
```
#### 1.3.3 Routing & Layouts
- Public /login, /health
- Protected: /dashboard, /users, /correspondences, ... (client-side guard)
- เก็บ middleware.ts (ของเดิม) เพื่อหลีกเลี่ยง regression; ใช้ clientguard + server action อย่างระมัดระวัง
#### 1.3.4 Auth Flow (Cookie-based)
1. ผู้ใช้ submit form /login → POST /api/auth/login (Backend)
2. Backend set HttpOnly cookie (JWT) + SameSite=Lax/Strict, Secure
3. หน้า protected เรียก GET /api/auth/me เพื่อตรวจสอบสถานะ
4. หาก 401 → redirect → /login
**CORS/Fetch**: เเปิด credentials: 'include' ทุกครั้ง, ตั้ง NEXT_PUBLIC_API_BASE เป็น origin ของ backend ผ่าน proxy (เช่น https://lcbp3.np-dms.work)
#### 1.3.5 UI/UX
- Seablue palette, sidebar พับได้, cardbased KPI
- ตารางข้อมูลเตรียมรองรับ serverside DataTables\*\*
- shadcn/ui: Button, Card, Badge, Tabs, Dropdown, Tooltip, Switch, etc.
#### 1.3.6 Config & ENV
- NEXT_PUBLIC_API_BAS (ex: https://lcbp3.np-dms.work)
- Build output แยก dev/prod; ระวัง EACCES บน QNAP → ใช้ user node + ปรับสิทธิ์โวลุ่ม .next/\*
#### 1.3.7 Error Handling & Observability (FE)
- Global error boundary (app router) + toast/alert patterns
- Network layer: แยก handler สำหรับ 401/403/500 + retry/backoff ที่จำเป็น
- Metrics (optional): webvitals, UX timing (เก็บฝั่ง n8n หรือ simple logging)
---
### 1.4 Backend Architecture (Node.js ESM / Express)
#### 1.4.1 Stack & Structure
- Node 20.x, ESM modules, Express\*\*
- mysql2/promise, jsonwebtoken, cookie-parser, cors, helmet, winston/morgan
```text
/backend/
├─ src/
│ ├─ index.js # bootstrap server, CORS, cookies, health
│ ├─ routes/
│ │ ├─ auth.js # /api/auth/* (login, me, logout)
│ │ ├─ users.js # /api/users/*
│ │ ├─ correspondences.js # /api/correspondences/*
│ │ ├─ drawings.js # /api/drawings/*
│ │ ├─ rfas.js # /api/rfas/*
│ │ └─ transmittals.js # /api/transmittals/*
│ ├─ middleware/
│ │ ├─ authGuard.js # verify JWT from cookie
│ │ ├─ requirePermission.js# RBAC/ABAC enforcement
│ │ ├─ errorHandler.js
│ │ └─ requestLogger.js
│ ├─ db/
│ │ ├─ pool.js # createPool, sane defaults
│ │ └─ models/ # query builders (User, Drawing, ...)
│ ├─ utils/
│ │ ├─ hash.js (bcrypt/argon2)
│ │ ├─ jwt.js
│ │ ├─ pagination.js
│ │ └─ responses.js
│ └─ config/
│ └─ index.js # env, constants
├─ Dockerfile
└─ package.json
```
#### 1.4.2 Request Lifecycle
1. helmet + cors (allow specific origin; credentials true)
2. cookie-parser, json limit (e.g., 2MB)
3. requestLogger → trace + response time
4. Route handler → authGuard (protected) → requirePermission (perroute) → Controller
5. Error bubbles → errorHandler (JSON shape, status map)
#### 1.4.3 Auth & RBAC/ABAC
- JWT ใน HttpOnly cookie; Claims: sub (user_id), roles, exp
- authGuard: ตรวจ token → แนบ req.user
- requirePermission: เช็ค permission ตามเส้นทาง/วิธี; แผนขยาย ABAC (เช่น project scope, owner, doc state)
- Roles/Permissions ถูก seed ใน SQL; มี view เมทริกซ์ เพื่อ debug (เช่น v_role_permission_matrix)
\*\*ตัวอย่าง pseudo requirePermission(permission)
```js
export const requirePermission = (perm) => async (req, res, next) => {
if (!req.user) return res.status(401).json({ error: "Unauthenticated" });
const ok = await checkPermission(req.user.user_id, perm, req.context);
if (!ok) return res.status(403).json({ error: "Forbidden" });
return next();
};
```
#### 1.4.4 Database Access & Pooling
- createPool({ connectionLimit: 10~25, queueLimit: 0, waitForConnections: true })
- ใช้ parameterized queries เสมอ; ปรับ sql_mode ที่จำเป็นใน my.cnf
#### 1.4.5 File Storage & Secure Download
- Root: /share/dmsdata
- โครงโฟลเดอร์: {module}/{yyyy}/{mm}/{entityId}/ + ชื่อไฟล์ตามมาตรฐาน (เช่น DRW-code-REV-rev.pdf)
- Endpoint download: ตรวจสิทธิ์ (RBAC/ABAC) → res.sendFile()/stream; ป้องกัน path traversal
- MIME allowlist + size limit + virus scan (optional; ภายหลัง)
#### 1.4.6 Health & Readiness
- GET /api/health → { ok: true }
- (optional) /api/ready ตรวจ DB ping + disk space (dmsdata)
#### 1.4.7 Config & ENV (BE)
- DB_HOST, DB_PORT, DB_USER, DB_PASS, DB_NAME
- JWT_SECRET, COOKIE_NAME, COOKIE_SAMESITE, COOKIE_SECURE
- CORS_ORIGIN, LOG_LEVEL, APP_BASE_URL
- FILE_ROOT=/share/dms-data
#### 1.4.8 Logging
- Access log (morgan) + App log (winston) → /share/Container/dms/logs/backend/
- รูปแบบ JSON (timestamp, level, msg, reqId) + daily rotation (logrotate/containerside)
### 1.5 Database (MariaDB 10.11)
#### 1.5.1 Schema Overview (ย่อ)
- RBAC core: users, roles, permissions, user_roles, role_permissions
- Domain: drawings, contracts, correspondences, rfas, transmittals, organizations, projects, ...
- Audit: audit_logs (แผนขยาย), deleted_at (soft delete, แผนงาน)
```text
[users]──<user_roles>──[roles]──<role_permissions>──[permissions]
└── activities/audit_logs (future expansion)
[drawings]──<mapping>──[contracts]
[rfas]──<links>──[drawings]
[correspondences] (internal/external flag)
```
#### 1.5.2 Init SQL Pipeline
1. 01\_\*\_deploy_table_rbac.sql — สร้างตารางหลักทั้งหมด + RBAC
2. 02\_\*\_triggers.sql — บังคับ data rules, autoaudit fields
3. 03\_\*\_procedures_handlers.sql — upsert/bulk handlers (เช่น sp_bulk_import_contract_dwg)
4. 04\_\*\_views.sql — รายงาน/เมทริกซ์สิทธิ์ (v_role_permission_matrix, etc.)
5. 05\_\*\_seed_data.sql — ค่าพื้นฐาน domain (project, categories, statuses)
6. 06\_\*\_seed_users.sql — บัญชีเริ่มต้น (superadmin, editors, viewers)
7. 07\_\*\_seed_contract_dwg.sql — ข้อมูลตัวอย่างแบบสัญญา
#### 1.5.3 Indexing & Performance
- Composite indexes ตามคอลัมน์ filter/sort (เช่น (project_id, updated_at DESC))
- Fulltext index (optional) สำหรับ advanced search
- Query plan review (EXPLAIN) + เพิ่ม covering index ตามรายงาน
#### 1.5.4 MySQL/MariaDB Config (my.cnf — แนวทาง)
```conf
[mysqld]
innodb_buffer_pool_size = 4G # ปรับตาม RAM/QNAP
innodb_log_file_size = 512M
innodb_flush_log_at_trx_commit = 1
max_connections = 200
sql_mode = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
```
> ปรับค่าให้เหมาะกับ workload จริง + เฝ้าดู IO/CPU ของ QNAP
#### 1.5.5 Backup/Restore
- Logical backup: mysqldump --routines --triggers --single-transaction
- Physical (snapshot QNAP) + schedule ผ่าน n8n/cron
- เก็บสำเนา offNAS (encrypted)
### 1.6 Reverse Proxy & TLS
#### 1.6.1 Nginx (Alpine) — ตัวอย่าง server block
> สำคัญ: บนสภาพแวดล้อมนี้ ให้ใช้คนละบรรทัด:
> listen 443 ssl;
> http2 on;
> หลีกเลี่ยง listen 443 ssl http2;
```conf
server {
listen 80;
server_name lcbp3.np-dms.work;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name lcbp3.np-dms.work;
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
add_header Strict-Transport-Security "max-age=63072000; preload" always;
# Frontend
location / {
proxy_pass http://frontend:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Next.js static
location /_next/ {
proxy_pass http://frontend:3000;
}
# Backend API
location /api/ {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://backend:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
# phpMyAdmin (sub-path)
location /pma/ {
proxy_pass http://phpmyadmin:80/;
}
# n8n
location /n8n/ {
proxy_pass http://n8n:5678/;
}
}
```
#### 1.6.2 Nginx Proxy Manager (NPM) — Tips
- ระวังอย่าใส่ proxy_http_version ซ้ำซ้อน (duplicate directive) ใน Advanced
- ถ้าต้องแก้ไฟล์ด้านใน NPM → ระวังไฟล์ใน /data/nginx/proxy_host/\*.conf
- จัดการ certificate / SAN หลาย subdomain ใน UI แต่ mainten ดีเรื่อง symlink/renew
#### 1.6.3 TLS & Certificates
- Lets Encrypt (HTTP01 webroot/standalone) + HSTS
- QNAP mgmt เปลี่ยนเป็น 8443 → พอร์ต 443 public ว่างสำหรับ Nginx/NPM
### 1.7 Docker Compose Topology
#### 1.7.1 Services (สรุป)
- frontend (Next.js) :3000
- backend (Express) :3001
- mariadb (10.11) :3306 (internal)
- phpmyadmin :80 (internal)
- nginx or npm :80/443 (published)
- n8n :5678 (internal)
- postgres_n8n (16-alpine)
- pgadmin4
#### 1.7.2 Volumes & Paths
```text
/share/Container/dms/
├─ mariadb/data
├─ mariadb/init/*.sql
├─ backend/ (code)
├─ frontend/ (code)
├─ phpmyadmin/{sessions,tmp,config.user.inc.php}
├─ nginx/{nginx.conf,dms.conf,certs/}
├─ n8n, n8n-postgres, n8n-cache
└─ logs/{backend,frontend,nginx,pgadmin,phpmyadmin,postgres_n8n}
/share/dms-data (pdf/dwg storage)
```
#### 1.7.3 Healthchecks (suggested)
- backend:
```sh
curl http://localhost:3001/api/health
```
- frontend: curl /health (simple JSON)
- mariadb: mysqladmin ping with credentials
- nginx: nginx -t at startup
#### 1.7.4 Security Hardening
- รัน container ด้วย user nonroot (user: node สำหรับ FE/BE)
- จำกัด capabilities; readonly FS (ยกเว้นโวลุ่มจำเป็น)
- เฉพาะ backend เมานต์ /share/dms-data
### 1.8 Observability, Ops, and Troubleshooting
#### 1.8.1 Logs
- Frontend → /logs/frontend/\*
- Backend → /logs/backend/\* (app/access/error)
- Nginx/NPM → /logs/nginx/\*
- MariaDB → default datadir log + slow query (เปิดใน my.cnf หากต้องการ)
#### 1.8.2 Common Issues & Playbooks
- 401 Unauthenticated: ตรวจ authGuard → JWT cookie มี/หมดอายุ → เวลา server/FE sync → CORS credentials: true
- EACCES Next.js: สิทธิ์ .next/\* + run as`node, โวลุ่ม map ถูก user:group
- NPM duplicate directive: ลบซ้ำ proxy_http_version ใน Advanced / ตรวจ proxy_host/\*.conf
- LE cert path/symlink: ตรวจ /etc/letsencrypt/live/npm-\* symlink ชี้ถูก
- DB field not found: ตรวจ schema vs code (migration/init SQL) → sync ให้ตรง
#### 1.8.3 Performance Guides
- Backend: keepalive, gzip/deflate at proxy, pool 1025, paginate, avoid N+1
- Frontend: prefetch critical routes, cache static, image optimization
- DB: เพิ่ม index จุด filter, analyze query (EXPLAIN), ปรับ buffer pool
### 1.9 Security & Compliance
- HTTPS only + HSTS (preload)
- CORS: allow list เฉพาะ FE origin; Access-Control-Allow-Credentials: true
- Cookie: HttpOnly, Secure, SameSite=Lax/Strict
- Input Validation: celebrate/zod (optional) + sanitize
- Rate limiting: per IP/route (optional)
- AuditLog: วางแผนเพิ่ม ครอบคลุม CRUD + mapping (actor, action, entity, before/after)
- Backups: DB + /share/dms-data + config (encrypted offNAS)
### 1.10 Backlog → Architecture Mapping
1. RBAC Enforcement ครบ → เติม requirePermission ทุก route + test matrix ผ่าน view
2. AuditLog ครบ CRUD/Mapping → trigger + table audit_logs + BE hook
3. Upload/Download จริงของ Drawing Revisions → BE endpoints + virus scan (optional)
4. Dashboard KPI → BE summary endpoints + FE cards/charts
5. Serverside DataTables → paging/sort/filter + indexesรองรับ
6. รายงาน Export CSV/Excel/PDF → BE export endpoints + FE buttons
7. Soft delete (deleted_at) → BE filter default scope + restore endpoint
8. Validation เข้ม → celebrate/zod schema + consistent error shape
9. Indexing/Perf → slow query log + EXPLAIN review
10. Job/Cron Deadline Alerts → n8n schedule + SMTP
### 1.11 Port & ENV Matrix (Quick Ref)
| Component | Ports | Key ENV |
| Nginx/NPM | 80/443 (public) | SSL paths, HSTS |
| Frontend | 3000 (internal) | NEXT*PUBLIC_API_BASE |
| Backend | 3001 (internal) | DB*\*, JWT*SECRET, CORS_ORIGIN, FILE_ROOT |
| MariaDB | 3306 (internal) | MY_CNF, credentials |
| n8n | 5678 (internal) | N8N*, webhook URL under /n8n/ |
| Postgres | 5432 (internal) | n8n DB |
QNAP mgmt: 8443 (already moved)
### 1.12 Sample Snippets
#### 1.12.1 Backend CORS (credentials)
```js
app.use(
cors({
origin: ["https://lcbp3.np-dms.work"],
credentials: true,
})
);
```
#### 1.12.2 Secure Download (guarded)
```js
router.get(
"/files/:module/:id/:filename",
authGuard,
requirePermission("file.read"),
async (req, res) => {
const { module, id, filename } = req.params;
// 1) ABAC: verify user can access this module/entity
const ok = await canReadFile(req.user.user_id, module, id);
if (!ok) return res.status(403).json({ error: "Forbidden" });
const abs = path.join(FILE_ROOT, module, id, filename);
if (!abs.startsWith(FILE_ROOT))
return res.status(400).json({ error: "Bad path" });
return res.sendFile(abs);
}
);
```
#### 1.12.3 Healthcheck
```js
router.get("/health", (req, res) => res.json({ ok: true }));
```
### 13 Deployment Workflow (Suggested)
1. Git (Gitea) branch strategy feature/\* → PR → main
2. Build images (dev/prod) via Dockerfile multistage; pin Node/MariaDB versions
3. docker compose up -d --build จาก /share/Container/dms
4. Validate: /health, /api/health, login roundtrip
5. Monitor logs + baseline perf; run SQL smoke tests (views/triggers/procs)
### 14 Appendix
- Naming conventions: snake_case DB, camelCase JS
- Timezones: store UTC in DB; display in app TZ (+07:00)
- Character set: UTF8 (utf8mb4_unicode_ci)
- Large file policy: size limit (e.g., 50200MB), allowlist extensions
- Retention: archive strategy for old revisions (optional)
## บทบาท: คุณคือ Programmer และ Document Engineer ที่เชี่ยวชาญ
1. การพัฒนาเว็บแอป (Web Application Development)
2. Configuration of Container Station on QNAP
3. Database: mariadb:10.11
4. Database management: phpmyadmin:5-apache
5. Backend: node:.js (ESM)
6. Frontend: next.js, react
7. Workflow automation: n8n:
8. Workflow database: postgres:16-alpine
9. Workflow database management: pgadmin4
10. Reverse proxy: nginx:1.27-alpine
11. linux on QNAP
12. การจัดการฐานข้อมูล (Database Management)
13. การวิเคราะห์ฐานข้อมูล (Database Analysis)
14. การจัดการฐานข้อมูลเชิงสัมพันธ์ (Relational Databases)
15. ภาษา SQL
16. RBAC
## 2. ระบบที่ใช้
## Server
- ใช้ Container Station เป็น SERVER บน QNAP (Model: TS-473A, RAM: 32GB, CPU: AMD Ryzen V1500B 4 cores 8 threads) **เปลี่ยน port 443 ของ QNAP เป็น 8443 แล้ว**
## การพัฒนาโครงการ
- ด้วย Visual Studio Code บน Windows 11
- ใช้ ๊ UI ของ Container Station เป็นหลัก
## โครงสร้างโฟลเดอร์ (บน QNAP)
/share/Container/dms/
├─ docker-compose.yml # Create โดย UI Container Station
├─ mariadb/
│ ├─ data/ # ข้อมูลจริงของ MariaDB
│ ├─ init/ # ข้อมูลเริ่มต้นของ MariaDB
│ │ ├─ 01_dms_data_v5_1_deploy_table_rbac.sql # Create all data table & RBAC table here!
│ │ ├─ 02_dms_data_v5_1_triggers.sql # Create all triggers here!
│ │ ├─ 03_dms_data_v5_1_procedures_handlers.sql # Create all procedures here!
│ │ ├─ 04_dms_data_v5_1_views.sql # Create all views here!
│ │ ├─ 05 dms_data_v5_1_seeก_data.sql # Seed nescesary data here!
│ │ ├─ 06_dms_data_v5_1_seed_users.sql # Seed users data here!
│ │ └─ 07_dms_data_v5_1_seed_contract_dwg.sql # Seed contract drawing data here!
│ └─ my.cnf
├─ backend/
│ ├─ app/
│ ├─ src/
│ │ ├─ db/
│ │ │ └─models/
│ │ ├─ middleware/
│ │ ├─ routes/
│ │ ├─ utils/
│ │ └─ index.js
│ ├─ Dockerfile
│ ├─ package.json
│ └─ package-lock.json # ไม่มี
├─ frontend/
│ ├─ app/
│ │ ├─ correspondences/
│ │ ├─ dashboard/
│ │ ├─ health/
│ │ ├─ login/
│ │ └─ users/
│ ├─ public/
│ ├─ Dockerfile
│ ├─ package.json
│ ├─ package-lock.json # ไม่มี
│ ├─ next.config.js
│ └─ page.jsx
├─ phpmyadmin/
│ ├─ sessions/ # โฟลเดอร์เซสชันถาวรของ phpMyAdmin
│ ├─ tmp/
│ ├─ config.user.inc.php
│ └─ zzz-custom.ini
├─ nginx/
│ ├─ certs/
│ ├─ nginx.conf
│ └─ dms.conf
├─ n8n/
├─ n8n-cache/
├─ n8n-postgres/
└─ logs/
├─ backend/
├─ frontend/
├─ nginx/
├─ pgadmin/
├─ phpmyadmin/
└─ postgres_n8n/
/share/dms-data # เก็บข้อมมูล .pdf, .dwg แยกตาม correspondences, documents
# งานที่ต้องการ:
- ไม่ใช้ .env เด็ดขาด Container Station ไม่รองรับ และ docker-compose.yml ได้ทดสอบ รันบน Container station มาแล้ว
- Code ของ backend ทั้งหมด
- การทดสอบระบบ backend ทุกส่วน ให้พร้อม สำหรับ frontend
# กรณี 2: มี Git อยู่แล้ว (มี main อยู่)
2.1 อัปเดต main ให้ตรงล่าสุดก่อนแตกบร้านช์
cd /share/Container/dms
git checkout main
git pull --ff-only # ถ้าเชื่อม remote อยู่
git tag -f stable-$(date +%F) # tag จุดเสถียรปัจจุบัน
2.2 แตก branch งาน Dashboard
git checkout -b feature/dashboard-update-$(date +%y%m%d)
git checkout -b feature/dashboard-update-251004
2.3 ทำงาน/คอมมิตตามปกติ
# แก้ไฟล์ frontend/app/dashboard/\* และที่เกี่ยวข้อง
git add frontend/app/dashboard
git commit -m "feat(dashboard): เพิ่มส่วนจัดการ user"
git push -u origin feature/dashboard-update-251004

View File

@@ -0,0 +1,134 @@
You are a senior TypeScript programmer with experience in the NestJS framework and a preference for clean programming and design patterns.
Generate code, corrections, and refactorings that comply with the basic principles and nomenclature.
## TypeScript General Guidelines
### Basic Principles
- Use English for all code and documentation.
- Always declare the type of each variable and function (parameters and return value).
- Avoid using any.
- Create necessary types.
- Use JSDoc to document public classes and methods.
- Don't leave blank lines within a function.
- One export per file.
### Nomenclature
- Use PascalCase for classes.
- Use camelCase for variables, functions, and methods.
- Use kebab-case for file and directory names.
- Use UPPERCASE for environment variables.
- Avoid magic numbers and define constants.
- Start each function with a verb.
- Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
- Use complete words instead of abbreviations and correct spelling.
- Except for standard abbreviations like API, URL, etc.
- Except for well-known abbreviations:
- i, j for loops
- err for errors
- ctx for contexts
- req, res, next for middleware function parameters
### Functions
- In this context, what is understood as a function will also apply to a method.
- Write short functions with a single purpose. Less than 20 instructions.
- Name functions with a verb and something else.
- If it returns a boolean, use isX or hasX, canX, etc.
- If it doesn't return anything, use executeX or saveX, etc.
- Avoid nesting blocks by:
- Early checks and returns.
- Extraction to utility functions.
- Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting.
- Use arrow functions for simple functions (less than 3 instructions).
- Use named functions for non-simple functions.
- Use default parameter values instead of checking for null or undefined.
- Reduce function parameters using RO-RO
- Use an object to pass multiple parameters.
- Use an object to return results.
- Declare necessary types for input arguments and output.
- Use a single level of abstraction.
### Data
- Don't abuse primitive types and encapsulate data in composite types.
- Avoid data validations in functions and use classes with internal validation.
- Prefer immutability for data.
- Use readonly for data that doesn't change.
- Use as const for literals that don't change.
### Classes
- Follow SOLID principles.
- Prefer composition over inheritance.
- Declare interfaces to define contracts.
- Write small classes with a single purpose.
- Less than 200 instructions.
- Less than 10 public methods.
- Less than 10 properties.
### Exceptions
- Use exceptions to handle errors you don't expect.
- If you catch an exception, it should be to:
- Fix an expected problem.
- Add context.
- Otherwise, use a global handler.
### Testing
- Follow the Arrange-Act-Assert convention for tests.
- Name test variables clearly.
- Follow the convention: inputX, mockX, actualX, expectedX, etc.
- Write unit tests for each public function.
- Use test doubles to simulate dependencies.
- Except for third-party dependencies that are not expensive to execute.
- Write acceptance tests for each module.
- Follow the Given-When-Then convention.
## Specific to NestJS
### Basic Principles
- Use modular architecture.
- Encapsulate the API in modules.
- One module per main domain/route.
- One controller for its route.
- And other controllers for secondary routes.
- A models folder with data types.
- DTOs validated with class-validator for inputs.
- Declare simple types for outputs.
- A services module with business logic and persistence.
- Entities with MikroORM for data persistence.
- One service per entity.
- Common Module: Create a common module (e.g., @app/common) for shared, reusable code across the application.
- This module should include:
- Configs: Global configuration settings.
- Decorators: Custom decorators for reusability.
- DTOs: Common data transfer objects.
- Guards: Guards for role-based or permission-based access control.
- Interceptors: Shared interceptors for request/response manipulation.
- Notifications: Modules for handling app-wide notifications.
- Services: Services that are reusable across modules.
- Types: Common TypeScript types or interfaces.
- Utils: Helper functions and utilities.
- Validators: Custom validators for consistent input validation.
- Core module functionalities:
- Global filters for exception handling.
- Global middlewares for request management.
- Guards for permission management.
- Interceptors for request processing.
### Testing
- Use the standard Jest framework for testing.
- Write tests for each controller and service.
- Write end to end tests for each api module.
- Add a admin/test method to each controller as a smoke test.

View File

@@ -0,0 +1,33 @@
You are a Senior Front-End Developer and an Expert in ReactJS, NextJS, JavaScript, TypeScript, HTML, CSS and modern UI/UX frameworks (e.g., TailwindCSS, Shadcn, Radix). You are thoughtful, give nuanced answers, and are brilliant at reasoning. You carefully provide accurate, factual, thoughtful answers, and are a genius at reasoning.
- Follow the users requirements carefully & to the letter.
- First think step-by-step - describe your plan for what to build in pseudocode, written out in great detail.
- Confirm, then write code!
- Always write correct, best practice, DRY principle (Dont Repeat Yourself), bug free, fully functional and working code also it should be aligned to listed rules down below at Code Implementation Guidelines .
- Focus on easy and readability code, over being performant.
- Fully implement all requested functionality.
- Leave NO todos, placeholders or missing pieces.
- Ensure code is complete! Verify thoroughly finalised.
- Include all required imports, and ensure proper naming of key components.
- Be concise Minimize any other prose.
- If you think there might not be a correct answer, you say so.
- If you do not know the answer, say so, instead of guessing.
### Coding Environment
The user asks questions about the following coding languages:
- ReactJS
- NextJS
- JavaScript
- TypeScript
- TailwindCSS
- HTML
- CSS
### Code Implementation Guidelines
Follow these rules when you write code:
- Use early returns whenever possible to make the code more readable.
- Always use Tailwind classes for styling HTML elements; avoid using CSS or tags.
- Use “class:” instead of the tertiary operator in class tags whenever possible.
- Use descriptive variable and function/const names. Also, event functions should be named with a “handle” prefix, like “handleClick” for onClick and “handleKeyDown” for onKeyDown.
- Implement accessibility features on elements. For example, a tag should have a tabindex=“0”, aria-label, on:click, and on:keydown, and similar attributes.
- Use consts instead of functions, for example, “const toggle = () =>”. Also, define a type if possible.

View File

@@ -0,0 +1,171 @@
# การติดตั้งและสร้างโปรเจกต์ (Project Initialization)
1. ข้อกำหนดเบื้องต้น (Prerequisites)
ก่อนเริ่ม, ตรวจสอบให้แน่ใจว่าคุณมีเครื่องมือเหล่านี้ติดตั้งบน Windows 11 ของคุณแล้ว:
Node.js: เวอร์ชัน 18.x หรือสูงกว่า
NPM หรือ Yarn: ตัวจัดการ Package (มักจะมาพร้อมกับ Node.js)
NestJS CLI: เครื่องมือ Command-line สำหรับ NestJS
หากยังไม่ได้ติดตั้ง NestJS CLI, ให้เปิด VS Code Terminal หรือ Command Prompt แล้วรันคำสั่ง:
bash
npm install -g @nestjs/cli
## 2.1 สร้างโปรเจกต์ NestJS ใหม่
ไปที่ Directory ที่คุณต้องการเก็บโปรเจกต์ (เช่น C:\Users\YourUser\Development\)
ใช้ NestJS CLI เพื่อสร้างโปรเจกต์ใหม่ ผมจะตั้งชื่อว่า backend-np-dms นะครับ:
Bash
nest new backend
ระบบจะถามว่าต้องการใช้ Package Manager ตัวไหน แนะนำให้เลือก npm, รอจนกว่ากระบวนการจะเสร็จสิ้น คุณจะได้โฟลเดอร์ backend ที่มีโครงสร้างพื้นฐานของ NestJS พร้อมใช้งาน
## 2.2 ติดตั้ง Dependencies ที่จำเป็น
ตอนนี้เราจะติดตั้ง Modules ทั้งหมดที่คุณวางแผนไว้ในคราวเดียว เพื่อให้โปรเจกต์พร้อมสำหรับการพัฒนา
เปิด Terminal ใน VS Code ภายในโฟลเดอร์ backend (cd backend) แล้วรันคำสั่งต่อไปนี้:
* Database & ORM (TypeORM for MariaDB/MySQL)
Bash
npm install @nestjs/typeorm typeorm mysql2
* Configuration Management (สำหรับ .env)
npm install @nestjs/config
* API Documentation
npm install @nestjs/swagger
* Validation & Transformation
npm install class-validator class-transformer
* Security
npm install helmet
* Authentication (JWT)
npm install @nestjs/passport passport passport-jwt @nestjs/jwt
npm install --save-dev @types/passport-jwt
คำอธิบาย:
@nestjs/typeorm typeorm mysql2: สำหรับเชื่อมต่อและจัดการฐานข้อมูล MariaDB
@nestjs/config: สำหรับจัดการ Environment Variables (เช่น ข้อมูลการเชื่อมต่อ DB) ผ่านไฟล์ .env
@nestjs/swagger: สำหรับสร้างหน้าเอกสาร API (Swagger/OpenAPI) โดยอัตโนมัติ
class-validator class-transformer: ใช้สำหรับตรวจสอบความถูกต้องของข้อมูลที่ส่งเข้ามาใน API (Request Body Validation)
helmet: ช่วยเพิ่มความปลอดภัยพื้นฐานโดยการตั้งค่า HTTP Headers ที่เหมาะสม
@nestjs/passport, @nestjs/jwt: เครื่องมือมาตรฐานสำหรับทำระบบ Authentication
## 2.3: ตั้งค่าพื้นฐานในโปรเจกต์ (Initial Configuration)
ตอนนี้เราจะแก้ไขไฟล์หลักๆ เพื่อเปิดใช้งาน Modules ที่ติดตั้งไป
1. สร้างไฟล์ Environment (.env)
ที่ราก (root) ของโปรเจกต์ backend-np-dms, สร้างไฟล์ใหม่ชื่อ .env และใส่ข้อมูลการเชื่อมต่อฐานข้อมูลของคุณ (ข้อมูลนี้จะไม่ถูกเก็บใน Git):
.env
Code snippet
* Database Configuration
DB_TYPE=mysql
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=your_db_user # <-- แก้ไขเป็น user ของคุณ
DB_PASSWORD=your_db_password # <-- แก้ไขเป็น password ของคุณ
DB_DATABASE=dms_db # <-- แก้ไขเป็นชื่อ database ของคุณ
* Application
API_PORT=3001
💡 Tip: หากคุณรัน MariaDB ผ่าน Docker, DB_HOST อาจจะเป็นชื่อ Service ของ Docker container (เช่น mariadb-container) หรือ IP ของ QNAP ของคุณ
2. แก้ไข app.module.ts เพื่อเชื่อมต่อ Database และ Config
เปิดไฟล์ src/app.module.ts และแก้ไขให้เป็นตามนี้เพื่อ import ConfigModule และ TypeOrmModule:
src/app.module.ts
```TypeScript
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
// 1. Config Module - สำหรับอ่าน .env (ต้องอยู่บนสุด)
ConfigModule.forRoot({
isGlobal: true, // ทำให้ ConfigService พร้อมใช้งานทั่วทั้งแอป
envFilePath: '.env',
}),
// 2. TypeORM Module - สำหรับเชื่อมต่อ Database
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
type: 'mysql',
host: configService.get<string>('DB_HOST'),
port: configService.get<int>('DB_PORT'),
username: configService.get<string>('DB_USERNAME'),
password: configService.get<string>('DB_PASSWORD'),
database: configService.get<string>('DB_DATABASE'),
entities: [__dirname + '/../**/*.entity{.ts,.js}'],
synchronize: true, // สำหรับ Development เท่านั้น! จะสร้างตารางให้อัตโนมัติ
logging: true,
}),
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
```
⚠️ คำเตือน: synchronize: true สะดวกมากในช่วงพัฒนาเพราะมันจะปรับโครงสร้างตารางตาม Entity ให้อัตโนมัติ ห้ามใช้ใน Production เด็ดขาด เพราะอาจทำให้ข้อมูลหายได้ ใน Production ควรใช้ระบบ Migration แทน
3. แก้ไข main.ts เพื่อเปิดใช้งาน Swagger, Validation และ Security
เปิดไฟล์ src/main.ts และเพิ่มการตั้งค่าต่างๆ เข้าไป:
src/main.ts
TypeScript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import helmet from 'helmet';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// เปิดใช้งาน CORS (Cross-Origin Resource Sharing)
app.enableCors();
// เพิ่ม Helmet เพื่อความปลอดภัย
app.use(helmet());
// ตั้งค่า Global Validation Pipe
app.useGlobalPipes(new ValidationPipe({
whitelist: true, // ตัด property ที่ไม่มีใน DTO ออก
transform: true, // แปลงข้อมูลให้เป็น type ที่ระบุใน DTO
}));
// ตั้งค่า Swagger API Documentation
const config = new DocumentBuilder()
.setTitle('LCBP3-DMS API')
.setDescription('The Document Management System API for LCBP3 Project')
.setVersion('1.0')
.addBearerAuth() // สำหรับ JWT
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api-docs', app, document); // เข้าถึงได้ที่ /api-docs
// เริ่มรัน Server
const port = process.env.API_PORT || 3001;
await app.listen(port);
console.log(`Application is running on: ${await app.getUrl()}`);
}
bootstrap();
curl -i -X POST \
-H "Content-Type: application/json" \
-d '{"username": "superadmin", "password": "Center#2025"}' \
https://backend.np-dms.work/api/auth/login

View File

@@ -0,0 +1,17 @@
ฟีเจอร์ขั้นสูง (Advanced Features)
Error Handling: ใช้ Global Exception Filter เพื่อจัดการ Error และส่ง Response ที่เป็นมาตรฐาน
Logging: ใช้ Winston สำหรับ Structured Logging และบันทึก Error ลงไฟล์
Testing: มีโครงสร้างสำหรับ Unit Test และ E2E Test ด้วย Jest และ Supertest
Performance: ใช้ CacheModule สำหรับ Caching ข้อมูลที่เรียกใช้บ่อย
Security:
Rate Limiting: ใช้ ThrottlerModule เพื่อป้องกัน Brute-force attack
Secret Management: แนะนำให้ใช้ Environment Variable ของ Docker แทนไฟล์ .env ใน Production
API Documentation: สร้างเอกสาร API อัตโนมัติด้วย @nestjs/swagger และเข้าถึงได้ที่ /api-docs

View File

@@ -0,0 +1,192 @@
## Workflow ระดับ Project (correspondence_routing_steps, technical_doc_workflows): คือ "การเดินทาง" ของเอกสาร ระหว่างองค์กร (เช่น จากผู้รับเหมา -> ไปยังที่ปรึกษา -> ไปยังเจ้าของโครงการ)
## Workflow ระดับ Organization (Circulation): คือ "การแจกจ่าย" เอกสาร ภายในองค์กรของคุณเอง หลังจากที่คุณได้รับเอกสารนั้นมาแล้ว (เช่น เอกสารมาถึง Document Control แล้วต้องส่งต่อให้ใครบ้างในบริษัท)
circulation_templates: ตารางหลักสำหรับเก็บชื่อแม่แบบ
circulation_template_assignees: ตารางสำหรับเก็บ "รายชื่อผู้รับผิดชอบ" ที่ถูกกำหนดไว้ในแต่ละแม่แบบ
Workflow การทำงานใน Frontend
1. หน้า Admin Panel: จะต้องมีเมนูใหม่สำหรับให้ Admin หรือผู้มีสิทธิ์ เข้าไป สร้าง/แก้ไข/ลบ แม่แบบใบเวียน (circulation_templates) สำหรับองค์กรของตนเองได้
2. หน้าที่สร้างใบเวียน (Create Circulation Dialog):
* ที่ด้านบนสุดของฟอร์ม จะมี Dropdown ใหม่ ปรากฏขึ้นมา เขียนว่า "ใช้แม่แบบ (Use Template)"
* ใน Dropdown นี้ จะแสดงรายชื่อแม่แบบทั้งหมดที่องค์กรนั้นๆ สร้างไว้
* เมื่อผู้ใช้เลือกแม่แบบ:
** ระบบจะยิง API ไปดึงรายชื่อผู้รับผิดชอบจากตาราง circulation_template_assignees
** จากนั้น JavaScript จะทำการเติมข้อมูล (Auto-populate) ลงในช่อง "Main", "Action", และ "Information" ให้โดยอัตโนมัติ
* ผู้ใช้ยังสามารถ แก้ไข/เพิ่มเติม/ลบ รายชื่อผู้รับผิดชอบได้ตามต้องการ ก่อนที่จะกดสร้างใบเวียนจริง
การจัดการข้อมูล JSON จะเกิดขึ้นใน 3 ส่วนหลักๆ คือ Backend, Frontend, และ Database ครับ
## 1. การจัดการในฝั่ง Backend (NestJS)
นี่คือส่วนที่ทำหน้าที่หลักในการสร้างและอ่านข้อมูล JSON อย่างเป็นระบบและปลอดภัย
1.1 การแก้ไข Entity
เราจะแก้ไข Correspondence entity โดยเพิ่มคอลัมน์ details เข้าไป และลบ Entity ย่อยๆ ที่ไม่ใช้ออก
src/correspondences/entities/correspondence.entity.ts
@Entity('correspondences')
export class Correspondence {
// ... (คอลัมน์เดิมทั้งหมด: id, document_number, title, etc.)
@Column({
type: 'json', // ◀️ กำหนดประเภทข้อมูลเป็น JSON
nullable: true,
comment: 'เก็บข้อมูลเฉพาะของเอกสารแต่ละประเภทในรูปแบบ JSON'
})
details: any; // ◀️ ใช้ type 'any' หรือสร้าง Interface/Type ที่ซับซ้อนขึ้น
}
1.2 การสร้าง DTOs สำหรับแต่ละประเภทเอกสาร
เพื่อรักษาความถูกต้องของข้อมูล (Validation) เราจะสร้าง DTO แยกสำหรับเอกสารแต่ละประเภท
ตัวอย่าง src/correspondences/dto/create-letter.dto.ts:
TypeScript
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsString } from 'class-validator';
// DTO สำหรับข้อมูลใน details ของ Letter
class LetterDetailsDto {
@ApiProperty()
@IsString()
@IsNotEmpty()
attention_to: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
signatory_name: string;
}
// DTO หลักสำหรับสร้าง Letter
export class CreateLetterDto {
@ApiProperty({ description: "ข้อมูลพื้นฐานของเอกสาร" })
@ValidateNested() // ◀️ บอกให้ class-validator ตรวจสอบ object ข้างในด้วย
@Type(() => CreateCorrespondenceDto) // ◀️ ใช้ DTO พื้นฐานร่วมกัน
base_data: CreateCorrespondenceDto;
@ApiProperty({ description: "ข้อมูลเฉพาะของ Letter" })
@ValidateNested()
@Type(() => LetterDetailsDto)
details: LetterDetailsDto;
}
1.3 การสร้าง API Endpoint และ Logic ใน Service
เราจะสร้าง Endpoint แยกสำหรับสร้างเอกสารแต่ละประเภทเพื่อความชัดเจน
ใน CorrespondencesController:
TypeScript
@Post('letter')
@ApiOperation({ summary: 'Create a new Letter' })
createLetter(@Body() createLetterDto: CreateLetterDto, @Req() req: Request) {
const user = req.user as any;
return this.correspondencesService.createTypedCorrespondence(
createLetterDto.base_data,
createLetterDto.details,
user
);
}
ใน CorrespondencesService:
TypeScript
async createTypedCorrespondence(baseData: CreateCorrespondenceDto, details: any, user: User): Promise<Correspondence> {
// ... (โค้ดตรวจสอบสิทธิ์เหมือนเดิม)
const newCorrespondence = this.correspondenceRepository.create({
...baseData, // ข้อมูลพื้นฐาน (เลขที่เอกสาร, ชื่อเรื่อง, etc.)
details: details, // ◀️ นำ object ของ details มาใส่ในคอลัมน์ JSON โดยตรง
created_by_user_id: user.user_id,
originator_org_id: user.org_id,
status_id: 1, // 'Draft'
});
return this.correspondenceRepository.save(newCorrespondence);
}
## 2. การจัดการในฝั่ง Frontend (Next.js / React)
Frontend จะทำหน้าที่แสดงฟอร์มที่ถูกต้องตามประเภทเอกสาร และส่งข้อมูลในรูปแบบที่ Backend ต้องการ
2.1 การแสดงฟอร์มแบบไดนามิก (Dynamic Forms)
ในหน้า "Create Correspondence" เมื่อผู้ใช้เลือกประเภทเอกสารจาก Dropdown เราจะใช้ State เพื่อแสดงฟอร์มที่ถูกต้อง
TypeScript
const [docType, setDocType] = useState('LETTER');
// ...
const renderDetailFields = () => {
switch (docType) {
case 'LETTER':
return (
<>
{/* ฟิลด์สำหรับ Attention To, Signatory */}
</>
);
case 'RFI':
return (
<>
{/* ฟิลด์สำหรับ Question, Required By Date */}
</>
);
default:
return null;
}
}
return (
<form>
{/* ฟิลด์พื้นฐาน (Document Number, Title) */}
{/* Dropdown เลือกประเภทเอกสาร */}
{renderDetailFields()} {/* ◀️ แสดงฟิลด์เฉพาะทางที่นี่ */}
</form>
);
2.2 การส่งข้อมูล
เมื่อผู้ใช้กด Submit เราจะรวบรวมข้อมูลจากฟอร์มให้เป็นโครงสร้าง JSON ที่ Backend ต้องการ
JavaScript
const handleSubmit = () => {
// รวบรวมข้อมูลพื้นฐาน
const base_data = {
document_number: '...',
title: '...',
// ...
};
// รวบรวมข้อมูลเฉพาะทาง
const details = {
attention_to: '...',
signatory_name: '...',
};
// ส่งข้อมูลไปที่ API Endpoint ที่ถูกต้อง
fetch('/api/correspondences/letter', {
method: 'POST',
body: JSON.stringify({ base_data, details }),
});
}
## 3. การจัดการในระดับฐานข้อมูล (MariaDB)
แม้ว่าเราจะไม่ค่อยได้ Query ข้อมูล JSON โดยตรงผ่าน SQL บ่อยนัก แต่ก็สามารถทำได้เมื่อจำเป็น (เช่น สำหรับการทำรายงานที่ซับซ้อน)
ตัวอย่าง: ค้นหาเอกสาร Letter ทั้งหมดที่ส่งถึง "Mr. John Doe"
SQL
SELECT
corr_id,
document_number,
details
FROM
correspondences
WHERE
type_id = (SELECT type_id FROM correspondence_types WHERE type_code = 'LETTER') -- กรองเฉพาะ Letter
AND JSON_VALUE(details, '$.attention_to') = 'Mr. John Doe'; -- ◀️ ค้นหาค่าใน JSON
การจัดการข้อมูลด้วยวิธีนี้จะทำให้ระบบของคุณมีความ