Files
fm_be/docs/duty-roster-migrations.md
2026-07-16 22:16:45 +07:00

5.8 KiB

Duty Roster Migrations

Catatan eksekusi 6 file migrasi duty roster di migrations/.

Konfigurasi Tool Migrasi

Tool migrasi yang dipakai project ini adalah goose (Makefile:5) dengan direktori target:

GOOSE_DIR ?= migrations/goose

Konsekuensi: make migrate-up hanya menjalankan file di migrations/goose/. Semua file .sql di root migrations/ — termasuk 6 file duty roster — tidak otomatis dieksekusi. Mereka berfungsi sebagai script SQL ad-hoc / log historis dan harus dijalankan manual (mysql < file.sql) atau dipindahkan ke migrations/goose/ dengan format -- +goose Up / -- +goose Down.

Urutan Eksekusi (by Timestamp)

Goose mengurutkan file by filename ascending. Untuk dua file dengan timestamp sama (20260502), urutannya alfabetis: duty < purge.

1. 20260408_hems_duty_roster_crews_confirm_at.sql
2. 20260429_rename_duty_roster_tables.sql
3. 20260430_normalize_duty_roster_legacy.sql
4. 20260502_duty_roster_permissions_unification.sql
5. 20260502_purge_legacy_hems_duty_roster_permissions.sql
6. 20260504_duty_roster_drop_unique_base_date.sql

Efek per File

# File Efek di DB
1 20260408_hems_duty_roster_crews_confirm_at.sql ALTER TABLE hems_duty_roster_crews ADD COLUMN confirm_at DATETIME NULL (nama tabel lama). Idempoten via IF NOT EXISTS.
2 20260429_rename_duty_roster_tables.sql RENAME TABLE hems_duty_rosters → duty_rosters dan hems_duty_roster_crews → duty_roster_crews. Pakai guard cek information_schema.TABLES jadi idempoten.
3 20260430_normalize_duty_roster_legacy.sql (a) Rename tabel lagi dengan guard sama (no-op kalau #2 sukses). (b) Rename kolom hems_base_id → base_id di duty_rosters. (c) Ensure confirm_at ada di duty_roster_crews baru (dan di tabel lama jika masih ada). (d) Rewire FK roster_crews.roster_id & duty_roster_other_persons.roster_id supaya reference duty_rosters (bukan hems_duty_rosters).
4 20260502_duty_roster_permissions_unification.sql Insert 4 permission canonical: duty_roster.{create,read,update,delete} (skip via WHERE NOT EXISTS). Grant ke role yang punya legacy hems_duty_roster.* ke canonical baru, anti-duplikasi via LEFT JOIN ... NOT EXISTS. Tidak menghapus legacy.
5 20260502_purge_legacy_hems_duty_roster_permissions.sql (a) Re-insert canonical (no-op jika #4 sudah jalan). (b) Re-grant (no-op). (c) DELETE FROM role_permissions WHERE permission.key IN (legacy). (d) DELETE FROM permissions WHERE key IN (legacy).
6 20260504_duty_roster_drop_unique_base_date.sql DROP INDEX idx_roster_base_date (sebelumnya unique). CREATE INDEX idx_roster_base_date ON duty_rosters(base_id, duty_date) non-unique. Konsekuensi aplikasi: schema tidak lagi mencegah multiple roster di pasangan (base_id, duty_date) yang sama — kode handler harus mendukung skenario ini (lihat ensureRosterDates yang sebelumnya dedup-by-date).

Overlap & Redundansi

  • #2 ⊂ #3 — File 0430_normalize_legacy sudah include semua rename dari 0429 dengan guard yang sama. File 0429 secara fungsional redundant; akan no-op jika dijalankan setelah 0430.
  • #4 ⊂ #5 — File 0502_purge_legacy adalah superset dari 0502_unification. Insert + grant identik, lalu tambah DELETE. File 0502_unification redundant.

Idempotensi Re-run

File Idempoten? Catatan
#1 Ya ADD COLUMN IF NOT EXISTS
#2 Ya Guard via information_schema.TABLES
#3 Ya Setiap ALTER dibungkus prepared statement dengan kondisi
#4 Ya WHERE NOT EXISTS untuk insert + LEFT JOIN ... IS NULL untuk grant
#5 Ya Sama dengan #4, ditambah DELETE (idempoten karena hanya hapus key legacy)
#6 TIDAK DROP INDEX idx_roster_base_date tanpa guard. Re-run setelah index sudah di-drop + recreate (sebagai non-unique) akan gagal karena nama indexnya sama. Mestinya pakai prepared statement guard yang cek information_schema.STATISTICS.

Versi Minimal yang Setara

Dengan urutan dijalankan penuh, efek akhirnya cukup dicapai dengan 4 file:

0408_..._confirm_at        (kompat untuk env yang masih punya hems_duty_*)
0430_normalize_legacy      (rename tabel + kolom + FK + confirm_at — superset dari 0429)
0502_purge_legacy          (canonical perm + delete legacy — superset dari 0502_unification)
0504_drop_unique_base_date (butuh tambah guard agar idempoten)

Untuk env yang sudah pasti fresh (tanpa sisa hems_duty_* apa pun), kelima file di atas bisa digabung jadi satu file goose-format dengan branch yang relevan saja. Sebelum melakukan ini, pastikan tidak ada DB target yang masih nyangkut di mid-state — file individual lebih aman selama transisi.

Bug yang Pernah Ditemukan Akibat #6

Setelah idx_roster_base_date jadi non-unique, beberapa baris kode aplikasi yang asumsi unique (base_id, duty_date) jadi salah:

  • ensureRosterDates di handler GET /duty-roster/get-all & /get-all/dt sebelumnya pakai map[string]R keyed by date — multiple roster di tanggal sama di-overwrite, hanya 1 yang muncul. Sudah diperbaiki pakai map[string][]R (multi-value).

Pastikan setiap kode baru yang query/iterasi roster per (base_id, duty_date) menyadari bahwa kombinasi ini tidak lagi unique.