260322:1648 Correct Coresspondence / Doing RFA / Correct CI
CI Pipeline / build (push) Failing after 12m41s
Build and Deploy / deploy (push) Failing after 2m44s

This commit is contained in:
admin
2026-03-22 16:48:12 +07:00
parent e5deedb42e
commit 11984bfa29
683 changed files with 105251 additions and 29068 deletions
@@ -48,14 +48,14 @@
### **2.4 ข้อตกลงในการตั้งชื่อ (Naming Conventions)**
| Entity (สิ่งที่ตั้งชื่อ) | Convention (รูปแบบ) | Example (ตัวอย่าง) |
| :-------------------- | :----------------- | :--------------------------------- |
| Classes | PascalCase | UserService |
| Property | snake_case | user_id |
| Variables & Functions | camelCase | getUserInfo |
| Files & Folders | kebab-case | user-service.ts |
| Environment Variables | UPPERCASE | DATABASE_URL |
| Booleans | Verb + Noun | isActive, canDelete, hasPermission |
| Entity (สิ่งที่ตั้งชื่อ) | Convention (รูปแบบ) | Example (ตัวอย่าง) |
| :----------------------- | :------------------ | :--------------------------------- |
| Classes | PascalCase | UserService |
| Property | snake_case | user_id |
| Variables & Functions | camelCase | getUserInfo |
| Files & Folders | kebab-case | user-service.ts |
| Environment Variables | UPPERCASE | DATABASE_URL |
| Booleans | Verb + Noun | isActive, canDelete, hasPermission |
ใช้คำเต็ม — ไม่ใช้อักษรย่อ — ยกเว้นคำมาตรฐาน (เช่น API, URL, req, res, err, ctx)
@@ -504,34 +504,34 @@ export class IdempotencyInterceptor implements NestInterceptor {
### **3.13 เเทคโนโลยีที่ใช้ (Technology Stack)**
| ส่วน | Library/Tool | หมายเหตุ |
| ----------------------- | ---------------------------------------------------- | -------------------------------------- |
| **Framework** | `@nestjs/core`, `@nestjs/common` | Core Framework |
| **Language** | `TypeScript` | ใช้ TypeScript ทั้งระบบ |
| **Database** | `MariaDB 10.11` | ฐานข้อมูลหลัก |
| **ORM** | `@nestjs/typeorm`, `typeorm` | 🗃️จัดการการเชื่อมต่อและ Query ฐานข้อมูล |
| **Validation** | `class-validator`, `class-transformer` | 📦ตรวจสอบและแปลงข้อมูลใน DTO |
| **Auth** | `@nestjs/jwt`, `@nestjs/passport`, `passport-jwt` | 🔐การยืนยันตัวตนด้วย JWT |
| **Authorization** | `casl` | 🔐จัดการสิทธิ์แบบ RBAC |
| **File Upload** | `multer` | 📁จัดการการอัปโหลดไฟล์ |
| **Search** | `@nestjs/elasticsearch` | 🔍สำหรับการค้นหาขั้นสูง |
| **Notification** | `nodemailer` | 📬ส่งอีเมลแจ้งเตือน |
| ส่วน | Library/Tool | หมายเหตุ |
| ----------------------- | ---------------------------------------------------- | -------------------------------------------- |
| **Framework** | `@nestjs/core`, `@nestjs/common` | Core Framework |
| **Language** | `TypeScript` | ใช้ TypeScript ทั้งระบบ |
| **Database** | `MariaDB 10.11` | ฐานข้อมูลหลัก |
| **ORM** | `@nestjs/typeorm`, `typeorm` | 🗃️จัดการการเชื่อมต่อและ Query ฐานข้อมูล |
| **Validation** | `class-validator`, `class-transformer` | 📦ตรวจสอบและแปลงข้อมูลใน DTO |
| **Auth** | `@nestjs/jwt`, `@nestjs/passport`, `passport-jwt` | 🔐การยืนยันตัวตนด้วย JWT |
| **Authorization** | `casl` | 🔐จัดการสิทธิ์แบบ RBAC |
| **File Upload** | `multer` | 📁จัดการการอัปโหลดไฟล์ |
| **Search** | `@nestjs/elasticsearch` | 🔍สำหรับการค้นหาขั้นสูง |
| **Notification** | `nodemailer` | 📬ส่งอีเมลแจ้งเตือน |
| **Scheduling** | `@nestjs/schedule` | 📬สำหรับ Cron Jobs (เช่น แจ้งเตือน Deadline) |
| **Logging** | `winston` | 📊บันทึก Log ที่มีประสิทธิภาพ |
| **Testing** | `@nestjs/testing`, `jest`, `supertest` | 🧪ทดสอบ Unit, Integration และ E2E |
| **Documentation** | `@nestjs/swagger` | 🌐สร้าง API Documentation อัตโนมัติ |
| **Security** | `helmet`, `rate-limiter-flexible` | 🛡️เพิ่มความปลอดภัยให้ API |
| **Resilience** | `@nestjs/circuit-breaker` | 🔄 Circuit breaker pattern |
| **Caching** | `@nestjs/cache-manager`, `cache-manager-redis-store` | 💾 Distributed caching |
| **Security** | `helmet`, `csurf`, `rate-limiter-flexible` | 🛡️ Security enhancements |
| **Validation** | `class-validator`, `class-transformer` | ✅ Input validation |
| **Monitoring** | `@nestjs/monitoring`, `winston` | 📊 Application monitoring |
| **File Processing** | `clamscan` | 🦠 Virus scanning |
| **Cryptography** | `bcrypt`, `crypto` | 🔐 Password hashing และ checksums |
| **JSON Validation** | `ajv`, `ajv-formats` | 🎯 JSON schema validation |
| **JSON Processing** | `jsonpath`, `json-schema-ref-parser` | 🔧 JSON manipulation |
| **Data Transformation** | `class-transformer` | 🔄 Object transformation |
| **Compression** | `compression` | 📦 JSON compression |
| **Logging** | `winston` | 📊บันทึก Log ที่มีประสิทธิภาพ |
| **Testing** | `@nestjs/testing`, `jest`, `supertest` | 🧪ทดสอบ Unit, Integration และ E2E |
| **Documentation** | `@nestjs/swagger` | 🌐สร้าง API Documentation อัตโนมัติ |
| **Security** | `helmet`, `rate-limiter-flexible` | 🛡️เพิ่มความปลอดภัยให้ API |
| **Resilience** | `@nestjs/circuit-breaker` | 🔄 Circuit breaker pattern |
| **Caching** | `@nestjs/cache-manager`, `cache-manager-redis-store` | 💾 Distributed caching |
| **Security** | `helmet`, `csurf`, `rate-limiter-flexible` | 🛡️ Security enhancements |
| **Validation** | `class-validator`, `class-transformer` | ✅ Input validation |
| **Monitoring** | `@nestjs/monitoring`, `winston` | 📊 Application monitoring |
| **File Processing** | `clamscan` | 🦠 Virus scanning |
| **Cryptography** | `bcrypt`, `crypto` | 🔐 Password hashing และ checksums |
| **JSON Validation** | `ajv`, `ajv-formats` | 🎯 JSON schema validation |
| **JSON Processing** | `jsonpath`, `json-schema-ref-parser` | 🔧 JSON manipulation |
| **Data Transformation** | `class-transformer` | 🔄 Object transformation |
| **Compression** | `compression` | 📦 JSON compression |
### **3.14 Security Testing:**
@@ -587,13 +587,11 @@ Backend (NestJS) ควรเป็น **Stateless** (ไม่เก็บส
1. User สร้างเอกสาร → เลือก routing template
2. System สร้าง routing instances ตาม template
3. สำหรับแต่ละ routing step:
- กำหนด due date (จาก expected_days)
- ส่ง notification ไปยังองค์กรผู้รับ
- อัพเดทสถานะเป็น SENT
4. เมื่อองค์กรผู้รับดำเนินการ:
- อัพเดทสถานะเป็น ACTIONED/FORWARDED/REPLIED
- บันทึก processed_by และ processed_at
- ส่ง notification ไปยังขั้นตอนต่อไป (ถ้ามี)
@@ -730,24 +728,20 @@ export function DynamicForm({ schemaName, onSubmit }: DynamicFormProps) {
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
{Object.entries(schema.schema_definition.properties).map(
([key, prop]: [string, any]) => (
<FormField
key={key}
control={form.control}
name={key}
render={({ field }) => (
<FormItem>
<FormLabel>{prop.title || key}</FormLabel>
<FormControl>
{renderFieldByType(prop.type, field)}
</FormControl>
<FormMessage />
</FormItem>
)}
/>
)
)}
{Object.entries(schema.schema_definition.properties).map(([key, prop]: [string, any]) => (
<FormField
key={key}
control={form.control}
name={key}
render={({ field }) => (
<FormItem>
<FormLabel>{prop.title || key}</FormLabel>
<FormControl>{renderFieldByType(prop.type, field)}</FormControl>
<FormMessage />
</FormItem>
)}
/>
))}
<Button type="submit"></Button>
</form>
</Form>
@@ -808,9 +802,7 @@ export function ResponsiveTable({ data }: { data: Correspondence[] }) {
<Card key={item.id}>
<CardContent className="pt-6">
<div className="space-y-2">
<div className="text-sm text-muted-foreground">
</div>
<div className="text-sm text-muted-foreground"></div>
<div className="font-medium">{item.doc_number}</div>
<div className="text-sm text-muted-foreground"></div>
<div>{item.title}</div>
@@ -933,10 +925,7 @@ export function useCreateCorrespondence() {
await queryClient.cancelQueries({ queryKey: ['correspondences'] });
const previous = queryClient.getQueryData(['correspondences']);
queryClient.setQueryData(['correspondences'], (old: any) => [
...old,
newCorrespondence,
]);
queryClient.setQueryData(['correspondences'], (old: any) => [...old, newCorrespondence]);
return { previous };
},
@@ -1100,24 +1089,17 @@ export function FileUploadZone({
className={`
border-2 border-dashed rounded-lg p-8 text-center cursor-pointer
transition-colors
${
isDragActive
? 'border-primary bg-primary/5'
: 'border-muted-foreground/25'
}
${isDragActive ? 'border-primary bg-primary/5' : 'border-muted-foreground/25'}
hover:border-primary hover:bg-primary/5
`}
>
<input {...getInputProps()} />
<Upload className="mx-auto h-12 w-12 text-muted-foreground" />
<p className="mt-2 text-sm text-muted-foreground">
{isDragActive
? 'วางไฟล์ที่นี่...'
: 'ลากไฟล์มาวางที่นี่ หรือคลิกเพื่อเลือกไฟล์'}
{isDragActive ? 'วางไฟล์ที่นี่...' : 'ลากไฟล์มาวางที่นี่ หรือคลิกเพื่อเลือกไฟล์'}
</p>
<p className="mt-1 text-xs text-muted-foreground">
: {acceptedTypes.join(', ')} ( {maxFiles} ,{' '}
{maxSize / 1024 / 1024}MB/)
: {acceptedTypes.join(', ')} ( {maxFiles} , {maxSize / 1024 / 1024}MB/)
</p>
</div>
);
@@ -1198,15 +1180,15 @@ updateRFA(@Param('id') id: string) {
## 🔗 **7. แนวทางการบูรณาการ Full Stack (Full Stack Integration Guidelines)**
| Aspect (แง่มุม) | Backend (NestJS) | Frontend (NextJS) | UI Layer (Tailwind/Shadcn) |
| :----------------------- | :------------------------- | :---------------------------- | :------------------------------------- |
| API | REST / GraphQL Controllers | API hooks ผ่าน fetch/axios/SWR | Components ที่รับข้อมูล |
| Validation (การตรวจสอบ) | class-validator DTOs | zod / react-hook-form | สถานะของฟอร์ม/input ใน Shadcn |
| Auth (การยืนยันตัวตน) | Guards, JWT | NextAuth / cookies | สถานะ UI ของ Auth (loading, signed in) |
| Errors (ข้อผิดพลาด) | Global filters | Toasts / modals | Alerts / ข้อความ feedback |
| Testing (การทดสอบ) | Jest (unit/e2e) | Vitest / Playwright | Visual regression |
| Styles (สไตล์) | Scoped modules (ถ้าจำเป็น) | Tailwind / Shadcn | Tailwind utilities |
| Accessibility (การเข้าถึง) | Guards + filters | ARIA attributes | Semantic HTML |
| Aspect (แง่มุม) | Backend (NestJS) | Frontend (NextJS) | UI Layer (Tailwind/Shadcn) |
| :------------------------- | :------------------------- | :----------------------------- | :------------------------------------- |
| API | REST / GraphQL Controllers | API hooks ผ่าน fetch/axios/SWR | Components ที่รับข้อมูล |
| Validation (การตรวจสอบ) | class-validator DTOs | zod / react-hook-form | สถานะของฟอร์ม/input ใน Shadcn |
| Auth (การยืนยันตัวตน) | Guards, JWT | NextAuth / cookies | สถานะ UI ของ Auth (loading, signed in) |
| Errors (ข้อผิดพลาด) | Global filters | Toasts / modals | Alerts / ข้อความ feedback |
| Testing (การทดสอบ) | Jest (unit/e2e) | Vitest / Playwright | Visual regression |
| Styles (สไตล์) | Scoped modules (ถ้าจำเป็น) | Tailwind / Shadcn | Tailwind utilities |
| Accessibility (การเข้าถึง) | Guards + filters | ARIA attributes | Semantic HTML |
## 🗂️ **8. ข้อตกลงเฉพาะสำหรับ DMS (LCBP3-DMS)**
@@ -1216,17 +1198,17 @@ updateRFA(@Param('id') id: string) {
บันทึกการดำเนินการ CRUD และการจับคู่ทั้งหมดลงในตาราง audit_logs
| Field (ฟิลด์) | Type (จาก SQL) | Description (คำอธิบาย) |
| :----------- | :------------- | :----------------------------------------------- |
| audit_id | BIGINT | Primary Key |
| user_id | INT | ผู้ใช้ที่ดำเนินการ (FK -> users) |
| action | VARCHAR(100) | rfa.create, correspondence.update, login.success |
| entity_type | VARCHAR(50) | ชื่อตาราง/โมดูล เช่น 'rfa', 'correspondence' |
| entity_id | VARCHAR(50) | Primary ID ของระเบียนที่ได้รับผลกระทบ |
| details_json | JSON | ข้อมูลบริบท (เช่น ฟิลด์ที่มีการเปลี่ยนแปลง) |
| ip_address | VARCHAR(45) | IP address ของผู้ดำเนินการ |
| user_agent | VARCHAR(255) | User Agent ของผู้ดำเนินการ |
| created_at | TIMESTAMP | Timestamp (UTC) |
| Field (ฟิลด์) | Type (จาก SQL) | Description (คำอธิบาย) |
| :------------ | :------------- | :----------------------------------------------- |
| audit_id | BIGINT | Primary Key |
| user_id | INT | ผู้ใช้ที่ดำเนินการ (FK -> users) |
| action | VARCHAR(100) | rfa.create, correspondence.update, login.success |
| entity_type | VARCHAR(50) | ชื่อตาราง/โมดูล เช่น 'rfa', 'correspondence' |
| entity_id | VARCHAR(50) | Primary ID ของระเบียนที่ได้รับผลกระทบ |
| details_json | JSON | ข้อมูลบริบท (เช่น ฟิลด์ที่มีการเปลี่ยนแปลง) |
| ip_address | VARCHAR(45) | IP address ของผู้ดำเนินการ |
| user_agent | VARCHAR(255) | User Agent ของผู้ดำเนินการ |
| created_at | TIMESTAMP | Timestamp (UTC) |
### 📂**8.2 การจัดการไฟล์ (File Handling)**