backup page - working 1 done

This commit is contained in:
2025-08-25 00:19:12 +05:30
parent d8ee9da6f9
commit 38c3c43e6b
7 changed files with 367 additions and 49 deletions

View File

@@ -2,4 +2,8 @@ HOST="localhost"
PORT=5000
FRONTEND_URL="http://localhost:3000"
JWT_SECRET = 'dentalsecret'
DB_HOST="localhost"
DB_USER="postgres"
DB_PASSWORD="mypassword"
DB_NAME="dentalapp"
DATABASE_URL=postgresql://postgres:mypassword@localhost:5432/dentalapp

View File

@@ -0,0 +1,116 @@
import { Router, Request, Response } from "express";
import { spawn } from "child_process";
import path from "path";
import os from "os";
import fs from "fs";
import { prisma } from "@repo/db/client";
const router = Router();
/**
* Create a database backup
*/
router.post("/backup", async (req: Request, res: Response) => {
try {
const fileName = `dental_backup_${Date.now()}.dump`;
const tmpFile = path.join(os.tmpdir(), fileName);
// Spawn pg_dump
const pgDump = spawn(
"pg_dump",
[
"-Fc", // custom format
"--no-acl",
"--no-owner",
"-h",
process.env.DB_HOST || "localhost",
"-U",
process.env.DB_USER || "postgres",
process.env.DB_NAME || "dental_db",
"-f",
tmpFile, // write directly to temp file
],
{
env: {
...process.env,
PGPASSWORD: process.env.DB_PASSWORD,
},
}
);
let errorMessage = "";
pgDump.stderr.on("data", (chunk) => {
errorMessage += chunk.toString();
});
pgDump.on("close", (code) => {
if (code === 0) {
// ✅ Send only if dump succeeded
res.setHeader(
"Content-Disposition",
`attachment; filename=${fileName}`
);
res.setHeader("Content-Type", "application/octet-stream");
const fileStream = fs.createReadStream(tmpFile);
fileStream.pipe(res);
fileStream.on("close", () => {
fs.unlink(tmpFile, () => {}); // cleanup temp file
});
} else {
console.error("pg_dump failed:", errorMessage);
fs.unlink(tmpFile, () => {}); // cleanup
res.status(500).json({
error: "Backup failed",
details: errorMessage || `pg_dump exited with code ${code}`,
});
}
});
pgDump.on("error", (err) => {
console.error("Failed to start pg_dump:", err);
fs.unlink(tmpFile, () => {});
res.status(500).json({
error: "Failed to run pg_dump",
details: err.message,
});
});
} catch (err: any) {
console.error("Unexpected error:", err);
if (!res.headersSent) {
res.status(500).json({
message: "Internal server error",
details: String(err),
});
}
}
});
/**
* Get database status (connected, size, records count)
*/
router.get("/status", async (req: Request, res: Response) => {
try {
const size = await prisma.$queryRawUnsafe<{ size: string }[]>(
"SELECT pg_size_pretty(pg_database_size(current_database())) as size"
);
const patientsCount = await prisma.patient.count();
res.json({
connected: true,
size: size[0]?.size,
patients: patientsCount,
});
} catch (err) {
console.error("Status error:", err);
res.status(500).json({
connected: false,
error: "Could not fetch database status",
});
}
});
export default router;

View File

@@ -1,26 +1,28 @@
import { Router } from 'express';
import patientsRoutes from './patients';
import appointmentsRoutes from './appointments'
import usersRoutes from './users'
import staffsRoutes from './staffs'
import pdfExtractionRoutes from './pdfExtraction';
import claimsRoutes from './claims';
import insuranceCredsRoutes from './insuranceCreds';
import documentsRoutes from './documents';
import insuranceEligibilityRoutes from './insuranceEligibility'
import paymentsRoutes from './payments'
import { Router } from "express";
import patientsRoutes from "./patients";
import appointmentsRoutes from "./appointments";
import usersRoutes from "./users";
import staffsRoutes from "./staffs";
import pdfExtractionRoutes from "./pdfExtraction";
import claimsRoutes from "./claims";
import insuranceCredsRoutes from "./insuranceCreds";
import documentsRoutes from "./documents";
import insuranceEligibilityRoutes from "./insuranceEligibility";
import paymentsRoutes from "./payments";
import databaseManagementRoutes from "./database-management";
const router = Router();
router.use('/patients', patientsRoutes);
router.use('/appointments', appointmentsRoutes);
router.use('/users', usersRoutes);
router.use('/staffs', staffsRoutes);
router.use('/pdfExtraction', pdfExtractionRoutes);
router.use('/claims', claimsRoutes);
router.use('/insuranceCreds', insuranceCredsRoutes);
router.use('/documents', documentsRoutes);
router.use('/insuranceEligibility', insuranceEligibilityRoutes);
router.use('/payments', paymentsRoutes);
router.use("/patients", patientsRoutes);
router.use("/appointments", appointmentsRoutes);
router.use("/users", usersRoutes);
router.use("/staffs", staffsRoutes);
router.use("/pdfExtraction", pdfExtractionRoutes);
router.use("/claims", claimsRoutes);
router.use("/insuranceCreds", insuranceCredsRoutes);
router.use("/documents", documentsRoutes);
router.use("/insuranceEligibility", insuranceEligibilityRoutes);
router.use("/payments", paymentsRoutes);
router.use("/database-management", databaseManagementRoutes);
export default router;
export default router;