hrms-api-org/plans/plan_cleanup-mock-seed.md

16 KiB
Raw Blame History

Plan + สรุปตาราง + Drop Script — Cleanup & Mock Seed hrms_organization

ไฟล์เดียวจบ: Part A สรุปตาราง DB · Part B plan checklist (CP0-CP7) · Part C drop script SQL Status: CP0-CP6 done (drop 54 tables + seed mock org/pos/profile) · CP7 (Keycloak) defer Seed mock: แยกที่ src/seed/npm run seed:run (ไม่กระทบ migration:run หลัก) วิธีใช้: เช็ค - [x] ทีละขั้น, ทุก CP destructive ต้องแจ้ง user ก่อน + รอยืนยัน (DB test 192.168.1.68 เท่านั้น)


Part A — สรุปตาราง DB

รายการ ค่า
Database hrms_organization (MySQL 8.4.6)
Host test 192.168.1.68 / prod 192.168.1.63 (ห้ามแตะ prod)
รวมตาราง 211 → 157 (drop 54 แล้ว @ test)

สถานะการใช้งาน:

สถานะ จำนวน รายละเอียด
ใช้งานจริง (เก็บไว้) 147 ข้อมูลธุรกิจหลัก + Master Data + ตารางเสริมที่มี controller
🗑️ เตรียมลบ/ลบแล้ว 54 ดู §5
⚙️ ระบบ/ตัวเชื่อม 10 junction + system tables
รวม 211

A.1 ข้อมูลหลัก

กลุ่ม ตัวอย่างตาราง
โครงสร้างองค์กร orgRoot, orgChild1orgChild4, orgRevision
ประวัติพนักงาน profile, profileEmployee, profileSalary, profile* + *History
ตำแหน่ง/อัตรากำลัง position, posMaster, posMasterHistory, employeePosition
คำสั่ง command, commandSend, commandRecive, commandOperator
สิทธิ์/การเข้าถึง authRole, permissionOrg, permissionProfile, roleKeycloak
อายุงาน/วิทยฐานะ tenure* (5 ตาราง)

A.2 Master Data (ข้อมูลอ้างอิง — lookup, เปลี่ยนน้อย)

กลุ่ม ตาราง (จำนวนแถว exact)
ที่อยู่ province (77), district (1,051), subDistrict (8,585), province_master, district_master, subdistrict_master
ประวัติบุคคล gender (3), bloodGroup (4), religion (5), relationship (4), prefixe (5), rank (9), educationLevel (14)
ตำแหน่ง posType (4), posLevel (15), posDict (910), posExecutive (40), employeePosType, employeePosLevel, employeePosDict
เครื่องราช insignia (14), insigniaType (3)
คำสั่ง/การลา commandType (47), commandCode (21), commandSys (12), leaveType (11)

💡 ที่อยู่มี 2 ชุดซ้ำซ้อน: province/district/subDistrict (ใช้จริง) vs *_master (ชุดสำรอง) — ตรวจสอบว่าจำเป็นไหม

A.3 ตารางคำนวณอัตโนมัติ (cron เขียนทุกคืน — ห้ามแก้ด้วยมือ)

เวลา ตาราง สิ่งที่ทำ
00:30 ทุกคืน profile, profileEmployee ประมวลผลคำสั่ง
04:00 ทุกคืน registry, registryEmployee, tenure* ล้างและสร้างใหม่ (full refresh)
02:00 วันที่ 1 ต.ค. profile, profileEmployee, profileSalary, posMaster อัปเดตสถานะเกษียณ

A.4 ข้อมูลต้นทางจากระบบเดิม (MIS)

ชื่อตารางตัวใหญ่ (HR_*, EMPLOYEE, Profile*):

สถานะ จำนวน รายละเอียด
ใช้อยู่ (สำหรับนำเข้าข้อมูล) 22 EMPLOYEE, OFFICER, Profile* (ตัวใหญ่), *Import
ไม่ได้ใช้แล้ว (dead entity) 25 HR_* (24) + IMPORT_ORG — เคยมีข้อมูลจริง >1.4M แถว

⚠️ ทั้ง 47 ตารางอยู่ในกลุ่มเตรียมลบ (§5) — drop แล้ว @ test

A.5 กลุ่มที่เตรียมลบ/ลบแล้ว (54 ตาราง)

กลุ่ม จำนวน ตัวอย่าง / เหตุผล
ข้อมูลระบบเดิม (MIS) 47 HR_*, EMPLOYEE, OFFICER, Profile*, *Import, IMPORT_ORG
ตารางพักนำเข้า (ว่าง) 2 HR_CHILDEN_EMPTEMP, HR_INSIGNIA_EMPTEMP (0 แถว)
ตารางซ้ำ/ทดสอบ/เก่า 5 Profiles, new_table, new_table_emp, entity_base, MET_PREFIX

หลังลบครบเหลือ 157 ตาราง. Script อยู่ Part C.

⚠️ profile*Employee* (profileDisciplineEmployee, profileInformation, profileSalaryEmployee + *History) ยังใช้ (มี controller: ProfileDisciplineEmployeeController, ProfileSalaryEmployeeController, ProfileEmployeeController) — อย่า drop

A.6 ข้อควรระวัง

  • ตารางเก็บ ชื่อ + เลขบัตรประชาชน: ~23 ตาราง (หลัก profile, profileEmployee, registry) — ข้อมูลส่วนบุคคล
  • migrations, typeorm_metadata เป็นตารางระบบ ห้ามลบเด็ดขาด
  • จำนวนแถวใน §A.1/A.4 เป็นค่าประมาณ (ยกเว้น §A.2 Master Data = exact)

A.7 Seed / Mock data (สำหรับ dev/test)

mock data แยกที่ src/seed/ (Node/TS) → npm run seed:show / seed:run / seed:revert seed แยกจาก migration หลักmigration:run ไม่เจอ seed → ไม่ทำลายข้อมูล prod. อ่าน src/seed/README.md


Part B — Plan checklist (CP0-CP7)

Context

DB hrms_organization (test) มีข้อมูลจริง + ตารางระบบเดิมไม่ได้ใช้ → ทำ environment สะอาด: ลดตารางเหลือใช้จริง + แทนข้อมูลจริงด้วย mock 30 คน + โครงสร้าง mock (revision 2569) + (defer) Keycloak

Decisions

Target DB 192.168.1.68 (test) — แจ้ง user ทุกครั้งก่อนจัดการ data
Mock 30 คน = 20 ข้าราชการ (Profile) + 10 ลูกจ้าง (ProfileEmployee)
citizenId สุ่ม 13 หลักผ่าน checksum จริง + ห้ามตรงของเดิม (block list)
HR_* (24) drop เลย (ไม่รอ .NET)
Keycloak clear keycloak column ก่อนลบ profile → CP6 clear orphan → CP7 ผูก KC ใหม่
CP7 password ddMMyyyy พ.ศ. จาก birthDate mock

Checklist

CP0 — Pre-flight

  • หยุด service (กัน cron 00:30/03:00/04:00 ทับ) + ยืนยันต่อ DB 192.168.1.68 (clone: 211 tables, profile 20,501)
  • verify junction/child table names + NOT NULL columns ของ target tables

เตรียมไฟล์

  • src/seed/mockData.ts (ชื่อไทย + genValidCitizenId checksum + deterministic UUID + genBirthDate)
  • 5 seed migrations (CP3-CP5c) + birthDate ใน CP5b; typecheck + test ผ่าน

CP1 — Full Backup SKIP (user มี backup อยู่แล้ว)

CP2 — Drop 54 unused tables (211 → 157) done

  • comment ImportDataController.ts @Route/@Security → npm run build → verify /api/v1/org/upload/* หาย
  • execute DROP 54 tables ใต้ SET FOREIGN_KEY_CHECKS=0/1 (ดู Part C)
  • verify: tables = 157; migrations/typeorm_metadata ยังอยู่

CP3 — Seed orgRevision 2569 done

  • run 1782100000001-seed_org_revision_2569.ts (ล้าง org/pos เดิม + INSERT "โครงสร้าง 2569")
  • verify: orgRevision=1, orgRevisionIsCurrent=1

CP4 — Seed mock org structure done

  • run 1782100000002-seed_mock_org_structure.ts
  • verify: สำนักA/หน่วยงานA/ฝ่ายA/กลุ่มงานA; FK chain ครบ

CP5a — Seed mock positions done (seed ตรง — TypeORM INSERT quirk)

  • run 1782100000003-seed_mock_positions.ts (20 posMaster + 10 employeePosMaster)
  • verify: posMaster=20, employeePosMaster=10; current_holderId NULL

CP5b — Seed mock profiles + clear keycloak done

  • run 1782100000004-seed_mock_profiles.ts (snapshot citizenId block list, clear keycloak, DELETE child + profile, INSERT 30 mock + birthDate)
  • verify: profile=20, profileEmployee=10; citizenId checksum + ไม่ตรง blocklist; birthDate ครบ
  • run 1782100000005-seed_link_holders.ts
  • verify: posMaster holder=20 join profile ครบ; employeePosMaster holder=10

CP6 — Clear Keycloak orphans SKIP (จัด KC ท้ายสุดพร้อม CP7)

CP7 — ผูก Keycloak ให้ mock defer

  • เปลี่ยน .env KC_SERVICE_ACCOUNT_* ชี้ Keycloak test
  • seed migration (1782100000006-seed_keycloak_users.ts) เรียก helper src/keycloak/index.ts (createUser/addUserRoles/getRoles/getUserByUsername)
  • role WHERE name='USER' (แทน hardcode UUID 8a1a0dc9-...)
  • loop mock 30 คน: createUser(citizenId, password ddMMyyyy พ.ศ. จาก birthDate) + addUserRoles(USER) + เซ็ต profile.keycloak + junction
  • verify: KC user = mock count; login mock ได้; super_admin ยังอยู่

ไฟล์ที่สร้างแล้ว

Seed (แยกจาก migration หลัก): src/seed/README.md, src/seed/data-source.ts, src/seed/mockData.ts, src/seed/migrations/178210000000{1..5}-seed_*.ts npm scripts: npm run seed:show / seed:run / seed:revert (ใช้ src/seed/data-source.ts) Code: src/controllers/ImportDataController.ts (@Route/@Security comment — CP2)

End-to-end verify (หลัง CP6)

  1. npm run migration:run ผ่านไม่ error (migration หลัก) + npm run seed:show เห็น seed 5
  2. tables = 157
  3. profile=20, profileEmployee=10, orgRevision=1
  4. citizenId ผ่าน checksum + ไม่ตรง blocklist
  5. posMaster holder=20 join profile ครบ
  6. cron 04:00 รอบแรก → registry/tenure rebuild จาก mock 30 คน
  7. login admin ได้ (super_admin ยังอยู่)

Risks

  • migration + SET FOREIGN_KEY_CHECKS session-level ไม่ rollback → backup เป็นหลัก ไม่พึ่ง down()
  • cron ทับ → หยุด service หรือทำ CP3-5c ในกรอบเวลาแคบ
  • CP7 env ต้องชี้ KC test ก่อน
  • TypeORM quirk: CP5a INSERT SELECT WHERE NOT EXISTS อาจไม่ execute ใน transaction → seed ตรงถ้า posMaster ว่าง

Part C — Drop script SQL (CP2)

⚠️⚠️⚠️ DROP TABLE ลบถาวร ย้อนกลับไม่ได้. ทุก DROP comment (--) ไว้ — uncomment เฉพาะที่ตรวจสอบแล้ว. ก่อนรัน: (1) backup DB (2) comment ImportDataController + npm run build (3) รันบน test เท่านั้น (4) ปรึกษาทีม .NET เรื่อง HR_* 🚫 ห้าม DROP: migrations, typeorm_metadata

USE hrms_organization;

-- นับตารางก่อนรัน (ควรได้ 211)
SELECT COUNT(*) AS tables_before
FROM information_schema.tables
WHERE table_schema = 'hrms_organization' AND table_type = 'BASE TABLE';

SET FOREIGN_KEY_CHECKS = 0;

-- ============================================================
-- กลุ่ม 1 — MIS tables (47) — ⚠️ ImportDataController พังหลัง drop → comment controller ก่อน
-- ============================================================
-- -- บุคลากรต้นทาง (4)
-- DROP TABLE IF EXISTS EMPLOYEE;
-- DROP TABLE IF EXISTS EMPLOYEETEMP;
-- DROP TABLE IF EXISTS OFFICER;
-- DROP TABLE IF EXISTS positionOfficer;
-- -- Profile* staging ตัว P ใหญ่ (14)
-- DROP TABLE IF EXISTS ProfileAbilitys;
-- DROP TABLE IF EXISTS ProfileCertificates;
-- DROP TABLE IF EXISTS ProfileChangeNames;
-- DROP TABLE IF EXISTS ProfileChildrens;
-- DROP TABLE IF EXISTS ProfileDisciplines;
-- DROP TABLE IF EXISTS ProfileDutys;
-- DROP TABLE IF EXISTS ProfileEducations;
-- DROP TABLE IF EXISTS ProfileHonors;
-- DROP TABLE IF EXISTS ProfileInsignias;
-- DROP TABLE IF EXISTS ProfileLeaveSummary;
-- DROP TABLE IF EXISTS ProfileNopaids;
-- DROP TABLE IF EXISTS ProfileOthers;
-- DROP TABLE IF EXISTS ProfileSalaries;
-- DROP TABLE IF EXISTS ProfileTrainings;
-- -- Import master (4)
-- DROP TABLE IF EXISTS amphurImport;
-- DROP TABLE IF EXISTS educationMis;
-- DROP TABLE IF EXISTS provinceImport;
-- DROP TABLE IF EXISTS subDistrictImport;
-- -- HR_* dead entity (24) — ⛔ มีข้อมูลจริง >1.4M แถว ปรึกษาทีม .NET ก่อน!
-- DROP TABLE IF EXISTS HR_CHANGENAME;
-- DROP TABLE IF EXISTS HR_CHANGENAME_EMP;
-- DROP TABLE IF EXISTS HR_CHANGENAME_EMPTEMP;
-- DROP TABLE IF EXISTS HR_CHILDEN;
-- DROP TABLE IF EXISTS HR_CHILDEN_EMP;
-- DROP TABLE IF EXISTS HR_DISCIPLINE;
-- DROP TABLE IF EXISTS HR_DISCIPLINE_EMP;
-- DROP TABLE IF EXISTS HR_DISCIPLINE_EMPTEMP;
-- DROP TABLE IF EXISTS HR_EDUCATION;
-- DROP TABLE IF EXISTS HR_EDUCATION_EMP;
-- DROP TABLE IF EXISTS HR_EDUCATION_EMPTEMP;
-- DROP TABLE IF EXISTS HR_FUND_COURSE_CODE;
-- DROP TABLE IF EXISTS HR_INSIGNIA;
-- DROP TABLE IF EXISTS HR_INSIGNIA_EMP;
-- DROP TABLE IF EXISTS HR_MAJOR_CODE;
-- DROP TABLE IF EXISTS HR_PERSONAL_EMPTEMP_ADDRESS;
-- DROP TABLE IF EXISTS HR_PERSONAL_EMPTEMP_FAMILY;
-- DROP TABLE IF EXISTS HR_PERSONAL_EMP_ADDRESS;
-- DROP TABLE IF EXISTS HR_PERSONAL_EMP_FAMILY;
-- DROP TABLE IF EXISTS HR_PERSONAL_OFFICER_ADDRESS;
-- DROP TABLE IF EXISTS HR_PERSONAL_OFFICER_FAMILY;
-- DROP TABLE IF EXISTS HR_POSITION_EMPLOYEE;
-- DROP TABLE IF EXISTS HR_POSITION_EMPLOYEETEMP;
-- DROP TABLE IF EXISTS HR_POSITION_OFFICER;
-- -- IMPORT_ORG (0 แถว)
-- DROP TABLE IF EXISTS IMPORT_ORG;

-- ============================================================
-- กลุ่ม 2 — Import staging ไม่มี entity (2, 0 แถว)
-- ============================================================
-- DROP TABLE IF EXISTS HR_CHILDEN_EMPTEMP;
-- DROP TABLE IF EXISTS HR_INSIGNIA_EMPTEMP;

-- ============================================================
-- กลุ่ม 3 — ซ้ำ/ทดสอบ/เก่า (5)
-- ⚠️ profile*Employee* ยังใช้ (มี controller) — อย่า drop
-- ============================================================
-- DROP TABLE IF EXISTS Profiles;
-- DROP TABLE IF EXISTS new_table;
-- DROP TABLE IF EXISTS new_table_emp;
-- DROP TABLE IF EXISTS entity_base;
-- DROP TABLE IF EXISTS MET_PREFIX;

SET FOREIGN_KEY_CHECKS = 1;

-- นับตารางหลังรัน (drop ครบ 54 → เหลือ 157)
SELECT COUNT(*) AS tables_after
FROM information_schema.tables
WHERE table_schema = 'hrms_organization' AND table_type = 'BASE TABLE';