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

This commit is contained in:
harid 2026-07-22 18:01:45 +07:00
parent d3e1707cc2
commit 8201ac51af
11 changed files with 836 additions and 3 deletions

View file

@ -0,0 +1,263 @@
# 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`, `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 ✅
- [x] หยุด service (กัน cron 00:30/03:00/04:00 ทับ) + ยืนยันต่อ DB `192.168.1.68` (clone: 211 tables, profile 20,501)
- [x] verify junction/child table names + NOT NULL columns ของ target tables
### เตรียมไฟล์ ✅
- [x] `src/seed/mockData.ts` (ชื่อไทย + genValidCitizenId checksum + deterministic UUID + genBirthDate)
- [x] 5 seed migrations (CP3-CP5c) + birthDate ใน CP5b; typecheck + test ผ่าน
### CP1 — Full Backup ✅ SKIP (user มี backup อยู่แล้ว)
### CP2 — Drop 54 unused tables (211 → 157) ✅ done
- [x] comment `ImportDataController.ts` @Route/@Security`npm run build` → verify `/api/v1/org/upload/*` หาย
- [x] execute DROP 54 tables ใต้ `SET FOREIGN_KEY_CHECKS=0/1` (ดู Part C)
- [x] **verify**: tables = **157**; `migrations`/`typeorm_metadata` ยังอยู่
### CP3 — Seed orgRevision 2569 ✅ done
- [x] run `1782100000001-seed_org_revision_2569.ts` (ล้าง org/pos เดิม + INSERT "โครงสร้าง 2569")
- [x] **verify**: `orgRevision`=1, `orgRevisionIsCurrent`=1
### CP4 — Seed mock org structure ✅ done
- [x] run `1782100000002-seed_mock_org_structure.ts`
- [x] **verify**: สำนักA/หน่วยงานA/ฝ่ายA/กลุ่มงานA; FK chain ครบ
### CP5a — Seed mock positions ✅ done (seed ตรง — TypeORM INSERT quirk)
- [x] run `1782100000003-seed_mock_positions.ts` (20 posMaster + 10 employeePosMaster)
- [x] **verify**: posMaster=20, employeePosMaster=10; current_holderId NULL
### CP5b — Seed mock profiles + clear keycloak ✅ done
- [x] run `1782100000004-seed_mock_profiles.ts` (snapshot citizenId block list, clear keycloak, DELETE child + profile, INSERT 30 mock + birthDate)
- [x] **verify**: profile=20, profileEmployee=10; citizenId checksum + ไม่ตรง blocklist; birthDate ครบ
### CP5c — Link holders ✅ done
- [x] run `1782100000005-seed_link_holders.ts`
- [x] **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`
```sql
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';
```