2026-07-11 22:32:37 +03:30
|
|
|
/**
|
|
|
|
|
* Dev-only: wipe all application data while keeping catalog / reference tables from seed.
|
|
|
|
|
*
|
|
|
|
|
* Preserved: organization_types, plans, features, permissions, treatment_types,
|
|
|
|
|
* lab_workflow_steps, prosthesis_types, prosthesis_type_steps, catalog_translations
|
|
|
|
|
*
|
|
|
|
|
* Usage: npm run prisma:wipe-app-data
|
|
|
|
|
*/
|
|
|
|
|
import { PrismaClient } from '@prisma/client';
|
|
|
|
|
import { config } from 'dotenv';
|
|
|
|
|
import { existsSync, rmSync } from 'fs';
|
|
|
|
|
import path from 'path';
|
|
|
|
|
|
|
|
|
|
const envPath = path.join(__dirname, '..', '.env');
|
|
|
|
|
config({ path: envPath });
|
|
|
|
|
|
|
|
|
|
if (process.env.NODE_ENV === 'production') {
|
|
|
|
|
console.error('wipe-app-data is not allowed in production');
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
|
|
|
|
|
|
const CATALOG_TABLES = new Set([
|
|
|
|
|
'organization_types',
|
|
|
|
|
'plans',
|
|
|
|
|
'features',
|
|
|
|
|
'permissions',
|
|
|
|
|
'treatment_types',
|
|
|
|
|
'lab_workflow_steps',
|
|
|
|
|
'prosthesis_types',
|
|
|
|
|
'prosthesis_type_steps',
|
|
|
|
|
'catalog_translations',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// FK-safe order: children before parents where CASCADE is not enough.
|
|
|
|
|
const TABLES_IN_ORDER = [
|
|
|
|
|
'phone_verification_codes',
|
|
|
|
|
'staff_working_hours_blocks',
|
|
|
|
|
'staff_working_hours_schedules',
|
|
|
|
|
'staff_invitations',
|
|
|
|
|
'membership_permissions',
|
|
|
|
|
'sessions',
|
2026-08-19 00:39:31 +03:30
|
|
|
'user_notifications',
|
|
|
|
|
'lab_case_user_read_states',
|
|
|
|
|
'lab_case_user_tab_read_states',
|
2026-07-11 22:32:37 +03:30
|
|
|
'lab_case_task_status_events',
|
|
|
|
|
'lab_case_comments',
|
|
|
|
|
'lab_case_attachments',
|
|
|
|
|
'lab_case_tasks',
|
|
|
|
|
'lab_case_sends',
|
|
|
|
|
'lab_case_tooth_prosthesis',
|
|
|
|
|
'lab_case_details',
|
|
|
|
|
'lab_cases',
|
2026-08-19 00:39:31 +03:30
|
|
|
'lab_case_activities',
|
2026-07-11 22:32:37 +03:30
|
|
|
'treatment_detail_attachments',
|
|
|
|
|
'treatment_details',
|
|
|
|
|
'treatments',
|
|
|
|
|
'appointments',
|
|
|
|
|
'organization_links',
|
|
|
|
|
'organization_invitations',
|
|
|
|
|
'patients',
|
|
|
|
|
'memberships',
|
|
|
|
|
'organizations',
|
|
|
|
|
'users',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
async function tableExists(table: string): Promise<boolean> {
|
|
|
|
|
const rows = await prisma.$queryRawUnsafe<Array<{ exists: string | null }>>(
|
|
|
|
|
`SELECT to_regclass('public."${table}"')::text AS exists`,
|
|
|
|
|
);
|
|
|
|
|
return rows[0]?.exists != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function main() {
|
|
|
|
|
console.log('🧹 Wiping application data (keeping catalog / reference tables)...');
|
|
|
|
|
|
|
|
|
|
const existing: string[] = [];
|
|
|
|
|
for (const table of TABLES_IN_ORDER) {
|
|
|
|
|
if (CATALOG_TABLES.has(table)) {
|
|
|
|
|
throw new Error(`Misconfigured wipe list includes catalog table: ${table}`);
|
|
|
|
|
}
|
|
|
|
|
if (await tableExists(table)) {
|
|
|
|
|
existing.push(table);
|
|
|
|
|
} else {
|
|
|
|
|
console.log(` - skipping "${table}" (does not exist yet)`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (existing.length === 0) {
|
|
|
|
|
console.log('No application tables found. Run `prisma migrate deploy` first.');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const targets = existing.map((t) => `"${t}"`).join(', ');
|
|
|
|
|
await prisma.$executeRawUnsafe(`TRUNCATE TABLE ${targets} RESTART IDENTITY CASCADE`);
|
|
|
|
|
|
|
|
|
|
const uploadRoot = path.join(__dirname, '..', 'uploads');
|
|
|
|
|
if (existsSync(uploadRoot)) {
|
|
|
|
|
rmSync(uploadRoot, { recursive: true, force: true });
|
|
|
|
|
console.log(' - removed local uploads/ directory');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('✅ Application data wiped.');
|
|
|
|
|
console.log(' Preserved catalog tables:', [...CATALOG_TABLES].sort().join(', '));
|
|
|
|
|
console.log(' Register a new user / org to start fresh testing.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
main()
|
|
|
|
|
.catch((e) => {
|
|
|
|
|
console.error('❌ Wipe failed:', e);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
})
|
|
|
|
|
.finally(async () => {
|
|
|
|
|
await prisma.$disconnect();
|
|
|
|
|
});
|