## 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
การจัดการข้อมูลด้วยวิธีนี้จะทำให้ระบบของคุณมีความ


