housekeeping-service — MIGRATION_PLAN
Schema migrations:
node-pg-migrate, expand → contract in two PRs. Data migrations: Cloud Run Jobs with throttling. Onboarding importer: optional CSV ingest for legacy housekeeping logs from incumbent PMS.
1. Schema migration policy
- One PR per logical change. Numbered files in
migrations/—YYYYMMDDHHMM_<slug>.sql— with bothupanddownblocks. - Expand → Contract in two PRs for any breaking change:
- Expand: add new column/table/index in a backward-compatible way. Code reads from old, dual-writes new. Deploy.
- Backfill: run a Cloud Run Job to populate the new shape.
- Contract: flip code to read from new; remove old after one deploy with no fall-back.
- Migrations run as a Cloud Run Job before traffic split during release. Job uses a dedicated service account with
cloudsql.clientonly (noBYPASSRLS). - Migrations must be idempotent (
IF NOT EXISTS,ON CONFLICT DO NOTHING) so partial failure replays cleanly. - Every migration is exercised in CI on a fresh DB and in a roll-back test (
upthendownthenup).
2. Partition management
housekeeping_tasksis partitioned bycreated_atmonthly viapg_partman.- Maintenance Cloud Run Job runs weekly and:
- Creates partitions for the next 3 months if missing.
- Detaches partitions older than 18 months, exports to GCS Parquet via the standard archive job, drops them.
- Index changes on the partitioned table apply globally; expand-contract still required.
3. Index changes
- New indexes created with
CONCURRENTLYto avoid table locks. partition-pruning.spec.tsbaseline updated whenever a hot query changes; CI rejects regressions.
4. Outbox / inbox migrations
outboxandinboxschemas are append-only-friendly; migrations only add fields.- During payload-schema bumps (
vN → vN+1):- Producer dual-publishes for ≥ 30 days (configurable).
EVENT_SCHEMAS.md §5policy applies.
5. Data migrations and backfills
Standard pattern:
- New column added (expand step).
- Cloud Run Job
housekeeping-backfill-<slug>reads in batches of 1000 ordered by(tenant_id, id), throttled to 1k rows/s default. - Job is resumable (writes a checkpoint row to
housekeeping.maintenance_state). - Verification query asserts 0 rows with NULL new column before contract step.
6. Onboarding importer (optional)
For tenants migrating from an existing PMS with usable housekeeping history:
- CSV format:
task_id_legacy,date,room_number,kind,assignee_legacy,started_at,completed_at,outcome,note. - Importer Cloud Run Job
housekeeping-onboarding-import:- Reads CSV from GCS bucket
gs://melmastoon-onboarding/<tenantId>/housekeeping/. - Resolves
room_number→room_idviaproperty-service; rejects unknown rows to a_rejects.csv. - Resolves
assignee_legacy→staff_idviastaff-servicemapping. - Inserts
housekeeping_tasksrows withsource='import',created_at= original date, status final-only (completed/failed/cancelled). - Skips outbox emission (historical, not live).
- Records audit row.
- Reads CSV from GCS bucket
- Limit: 50k rows/tenant per onboarding to avoid skewing dashboards; older history archived to GCS as Parquet only.
7. Cross-link
- Schema baseline:
DATA_MODEL.md. - Event-schema evolution rule:
EVENT_SCHEMAS.md§5. - Cloud Run Job topology:
DEPLOYMENT_TOPOLOGY.md§3.