// apps/hq/scripts/migrate-onboarding-templates.ts — Client Detail redesign task 5: one-time // migration swapping existing SMS/RTGS/MobileApp projects off the old generic onboarding // checklist onto their new per-module template, carrying mapped ticks. Idempotent — safe // to re-run (a second run does nothing). // DATABASE_URL=postgres://… npx tsx apps/hq/scripts/migrate-onboarding-templates.ts import { openDb, sqliteFilePath } from '../src/db' import { openPgDb, pgTargetDescription, requireDbUrlForEnv } from '../src/db-pg' import { migrateOnboardingTemplates } from '../src/migrate-onboarding-templates' import type { DB } from '../src/db' async function main(): Promise { // Pre-ship audit FIX A: the SAME resolver server.ts uses (never re-derived locally) — and, // unlike the server, this one-off script hard-fails rather than silently falling back to a // throwaway SQLite file when NODE_ENV=production resolves no Postgres target. const pgUrl = requireDbUrlForEnv() if (pgUrl !== '') { console.log(`[db] engine: postgres ${pgTargetDescription(pgUrl)}`) } else { console.log(`[db] engine: sqlite at ${sqliteFilePath(process.env['HQ_DATA_DIR'])}`) } const db: DB = pgUrl !== '' ? await openPgDb(pgUrl) : openDb(process.env['HQ_DATA_DIR']) try { const res = await migrateOnboardingTemplates(db) // eslint-disable-next-line no-console console.log( `Onboarding template migration: ${res.projects} project(s) rebuilt, ${res.carried} tick(s) carried, ` + `${res.dropped} dropped, ${res.collapsed} collapsed (two old ticks -> one key), ` + `${res.preserved} custom step(s) preserved.`, ) } finally { await db.close() } } main().catch((e) => { console.error(e); process.exit(1) })