From a12fb0450e7074500e70df65dacb934ba7b69af1 Mon Sep 17 00:00:00 2001 From: "s.esmaeili" Date: Mon, 14 Sep 2026 21:44:14 +0330 Subject: [PATCH] api: don't replay the baseline migration on pre-fix databases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The folder-discovery fix in the previous commit surfaced a second problem. Databases migrated BEFORE that fix recorded the baseline under the name of the hand-added flat duplicate that used to sit beside it (prisma/migrations/0001_init.sql). Once the runner started discovering the real folder (20260910113720_first), it saw a name it had never recorded and tried to apply the baseline again — against a database that already had it: Raw query failed. Code: 42710. ERROR: type "AdminRole" already exists The two files are identical SQL (verified byte-for-byte after normalising line endings; they differ only by one trailing blank line), so the recorded legacy name genuinely means that migration is applied. A LEGACY_NAME_ALIASES map now treats '0001_init.sql' as an already-applied marker for '20260910113720_first', so upgrading an existing database is a no-op instead of a crash. Verified against the local dev database this actually broke on (postgresql://localhost:5432/gold_banking, which had recorded only the old flat name): 'npm run dev' in apps/api now logs 'No pending migrations' and 'Nest application successfully started' instead of dying. That database's tracking table was also reconciled to record both real migration names, and it was confirmed to already contain both migrations' schema (AdminRole, City.percent, user_type, CustomerKind all present) — nothing was re-run against it. The dockerised database is unaffected: it already records the real names, so the alias is inert there. Co-Authored-By: Claude Opus 5 --- apps/api/release/app.js | 6 +++++- apps/api/src/prisma/migrate.ts | 14 +++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/api/release/app.js b/apps/api/release/app.js index 079d4bb..6789d8a 100644 --- a/apps/api/release/app.js +++ b/apps/api/release/app.js @@ -93025,6 +93025,9 @@ var require_migrate = __commonJS({ statements.push(current.trim()); return statements; } + var LEGACY_NAME_ALIASES = { + "20260910113720_first": "0001_init.sql" + }; function discoverMigrationFiles(dir) { const entries = (0, fs_1.readdirSync)(dir); const files = []; @@ -93060,7 +93063,8 @@ var require_migrate = __commonJS({ const appliedNames = new Set(alreadyApplied.map((row) => row.name)); const applied = []; for (const file2 of files) { - if (appliedNames.has(file2.name)) + const legacyName = LEGACY_NAME_ALIASES[file2.name]; + if (appliedNames.has(file2.name) || legacyName && appliedNames.has(legacyName)) continue; const statements = splitSqlStatements((0, fs_1.readFileSync)(file2.path, "utf8")); await prisma.$transaction( diff --git a/apps/api/src/prisma/migrate.ts b/apps/api/src/prisma/migrate.ts index 7e0429d..ff521bc 100644 --- a/apps/api/src/prisma/migrate.ts +++ b/apps/api/src/prisma/migrate.ts @@ -118,6 +118,17 @@ export function splitSqlStatements(sql: string): string[] { */ type MigrationFile = { name: string; path: string }; +/** + * Databases migrated before the folder-discovery fix recorded the baseline + * under the name of the hand-added flat duplicate that used to sit alongside + * it (prisma/migrations/0001_init.sql, identical SQL bar a trailing newline). + * Without this, upgrading replays the baseline against a database that already + * has it and dies on `type "AdminRole" already exists`. + */ +const LEGACY_NAME_ALIASES: Record = { + '20260910113720_first': '0001_init.sql', +}; + function discoverMigrationFiles(dir: string): MigrationFile[] { const entries = readdirSync(dir); const files: MigrationFile[] = []; @@ -171,7 +182,8 @@ export async function runMigrations(prisma: PrismaClient): Promise