fix: auto-migrate after DB restore and force re-login
- After importing a backup, run prisma migrate deploy so any schema migrations the backup is missing are applied automatically. This prevents pages from failing due to missing tables/columns when the backup was taken on an older version of the app. - Force logout and redirect to login after a successful restore so the JWT is refreshed against the restored database (prevents userId mismatch causing user-scoped queries to return empty results). - Fix getTotalPatientCount() in /status route to pass userId so it counts only the current user's patients instead of all patients. - Add prisma.$connect() after $disconnect() to ensure a clean reconnect. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
NODE_ENV="development"
|
||||
HOST=0.0.0.0
|
||||
PORT=5000
|
||||
FRONTEND_URLS=http://localhost:3000,http://192.168.1.236,https://communitydentistsoflowell.mydentalofficemanagement.com
|
||||
FRONTEND_URLS=http://localhost:3000
|
||||
SELENIUM_AGENT_BASE_URL=http://localhost:5002
|
||||
JWT_SECRET = 'dentalsecret'
|
||||
DB_HOST=localhost
|
||||
|
||||
@@ -120,7 +120,7 @@ router.get("/status", async (req: Request, res: Response): Promise<any> => {
|
||||
SELECT pg_size_pretty(pg_database_size(current_database())) as size
|
||||
`;
|
||||
|
||||
const patientsCount = await storage.getTotalPatientCount();
|
||||
const patientsCount = await storage.getTotalPatientCount(userId);
|
||||
const lastBackup = await storage.getLastBackup(userId);
|
||||
|
||||
res.json({
|
||||
@@ -388,11 +388,38 @@ router.post("/restore", restoreUpload.single("file"), async (req: Request, res:
|
||||
return res.status(500).json({ error: "Restore failed", details: stderr });
|
||||
}
|
||||
|
||||
// Reconnect Prisma after schema was replaced
|
||||
try {
|
||||
await prisma.$disconnect();
|
||||
await prisma.$connect();
|
||||
} catch (_) {}
|
||||
|
||||
res.json({ success: true });
|
||||
// Apply any migrations the backup may be missing so the schema matches
|
||||
// the current codebase. Uses prisma migrate deploy which is safe to run
|
||||
// repeatedly — it skips already-applied migrations.
|
||||
const migrate = spawn(
|
||||
"npx",
|
||||
["prisma", "migrate", "deploy", "--schema", path.resolve(__dirname, "../../../../packages/db/prisma/schema.prisma")],
|
||||
{
|
||||
env: { ...process.env, DATABASE_URL: process.env.DATABASE_URL || "" },
|
||||
cwd: path.resolve(__dirname, "../../../../packages/db"),
|
||||
}
|
||||
);
|
||||
let migrateOut = "";
|
||||
migrate.stdout.on("data", (d) => (migrateOut += d.toString()));
|
||||
migrate.stderr.on("data", (d) => (migrateOut += d.toString()));
|
||||
migrate.on("close", (migrateCode) => {
|
||||
if (migrateCode !== 0) {
|
||||
console.error("prisma migrate deploy failed after restore:", migrateOut);
|
||||
} else {
|
||||
console.log("prisma migrate deploy completed after restore:", migrateOut.trim());
|
||||
}
|
||||
res.json({ success: true });
|
||||
});
|
||||
migrate.on("error", (err) => {
|
||||
console.error("Failed to run prisma migrate deploy:", err.message);
|
||||
res.json({ success: true }); // still report success — data is restored
|
||||
});
|
||||
});
|
||||
|
||||
if (isZip && tmpZipPath) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
NODE_ENV=development
|
||||
HOST=0.0.0.0
|
||||
PORT=3000
|
||||
VITE_API_BASE_URL_BACKEND=
|
||||
VITE_API_BASE_URL_BACKEND=http://localhost:5000
|
||||
@@ -42,10 +42,18 @@ export function ImportDatabaseSection() {
|
||||
onSuccess: () => {
|
||||
toast({
|
||||
title: "Database Restored",
|
||||
description: "The database has been successfully restored from the backup file.",
|
||||
description: "Database restored successfully. Redirecting to login...",
|
||||
});
|
||||
setSelectedFile(null);
|
||||
if (fileInputRef.current) fileInputRef.current.value = "";
|
||||
// Clear auth token and reload so the user re-authenticates against the
|
||||
// restored database. This is necessary because the restored data may have
|
||||
// a different userId than the current JWT, which would cause all
|
||||
// user-scoped queries to return empty results.
|
||||
setTimeout(() => {
|
||||
localStorage.removeItem("token");
|
||||
window.location.href = "/";
|
||||
}, 2000);
|
||||
},
|
||||
onError: (err: any) => {
|
||||
toast({
|
||||
|
||||
Reference in New Issue
Block a user