ข้ามไปที่เนื้อหา

S4 — eMediation (ระบบไกล่เกลี่ยข้อพิพาท) — Target Schema (Phase 2)

TARGET DESIGN — เป็น DELTA ต่อยอด schema จริง ไม่ใช่ greenfield

S4 เป็น ระบบปรับปรุง (Improvement) ไม่ใช่ระบบใหม่ — schema MEDIATE มีอยู่จริงบน PSDBPRDDB (95 ตาราง cms_* / 1,911 คอลัมน์ + ข้อมูลจริง cms_mediation 12K–55K เคส) · งานนี้ = ต่อเติม mockup ใหม่บนของเดิม (เหมือน S8/S9 ไม่ใช่ S1/S2/S3) · de-facto UI contract = repos/emediation/fe branch mockup (React/Vite) · 📋 Changes vs Current · DDL DELTA: schema.sql · ERD · Data Dictionary · 🛠️ Backend Implementation · live baseline (as-is): ../../s4_mediation/

ทำไมเป็น DELTA (ต่อเติม) ไม่ใช่ออกแบบใหม่ทั้งชุด

ระบบ V1 (PHP/CI, .41) + V2 (Node/Vue, .87) รวมเป็น schema MEDIATE เดียวบน PSDBPRDDB แล้ว (migrated_to_single_db ✅) — ตาราง cms_* ครอบคลุมงานหลักครบ (เคส/ผู้ไกล่เกลี่ย/ศูนย์/อบรม/ค่าตอบแทน) งานนี้จึงเก็บของเดิม as-is แล้วเติมเฉพาะส่วนที่ mockup ใหม่ต้องการ:

  • REUSE (95 ตาราง)cms_mediation, cms_mediator_*, cms_people_center*, cms_training_*, cms_compensation_*, cms_master_*, cms_users/cms_user_role/cms_user_permission/cms_menu ฯลฯ ใช้ตามเดิม
  • MODIFY (7 กลุ่ม ALTER) — เพิ่มคอลัมน์ฟีเจอร์ใหม่ (2-round signup, ad-hoc role, auto-terminate counter, weighted assessment, draft→publish, eSign) ลงตารางเดิม
  • NEW (29 ตาราง) — สิ่งที่ของเดิมไม่มีเลย: Workflow Engine (9), คณะกรรมการประเมินศูนย์ (3), คลังข้อสอบ/ชุดข้อสอบ (3), ประเมินวิทยากร master (2), Template เอกสาร (1), เบิกค่าจัดกระบวนการ (2), องค์กรต้นแบบ/รางวัล (2), เชื่อมต่อระบบภายนอก (1), ไกล่เกลี่ยออนไลน์/Webex/eSign (5, ยกจาก V2), ตรวจสอบระบบ (1)

S4 PK/naming ตามของจริง MEDIATE (ต่างจาก S1/S2/S3 โดยตั้งใจ)

S1/S2/S3 เป็น greenfield → PascalCase (Province/ConsultationRequest) · S4 ต่อยอดของจริง จึงคงแบบ live เป๊ะ: cms_* snake_case · PK [table]_id int IDENTITY · audit septet created_at/by/ip + updated_at/by/ip + status/highlight/orderid · ไฟล์ = *_ext · ตาราง NEW เพิ่ม FK + CHECK (ของเดิม MEDIATE มี 0 FK / 0 SP — logic อยู่ที่แอป) เพื่อ integrity ฟีเจอร์ใหม่

Stack & Architecture (จาก SRS §2 + repo จริง)

ส่วน เทคโนโลยี
Backend JavaScript / NestJS / RESTful API — repo repos/emediation/be (สร้างใหม่ทับ V2)
Frontend Responsive Web (Desktop/Tablet/Mobile) — mockup repos/emediation/fe branch mockup
Database MS SQL Server 2022 — schema MEDIATE บน PSDBPRDDB (10.136.27.149:3412)
Auth ThaiD (Digital ID) หลัก + Keycloak SSO (RBAC 8 บทบาท, OAuth 2.0)
Integration ThaID · eSign (ETDA) · K-COP/KTB Corp (เบิกจ่าย) · ศาล/ตำรวจ (อนาคต) — toggle ได้ (REQ-008)
Observability NestJS ใช้ไลบรารีกลาง @rlpdjs/observability (logger/trace/metrics/DB query log)

ความสัมพันธ์กับ repo rlpdjs

rlpdjs = แพ็กเกจ @rlpdjs/observability (ไลบรารี NestJS ใช้ร่วม) — ไม่ใช่ backend ของ S4 Prisma stub ของมันตั้ง provider postgresql เพื่อ type-gen ของไลบรารีเท่านั้น → backend S4 (emediation/be) install @rlpdjs/observability เป็น dependency แล้วตั้ง Prisma datasource ของตัวเองเป็น sqlserver ชี้ schema MEDIATE · ดู implementation.md

Role Hierarchy (mockup core.jsx ROLE_OPTIONS — 8 บทบาท)

Role Code บทบาท สิทธิ์โดยสรุป
ADMIN ผู้ดูแลระบบ จัดการผู้ใช้/สิทธิ์ + Workflow Engine + ข้ามขั้นตอน + Master/Audit
DIRECTOR อธิบดี/รองอธิบดี อนุมัติสูงสุด (สาย 7 ระดับ) + Dashboard ผู้บริหาร
REGISTRAR นายทะเบียน รับรอง/ไม่รับรองผล + ส่งกลับ (ไกล่เกลี่ย/ทะเบียน/ศูนย์)
OFFICER_HEAD ผอ.กอง/หัวหน้ากลุ่ม อนุมัติขั้น Workflow + ตั้งคณะกรรมการประเมิน
OFFICER เจ้าหน้าที่ ตรวจคำร้อง + แต่งตั้งผู้ไกล่เกลี่ย + จัดทำเอกสาร (scope = จังหวัด)
EVAL_COMMITTEE คณะกรรมการประเมินศูนย์ ให้คะแนนรายบุคคล (role พิเศษ/เฉพาะกิจ)
MEDIATOR ผู้ไกล่เกลี่ย พอร์ทัลสมาชิก: ตอบรับ/ไกล่เกลี่ย/เบิกค่าตอบแทน
CITIZEN ผู้ร้อง/คู่กรณี บริการประชาชน: ยื่นคำร้อง/ติดตาม/eSign

RBAC อยู่ในตารางเดิม — REQ-007 = MODIFY ไม่ใช่ NEW

live มี cms_user_role + cms_user_permission (action_listing/view/edit/delete/publish/highlight ราย menu × role) + cms_menu/cms_menu_group อยู่แล้ว = permission matrix ครบ · งานนี้แค่เติม kind (ระบบ/เฉพาะกิจ) + base_role_id (clone) + note ลง cms_user_role

🔐 ผู้ใช้ทุกคน Login ผ่าน SSO (ไม่เก็บ password ในระบบ) — design_p2 D8

AuthN รวมศูนย์ที่ Keycloak SSO (realm rlpd federate AD) + ThaiD สำหรับประชาชน/ผู้ไกล่เกลี่ย · cms_users = thin mirror ของ SSO (auto-provision ตอน login ครั้งแรก, อ่าน role จาก JWT) → เลิกใช้ คอลัมน์ password/LDAP เดิม (ทั้ง MSSQL cms_users และ MySQL users.password/dn) · AuthZ = cms_user_role/cms_user_permission → sync เป็น Keycloak client roles · บทบาทกลาง = S9 Web Portal · ถ้าลูกค้ายืนยันต้องมี local fallback → เพิ่ม LoginAttempt/lockout ภายหลัง (OPEN-AUTH)

🔑 Requirement → Table Traceability (spine)

ทุก REQ-MED-001…017 มีแถว — map ไปตาราง REUSE / MODIFY / NEW หรือระบุว่าไม่มีผลต่อ schema

REQ TOR สาระสำคัญ ตารางที่รองรับ (R=reuse · M=modify · N=new)
REQ-MED-001 7.14.1 จัดการหลักสูตร + ข้อสอบสุ่ม/auto-grade + เช็คชื่อ + ประเมินวิทยากร + ประกาศนียบัตร R cms_training_topic,cms_training_register,cms_training_management_checkin/score/result,cms_training_certificate,cms_training_management_rate · N cms_exam_question,cms_exam,cms_exam_attempt,cms_trainer_eval_category,cms_trainer_eval_subject
REQ-MED-002 7.14.1 ขึ้นทะเบียน/ต่ออายุ/แก้ไข/สิ้นสภาพผู้ไกล่เกลี่ย + ≤3 สังกัด + bookbank/K-COP R cms_mediator_applicant,cms_mediator_registra,cms_mediator_appointment,cms_mediator_cert,cms_mediator_request_edit,cms_mediator_ending(_item),cms_mediator_portfolio,cms_member,cms_profile_ktbcorp*
REQ-MED-003 7.14.2 ขึ้นทะเบียนศูนย์ภาคประชาชน + คณะทำงาน 5 ตำแหน่ง + กฎเลขบัตรไม่ซ้ำ R cms_people_center,cms_people_center_participant,cms_master_center_position,cms_institute_mediation(_category)
REQ-MED-004 7.14.2 อนุมัติ + ประเมินศูนย์ (น้ำหนัก 4 ด้าน) + คณะกรรมการประเมิน + ใบรับรองรายปี R cms_people_center_assessment(_detail/_result),cms_master_assessment* · M cms_master_assessment_category(+weight) · N cms_assessment_committee,cms_assessment_committee_member,cms_assessment_committee_role
REQ-MED-005 7.14.3 ดำเนินการไกล่เกลี่ย + คู่กรณีหลายฝ่าย + นัดหมาย + รายงาน 1–4 + ข้อตกลง eSign + ไกล่เกลี่ยออนไลน์ (Webex) + eKYC R cms_mediation,cms_mediation_mediator/witness/docs/books/pdf,cms_mediation_booking*,cms_master_civil_dispute · M cms_mediation(+all_parties_replied_date),cms_mediation_books(+eSign) · N cms_online_meeting,cms_meeting_attendance,cms_meeting_signature,cms_meeting_report,cms_webex_auth (migrate จาก V2)
REQ-MED-006 7.14.3 รับรองผล (รับรอง/ไม่รับรอง/ส่งกลับ) + เบิกค่าตอบแทน (matrix เดินทาง) R cms_compensation_main/history/requisition_form/payment_receipt/files,cms_mediation_compensation(_rate),cms_comment_certificate,cms_compensation_certification_payment
REQ-MED-007 7.14.4 Workflow Engine (สาย 7 ระดับ, skip มีเหตุผล) + จัดการสิทธิ์ + มอบอำนาจ + audit N cms_wf_approval_level,cms_wf_request_type,cms_wf_definition,cms_wf_step,cms_wf_instance,cms_wf_instance_step,cms_wf_task,cms_wf_delegation,cms_wf_audit · M cms_user_role(+kind/base_role/note) · R cms_user_permission,cms_menu · N cms_system_audit (ตรวจสอบระบบ)
REQ-MED-008 7.14.4 เชื่อมต่อ ThaID + eSign + K-COP + ศาล/ตำรวจ + เปิด/ปิดราย integration + authoring N cms_integration_setting · M cms_news(+publish_state),cms_people_center_announcement(+publish_state) · R cms_news,cms_setting
REQ-MED-009 Dashboard ภาพรวม (ราย จังหวัด/ปีงบ) aggregate queries / views บนตารางจริง — ไม่มีตารางใหม่ (รายงานเป็น view)
REQ-MED-010 ยุติศูนย์ภาคประชาชนอัตโนมัติ (ไม่ผ่านประเมิน 2 ปีติด) M cms_people_center(+consecutive_fails) · N cms_wf_instance (สายยุติศูนย์)
REQ-MED-011 สร้าง Template เอกสารแบบ Dynamic (ตัวแปร {ชื่อ}/{ศูนย์}/{วันที่}) N cms_document_template · R cms_master_document_type
REQ-MED-012 แจ้งเตือนทะเบียน/วาระใกล้หมดอายุ (90 วัน) R cms_notify,cms_mediator_registra,cms_mediator_appointmentเงื่อนไข = scheduled job (app)
REQ-MED-013 ปรับ UX สมัครอบรม/ขึ้นทะเบียน (2 รอบ + ตรวจตน เลขบัตร+วันเกิด) M cms_training_register(+stage/pre_member_no/selection_result)
REQ-MED-014 แก้รหัสอ้างอิงเอกสาร + bug ระบบเดิม + กู้รูปที่หาย (V1→V2) R cms_setting (format เลขที่), cms_master_editinfoแก้ที่ logic/migration ไม่ใช่ schema
REQ-MED-015 เบิกค่าจัดกระบวนการไกล่เกลี่ยของศูนย์ (รายการ + ใบเสร็จ + สาย 7 ระดับ) N cms_center_process_cost,cms_center_process_cost_item · R cms_wf_instance
REQ-MED-016 ประเมินองค์กรต้นแบบ + รางวัล (เกณฑ์รายปีงบรวม 100% + QR cert) N cms_award_criteria,cms_center_award · M cms_people_center(+is_model_org)
REQ-MED-017 จัดเก็บผลงานศูนย์ (รายปีงบ + sync จาก REQ-005 + รายงาน PDF/Excel) R cms_people_center_report,cms_people_center_result(_item),cms_people_center_highlight,cms_master_performance
Auth §3 SSO ทุกผู้ใช้ (Keycloak+ThaiD) + RBAC 8 บทบาท — thin mirror ไม่เก็บ password R cms_users (thin mirror, เลิก password/LDAP),cms_user_role (+kind),cms_user_permission,cms_menu — อ่าน role จาก JWT

REQ ที่ไม่มีผลต่อ schema (จัดการที่ app/infra layer)

  • REQ-MED-009 — Dashboard = aggregate query/ view บนตารางจริง (filter จังหวัด/ปีงบ) ไม่ต้องมีตารางเก็บ
  • REQ-MED-012 — เกณฑ์ "ใกล้หมดอายุ 90 วัน" = scheduled job เทียบ expiry/registra date → เขียน cms_notify (ตารางเดิม)
  • REQ-MED-014 — แก้ format เลขที่เอกสาร + bug + กู้ไฟล์รูป = งาน migration/logic ; schema เดิมรองรับ (cms_setting)
  • NFR ทั้งหมด — PDPA/AES-256 at-rest (PII: idcard/bank/signature), TLS 1.2+, lockout 5 ครั้ง, ไฟล์ ≤10–50MB = infra/app + central SSO

Table Inventory — DELTA (29 NEW, schema MEDIATE)

กลุ่ม ตาราง NEW REQ
Workflow Engine (9) cms_wf_approval_level, cms_wf_request_type, cms_wf_definition, cms_wf_step, cms_wf_instance, cms_wf_instance_step, cms_wf_task, cms_wf_delegation, cms_wf_audit (append-only) 007
Assessment Committee (3) cms_assessment_committee, cms_assessment_committee_member, cms_assessment_committee_role (master) 004
Exam / Question Bank (3) cms_exam_question, cms_exam, cms_exam_attempt (migrate จาก V2 exams/questions) 001
Trainer Eval master (2) cms_trainer_eval_category, cms_trainer_eval_subject 001
Document Template (1) cms_document_template 011
Center Process Cost (2) cms_center_process_cost, cms_center_process_cost_item 015
Award / Model Org (2) cms_award_criteria, cms_center_award 016
Integration (1) cms_integration_setting 008
Online Mediation / Webex (5) cms_online_meeting, cms_meeting_attendance (+eKYC), cms_meeting_signature (eSign), cms_meeting_report, cms_webex_authmigrate จาก V2 MySQL (ดู validation) 005
System Audit (1) cms_system_audit (append-only — backing จอ system_audit + NFR audit trail) 007

✅ V2 source validation (SSH 10.136.27.87 — 2026-06-17)

ตรวจ source จริง mediation-backend2025 (active, Webify Phase-1) แล้ว ยืนยัน/แก้ไขดังนี้:

  • สถาปัตยกรรม dual-DB — V2 ใช้ 2 ฐาน: (1) MSSQL cms_* (MEDIATE) ผ่าน generic API /mssql/:table (getall/get/join/add/update/... + uploadSignature/uploadPDF/updateEvidence/updateDocMoney) → ตรงกับที่ mockup เรียกตาราง cms_* ตรง ๆ ; (2) MySQL Sequelize (mediation@localhost:3306) ผ่าน /model/:model เก็บ subsystem Phase-1: meetings(Webex), meetingAttendances(eKYC), signatures/signs(eSign BLOB), webex_auths, meetingReports, meeting_memos, exams/questions, trainings(+webex+exam_id), registers, trainingAttendances, mediationsetting
  • GAP ที่พบ → เพิ่มแล้ว (A9) — ระบบ ไกล่เกลี่ยออนไลน์ Webex + eKYC + eSign ไม่อยู่ใน cms_* MSSQL (อยู่ใน MySQL) · design เดิมตกหล่น → เพิ่ม 5 ตาราง A9 ให้ V3 รวมฐานเดียว "ทำงานเหมือนเดิม"
  • ยืนยัน examexams/questions ของ V2 มีจริง → cms_exam* คือปลายทาง migrate (map column ใน schema.sql §A3) ไม่ใช่ของใหม่ล้วน
  • ยืนยัน binary cols — endpoint updateEvidence/updateDocMoney/uploadPDF ยืนยัน varbinary evidence/doc_money/certificate ใน cms_mediation (ตรง recon)

MODIFY (ALTER) — 7 กลุ่ม: cms_training_register (013) · cms_user_role (007) · cms_people_center (010/016) · cms_master_assessment_category (004) · cms_news + cms_people_center_announcement (008) · cms_mediation (005) · cms_mediation_books (005)

Mockup → Target mapping (รองรับ frontend)

mockup fe/src/data/*.jsx 7 ไฟล์ → ตารางจริง (ส่วนใหญ่ map ตรงตาราง cms_* เดิม)

Mockup export (ไฟล์) Target (MEDIATE) หมายเหตุ
CASES (mediation.jsx) cms_mediation (R) petitioner/litigant/contact = คอลัมน์เดิม ; all_parties_replied_date เพิ่ม (M)
SESSIONS/AGREEMENTS (mediation.jsx) cms_mediation_docs/cms_mediation_books (R+M) รายงาน 1–4 = docs ; ข้อตกลงครั้งที่ 5 = books + eSign (sign_method/manual_sign_json)
MEDIATOR_APPLICANTS/MEDIATORS/APPOINTMENTS (mediators.jsx) cms_mediator_applicant/cms_mediator_registra/cms_mediator_appointment (R) eligibility/affiliations = คอลัมน์/ตารางเดิม (cms_mediator_applicant_item)
COMPENSATION_CLAIMS/KTB_BOOKBANK (mediators/masters) cms_compensation_main+cms_profile_ktbcorp* (R) 10 สถานะ map คอลัมน์ status เดิม
CENTERS/PARTICIPANTS/ASSESSMENTS (centers.jsx) cms_people_center/_participant/_assessment* (R) committeeScores → cms_people_center_assessment_detail ; consecutive_fails เพิ่ม (M)
ASSESSMENT_COMMITTEES/_ROLES (centers.jsx) cms_assessment_committee(_member/_role) (N) คณะเฉพาะกิจรายศูนย์×ปี — ของเดิมไม่มี
CENTER_CERT_HISTORY (centers.jsx) cms_people_center_result (R) ใบรับรองรายปี "ไม่ทับปีเก่า"
COURSES/REGISTRATIONS/CHECKINS/CERTS (training.jsx) cms_training_topic/cms_training_register/_checkin/cms_training_certificate (R+M) stage/pre_member_no/selection_result เพิ่ม (M, REQ-013)
EXAM_QUESTIONS/EXAMS/EXAM_ATTEMPTS (training.jsx) cms_exam_question/cms_exam/cms_exam_attempt (N) คลังข้อสอบ/สุ่ม/auto-grade — Phase-3 CMS ใหม่
TRAINER_EVAL* (training.jsx) cms_training_management_rate (R) + cms_trainer_eval_category/subject (N) 5 หมวด 11 วิชา = master ใหม่ ; คะแนน = rate เดิม
WORKFLOW_DEFINITIONS/_INSTANCES/TASKS/DELEGATIONS/AUDIT/APPROVAL_CHAIN_7/REQUEST_TYPES (workflow.jsx) cms_wf_* (N, 9 ตาราง) Workflow Engine ทั้งชุด — ของเดิมไม่มี
USERS/USER_ROLES/USER_LOGS (masters.jsx) cms_users/cms_user_role/cms_user_logs (R+M) USER_ROLES.kind/permscms_user_role(+kind) + cms_user_permission เดิม
จอ system_audit (crud.jsx — ไม่มี data export) cms_system_audit (N) audit รวม module/target/result — ของเดิม cms_user_logs บางเกินไป
INTEGRATION_SETTINGS (masters.jsx) cms_integration_setting (N) toggle ราย integration
WEBSITE_NEWS/PUBLIC_DOCUMENTS/COMPLAINTS (masters.jsx) cms_news/cms_complaint (R+M) publish_state/scheduled_at เพิ่ม (M, REQ-008) ; public docs → cms_news (type=คู่มือ/กฎหมาย)
MASTER_*/INSTITUTES (masters.jsx) cms_master_*/cms_institute_* (R) weight/indicators เพิ่มใน assessment_category (M)
REPORT_* (masters.jsx) views (R underlying) รายงาน = aggregate ไม่ใช่ตารางเก็บ

สิ่งที่ "ตัดออก" ไม่ยกเป็นตาราง: STATUSES palette (สี = presentation), NAV/ROLE_NAV (routing — ได้จาก cms_menu + role ใน JWT), REQ_ITEMS/fmtThaiDate (utility/registry ฝั่ง UI)

ประเด็นที่ต้อง align กับลูกค้า (OPEN)

Tag ประเด็น สถานะ / แนวทางในเอกสารนี้
[OPEN-EXPERTISE] SRS v4.0.0 ระบุ ตัด ฟิลด์ "ความเชี่ยวชาญ" (expertise) แต่ mockup ยังมี expertises[] + ตารางเดิม cms_master_expertise เอกสารนี้ คงตารางเดิม ไว้ (ยังไม่ลบ) แต่ไม่บังคับใช้ใน flow ใหม่ · รอลูกค้ายืนยันว่าตัดถาวรหรือไม่ → ถ้าตัด = เลิก map ใน UI (ไม่ drop ตารางเพื่อกันข้อมูลเดิมหาย)
[OPEN-NAMING] ของจริงใช้ cms_* snake_case + 0 FK ; design_p2 อื่น (S1/S2/S3) ใช้ PascalCase + FK ครบ เลือกตาม ของจริง as-is (snake_case) เพราะต่อยอด ; ตาราง NEW เพิ่ม FK/CHECK เป็น improvement · ถ้าทีมต้องการ uniform PascalCase ทั้ง DB = งาน refactor แยก (กระทบ V2 app เดิม)
[OPEN-FK-LEGACY] ตาราง legacy บางตัวอาจไม่มี PRIMARY KEY constraint จริง → FK จากตาราง NEW ชี้ไปไม่ได้ FK ภายในกลุ่ม NEW ประกาศครบใน schema.sql §C ; FK ที่ชี้ legacy (cms_people_center/cms_training_topic/cms_mediation/cms_users/cms_geo_province) comment ไว้ "verify before enable" — ตรวจ PK ปลายทางจาก schema.json ก่อน apply
[OPEN-DEDUP] live มีตาราง *_copy1 (cms_mediation_copy1, cms_mediator_applicant_copy1) = สำเนา/ขยะจาก migration ไม่ใช้/ไม่อ้างใน design นี้ — แนะนำ drop หลังยืนยันว่าไม่มี dependency (REQ-014 cleanup)
[DECIDED-SINGLE-DB] V2 มี MySQL แยก (mediation@3306, Sequelize) เก็บ online mediation/Webex/eSign — ยังใช้งานจริง (probe 2026-06-17) ตัดสินใจแล้ว: ย้าย MySQL เข้า single DB PSDBPRDDB/MEDIATE ให้หมด (ไม่เหลือ dual-DB) → ตาราง A9 (5) + cms_exam* รับ active subsystem ; mapping ครบ 21 ตาราง MySQL ดู implementation §5 · live MySQL ปัจจุบัน document ที่ ../../s4_mediation/online_mysql.md
[OPEN-COMP-MATRIX] matrix ค่าเดินทาง (ภาครัฐ/ประชาชน × ในเขต/นอกเขต) ใน SRS REQ-002 เก็บใน cms_mediation_compensation_rate เดิม + logic ที่ service — รอยืนยันอัตราจริง
[OPEN-DB] SRS §5 เคยระบุ DB เฉพาะของ eMediation แต่ design_p2 D1 = Single DB PSDBPRDDB ตาม design_p2 — schema MEDIATE ใน PSDBPRDDB (migrated แล้วตาม live docs)
[AUTH-SSO] V2 มี auth 3 แบบปน: local password (comment ออกแล้ว), LDAP (ldapController→AD .15:389, last login มิ.ย. 2025, users.dn แค่ 17/121 — legacy แทบตาย), SSO (ssoController + .env API_SSO_URL, Bearer JWT — active เป็นหลักแล้ว) V3 = SSO อย่างเดียว (Keycloak federate AD + ThaiD) ต่อยอดจากที่ V2 ทำไว้ — ตัด LDAP + local ทิ้ง · cms_users = thin mirror ไม่มี password/lockout · ถ้าลูกค้ายืนยันต้อง local fallback → เพิ่ม cms_login_attempt ภายหลัง (NFR lockout 5 ครั้ง)