import "dotenv/config" import { drizzle } from "drizzle-orm/node-postgres" import { sql } from "drizzle-orm" import { Pool } from "pg" import { loadSecrets, secrets } from "../src/utils/secrets" const maskConnectionString = (value: string) => value.replace(/:\/\/([^:@]+):([^@]+)@/, "://$1:***@") const logStep = (message: string) => { console.log(`[tenant-lock-migration] ${message}`) } async function run() { let connectionString = process.env.DATABASE_URL if (!connectionString) { logStep("DATABASE_URL nicht in process.env gefunden, lade Secrets") await loadSecrets() connectionString = secrets.DATABASE_URL } else { logStep("DATABASE_URL aus process.env gefunden") } if (!connectionString) { throw new Error("DATABASE_URL not configured") } logStep(`Verbinde mit ${maskConnectionString(connectionString)}`) const pool = new Pool({ connectionString, max: 1, connectionTimeoutMillis: 10000, idleTimeoutMillis: 10000, }) try { const db = drizzle(pool) logStep("Teste DB-Verbindung") await db.execute(sql`SELECT 1`) logStep("Setze Statement-Timeout") await db.execute(sql`SET statement_timeout = '30s'`) logStep("Erweitere tenant_export_jobs") await db.execute(sql` ALTER TABLE "tenant_export_jobs" ADD COLUMN IF NOT EXISTS "operation" text DEFAULT 'export' NOT NULL, ADD COLUMN IF NOT EXISTS "previous_tenant_locked" "locked_tenant"; `) logStep("Erweitere tenants") await db.execute(sql` ALTER TABLE "tenants" ADD COLUMN IF NOT EXISTS "locked_by_export_job_id" uuid; `) logStep("Prüfe Foreign Key") await db.execute(sql` DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema = 'public' AND constraint_name = 'tenants_locked_by_export_job_id_tenant_export_jobs_id_fk' ) THEN ALTER TABLE "tenants" ADD CONSTRAINT "tenants_locked_by_export_job_id_tenant_export_jobs_id_fk" FOREIGN KEY ("locked_by_export_job_id") REFERENCES "tenant_export_jobs"("id") ON DELETE SET NULL; END IF; END $$; `) logStep("Prüfe Drizzle-Schema") await db.execute(sql` CREATE SCHEMA IF NOT EXISTS drizzle; `) logStep("Prüfe Drizzle-Migrationstabelle") await db.execute(sql` CREATE TABLE IF NOT EXISTS drizzle.__drizzle_migrations ( id SERIAL PRIMARY KEY, hash text NOT NULL, created_at bigint ); `) logStep("Setze Drizzle-Journal auf 0055") await db.execute(sql` INSERT INTO drizzle.__drizzle_migrations (hash, created_at) SELECT 'manual-0055_tenant_export_maintenance_lock', 1784021669805 WHERE NOT EXISTS ( SELECT 1 FROM drizzle.__drizzle_migrations WHERE created_at >= 1784021669805 ); `) logStep("Fertig") console.log("✅ Tenant export lock migration applied") } finally { logStep("Schließe DB-Verbindung") await pool.end() } } run().catch((err) => { console.error("❌ Tenant export lock migration failed") console.error(err) process.exit(1) })