From dbb02e54cc46d787426e4d0a6b7c42b79ac5e710 Mon Sep 17 00:00:00 2001 From: Ashwin Kumar Sivakumar Date: Sun, 19 Jul 2026 05:40:48 +0530 Subject: [PATCH] fix(db): stop wiping employees table on every migration run, restore phone column CRITICAL: 20260402030000_strict_employee_separation.up.sql contained an unconditional DROP TABLE IF EXISTS employees CASCADE followed by a bare CREATE TABLE, written as a one-time schema transformation back when it was authored. The db-migrate tool has no applied-migrations tracking table - it replays every .sql file on every run - which turned that one-time DROP into a destructive operation that wipes every employee account (including admin accounts) on every single migration job run. This is what caused today's "db error while logging in": the phone column (never present in any tracked migration, added out-of-band in production at some point) was gone after the recreate, and every employee row - including the account in use this session - was deleted. Fix: make the table creation a plain idempotent CREATE TABLE IF NOT EXISTS (the standalone-schema transition it performed already happened in production long ago, so the drop was never needed for correctness going forward). Add a proper migration for the phone column so it's tracked instead of relying on an undocumented manual ALTER. Confirmed via kubectl-verified row count (0) and a pre-incident backup (2026-07-18T21:00:03Z, predates the destructive run) that the deleted row is recoverable; restoring it separately as a one-time data fix, not part of this schema migration. Co-Authored-By: Claude Sonnet 5 --- ...0260402030000_strict_employee_separation.up.sql | 14 ++++++++++---- .../20260719000926_employees_phone_column.down.sql | 1 + .../20260719000926_employees_phone_column.up.sql | 7 +++++++ 3 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 crates/db/migrations/20260719000926_employees_phone_column.down.sql create mode 100644 crates/db/migrations/20260719000926_employees_phone_column.up.sql diff --git a/crates/db/migrations/20260402030000_strict_employee_separation.up.sql b/crates/db/migrations/20260402030000_strict_employee_separation.up.sql index 44da563..82db9d4 100644 --- a/crates/db/migrations/20260402030000_strict_employee_separation.up.sql +++ b/crates/db/migrations/20260402030000_strict_employee_separation.up.sql @@ -1,10 +1,16 @@ -- UP: 20260402030000_strict_employee_separation.up.sql - --- Drop old employees table (was linked to users — replacing with standalone auth) -DROP TABLE IF EXISTS employees CASCADE; +-- +-- Originally: "Drop old employees table (was linked to users - replacing with +-- standalone auth)" - a one-time schema transformation. The db-migrate tool +-- (crates/db-migrate) has no applied-migrations tracking table; it replays +-- every .sql file on every run, which turned this one-time DROP TABLE ... +-- CASCADE into a destructive operation that wiped the live employees table +-- (and every employee account, including admin accounts) on every migration +-- run. The standalone-schema transition already happened in production long +-- ago, so this is now safely a plain idempotent create. -- 1. EMPLOYEES (Standalone Table - Not Linked to 'users') -CREATE TABLE employees ( +CREATE TABLE IF NOT EXISTS employees ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), first_name VARCHAR(100) NOT NULL, last_name VARCHAR(100) NOT NULL, diff --git a/crates/db/migrations/20260719000926_employees_phone_column.down.sql b/crates/db/migrations/20260719000926_employees_phone_column.down.sql new file mode 100644 index 0000000..eb01aee --- /dev/null +++ b/crates/db/migrations/20260719000926_employees_phone_column.down.sql @@ -0,0 +1 @@ +ALTER TABLE employees DROP COLUMN IF EXISTS phone; diff --git a/crates/db/migrations/20260719000926_employees_phone_column.up.sql b/crates/db/migrations/20260719000926_employees_phone_column.up.sql new file mode 100644 index 0000000..dce1d31 --- /dev/null +++ b/crates/db/migrations/20260719000926_employees_phone_column.up.sql @@ -0,0 +1,7 @@ +-- The employees table has always had a `phone` column in production (queried +-- by EmployeeRepository::get_by_email/get_by_id/list) but no migration ever +-- created it - it was added out-of-band at some point outside the tracked +-- migration files, and was lost when 20260402030000_strict_employee_separation +-- dropped and recreated the table. Restore it as a tracked column going forward. + +ALTER TABLE employees ADD COLUMN IF NOT EXISTS phone VARCHAR(20);