16 KiB
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 test192.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, orgChild1–orgChild4, 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 ครบ
CP5c — Link holders ✅ done
- 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
- เปลี่ยน
.envKC_SERVICE_ACCOUNT_*ชี้ Keycloak test - seed migration (
1782100000006-seed_keycloak_users.ts) เรียก helpersrc/keycloak/index.ts(createUser/addUserRoles/getRoles/getUserByUsername) - role
WHERE name='USER'(แทน hardcode UUID8a1a0dc9-...) - 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)
npm run migration:runผ่านไม่ error (migration หลัก) +npm run seed:showเห็น seed 5- tables = 157
- profile=20, profileEmployee=10, orgRevision=1
- citizenId ผ่าน checksum + ไม่ตรง blocklist
- posMaster holder=20 join profile ครบ
- cron 04:00 รอบแรก → registry/tenure rebuild จาก mock 30 คน
- login admin ได้ (super_admin ยังอยู่)
Risks
- migration +
SET FOREIGN_KEY_CHECKSsession-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) commentImportDataController+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';