feat(seed): synthetic fixture covering every pipeline stage + db:reset
Splits seed bootstrap (ports/roles/profile) into a shared module so
two seed entry points can share it:
- pnpm db:seed realistic NocoDB-shaped fixture (existing)
- pnpm db:seed:synthetic 12 clients, one per pipeline stage + archive
variants (rich metadata for restore wizard)
scripts/db-reset.ts truncates all data tables (preserves migrations);
guarded by --confirm and a localhost host check. Companion npm scripts:
- pnpm db:reset
- pnpm db:reseed:realistic
- pnpm db:reseed:synthetic
scripts/dev-open-browser.ts launches a headed Chromium with no viewport
override (uses the host monitor's natural size), pre-fills the login
form for the requested role.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
97
scripts/db-reset.ts
Normal file
97
scripts/db-reset.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Wipe all data from the database, preserving schema + drizzle migration
|
||||
* history. Run before swapping seed fixtures.
|
||||
*
|
||||
* pnpm tsx scripts/db-reset.ts (refuses without --confirm)
|
||||
* pnpm tsx scripts/db-reset.ts --confirm
|
||||
*
|
||||
* Truncates every table in the `public` schema except the drizzle
|
||||
* migration tracker, then resets sequences. Wraps the loop in a single
|
||||
* transaction so a mid-wipe failure rolls back cleanly.
|
||||
*
|
||||
* Refuses to run when DATABASE_URL points at anything that doesn't look
|
||||
* like a local/dev host. Override with --i-know-what-im-doing.
|
||||
*/
|
||||
|
||||
import 'dotenv/config';
|
||||
import postgres from 'postgres';
|
||||
|
||||
const url = process.env.DATABASE_URL;
|
||||
if (!url) {
|
||||
console.error('DATABASE_URL is not set; aborting.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const args = new Set(process.argv.slice(2));
|
||||
if (!args.has('--confirm')) {
|
||||
console.error('Refusing to wipe without --confirm');
|
||||
console.error('Run again as: pnpm tsx scripts/db-reset.ts --confirm');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Best-effort safety: refuse for anything that doesn't look like a local DB.
|
||||
function looksLocal(u: string): boolean {
|
||||
try {
|
||||
const parsed = new URL(u);
|
||||
return (
|
||||
parsed.hostname === 'localhost' ||
|
||||
parsed.hostname === '127.0.0.1' ||
|
||||
parsed.hostname === '::1' ||
|
||||
parsed.hostname.endsWith('.local') ||
|
||||
parsed.hostname.endsWith('.internal') ||
|
||||
parsed.hostname === 'host.docker.internal' ||
|
||||
// Docker compose service names commonly used here
|
||||
parsed.hostname === 'postgres' ||
|
||||
parsed.hostname === 'db'
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!looksLocal(url) && !args.has('--i-know-what-im-doing')) {
|
||||
console.error(
|
||||
`DATABASE_URL host doesn't look local. Refusing to wipe a remote DB without --i-know-what-im-doing.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const sql = postgres(url, { max: 1 });
|
||||
|
||||
async function main() {
|
||||
console.log('Resetting database...');
|
||||
console.log(` url: ${url.replace(/:[^:@]*@/, ':***@')}`);
|
||||
|
||||
const tables = await sql<{ tablename: string }[]>`
|
||||
SELECT tablename FROM pg_tables
|
||||
WHERE schemaname = 'public'
|
||||
AND tablename NOT LIKE 'drizzle_%'
|
||||
AND tablename != '__drizzle_migrations'
|
||||
`;
|
||||
|
||||
if (tables.length === 0) {
|
||||
console.log(' no user tables found, nothing to do.');
|
||||
await sql.end();
|
||||
return;
|
||||
}
|
||||
|
||||
// Single TRUNCATE … CASCADE is faster than per-table loops and handles
|
||||
// FK ordering for us. Quote table names defensively.
|
||||
const tableList = tables.map((t) => `"public"."${t.tablename}"`).join(', ');
|
||||
|
||||
console.log(` truncating ${tables.length} tables...`);
|
||||
await sql.unsafe(`TRUNCATE ${tableList} RESTART IDENTITY CASCADE`);
|
||||
console.log(' done.');
|
||||
|
||||
await sql.end();
|
||||
console.log('');
|
||||
console.log('Database reset complete. Run a seed script next:');
|
||||
console.log(' pnpm db:seed # realistic NocoDB-shaped fixture');
|
||||
console.log(' pnpm db:seed:synthetic # one client per pipeline stage');
|
||||
}
|
||||
|
||||
main().catch(async (err) => {
|
||||
console.error('Reset failed:', err);
|
||||
await sql.end().catch(() => undefined);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user