From d859362c40de02d5baec987b64c14e0991af7787 Mon Sep 17 00:00:00 2001 From: Potenz Date: Mon, 25 Aug 2025 23:59:16 +0530 Subject: [PATCH] backup page done --- apps/Backend/package.json | 1 + apps/Backend/src/app.ts | 6 +- apps/Backend/src/cron/backupCheck.ts | 50 +++ apps/Backend/src/index.ts | 37 ++- .../Backend/src/routes/database-management.ts | 29 +- apps/Backend/src/routes/index.ts | 2 + apps/Backend/src/routes/notifications.ts | 34 +++ apps/Backend/src/storage/index.ts | 132 ++++++-- .../components/layout/notification-bell.tsx | 287 ++++++++++++++++++ .../src/components/layout/top-app-bar.tsx | 10 +- package-lock.json | 10 + packages/db/prisma/schema.prisma | 35 ++- packages/db/types/databaseBackup-types.ts | 6 + packages/db/types/index.ts | 4 +- packages/db/types/notifications-types.ts | 11 + packages/db/usedSchemas/index.ts | 5 +- 16 files changed, 619 insertions(+), 40 deletions(-) create mode 100644 apps/Backend/src/cron/backupCheck.ts create mode 100644 apps/Backend/src/routes/notifications.ts create mode 100644 apps/Frontend/src/components/layout/notification-bell.tsx create mode 100644 packages/db/types/databaseBackup-types.ts create mode 100644 packages/db/types/notifications-types.ts diff --git a/apps/Backend/package.json b/apps/Backend/package.json index 94ee1f2..e22ef23 100644 --- a/apps/Backend/package.json +++ b/apps/Backend/package.json @@ -22,6 +22,7 @@ "form-data": "^4.0.2", "jsonwebtoken": "^9.0.2", "multer": "^2.0.0", + "node-cron": "^4.2.1", "passport": "^0.7.0", "passport-local": "^1.0.0", "ws": "^8.18.0", diff --git a/apps/Backend/src/app.ts b/apps/Backend/src/app.ts index 5d382ac..244403a 100644 --- a/apps/Backend/src/app.ts +++ b/apps/Backend/src/app.ts @@ -6,6 +6,7 @@ import { apiLogger } from "./middlewares/logger.middleware"; import authRoutes from "./routes/auth"; import { authenticateJWT } from "./middlewares/auth.middleware"; import dotenv from "dotenv"; +import { startBackupCron } from "./cron/backupCheck"; dotenv.config(); const FRONTEND_URL = process.env.FRONTEND_URL; @@ -30,4 +31,7 @@ app.use("/api", authenticateJWT, routes); app.use(errorHandler); -export default app; \ No newline at end of file +//startig cron job +startBackupCron(); + +export default app; diff --git a/apps/Backend/src/cron/backupCheck.ts b/apps/Backend/src/cron/backupCheck.ts new file mode 100644 index 0000000..b6f13f8 --- /dev/null +++ b/apps/Backend/src/cron/backupCheck.ts @@ -0,0 +1,50 @@ +import cron from "node-cron"; +import { storage } from "../storage"; +import { NotificationTypes } from "@repo/db/types"; + +/** + * Daily cron job to check if users haven't backed up in 7 days + * Creates a backup notification if overdue + */ +export const startBackupCron = () => { + cron.schedule("0 9 * * *", async () => { + console.log("🔄 Running daily backup check..."); + + const userBatchSize = 100; + let userOffset = 0; + + while (true) { + // Fetch a batch of users + const users = await storage.getUsers(userBatchSize, userOffset); + if (!users || users.length === 0) break; + + for (const user of users) { + try { + if (user.id == null) { + continue; + } + const lastBackup = await storage.getLastBackup(user.id); + const daysSince = lastBackup?.createdAt + ? (Date.now() - new Date(lastBackup.createdAt).getTime()) / + (1000 * 60 * 60 * 24) + : Infinity; + + if (daysSince >= 7) { + await storage.createNotification( + user.id, + "BACKUP" as NotificationTypes, + "⚠️ It has been more than 7 days since your last backup." + ); + console.log(`Notification created for user ${user.id}`); + } + } catch (err) { + console.error(`Error processing user ${user.id}:`, err); + } + } + + userOffset += userBatchSize; // next user batch + } + + console.log("✅ Daily backup check completed."); + }); +}; diff --git a/apps/Backend/src/index.ts b/apps/Backend/src/index.ts index 78a0ebb..c684822 100644 --- a/apps/Backend/src/index.ts +++ b/apps/Backend/src/index.ts @@ -1,11 +1,38 @@ -import app from './app'; -import dotenv from 'dotenv'; +import app from "./app"; +import dotenv from "dotenv"; dotenv.config(); const HOST = process.env.HOST; const PORT = process.env.PORT; -app.listen(PORT, () => { - console.log(`Server running at http://${HOST}:${PORT}`); -}); \ No newline at end of file +const server = app.listen(PORT, () => { + console.log(`✅ Server running at http://${HOST}:${PORT}`); +}); + +// Handle startup errors +server.on("error", (err: NodeJS.ErrnoException) => { + if (err.code === "EADDRINUSE") { + console.error(`❌ Port ${PORT} is already in use`); + } else { + console.error("❌ Server failed to start:", err); + } + process.exit(1); // Exit with failure +}); + +// Graceful shutdown +const shutdown = (signal: string) => { + console.log(`⚡ Received ${signal}, shutting down gracefully...`); + + server.close(() => { + console.log("✅ HTTP server closed"); + + // TODO: Close DB connections if needed + // db.$disconnect().then(() => console.log("✅ Database disconnected")); + + process.exit(0); + }); +}; + +process.on("SIGINT", () => shutdown("SIGINT")); +process.on("SIGTERM", () => shutdown("SIGTERM")); diff --git a/apps/Backend/src/routes/database-management.ts b/apps/Backend/src/routes/database-management.ts index d8ac518..4c21ae6 100644 --- a/apps/Backend/src/routes/database-management.ts +++ b/apps/Backend/src/routes/database-management.ts @@ -4,6 +4,7 @@ import path from "path"; import os from "os"; import fs from "fs"; import { prisma } from "@repo/db/client"; +import { storage } from "../storage"; const router = Router(); @@ -11,8 +12,13 @@ const router = Router(); * Create a database backup */ -router.post("/backup", async (req: Request, res: Response) => { +router.post("/backup", async (req: Request, res: Response): Promise => { try { + const userId = req.user?.id; + if (!userId) { + return res.status(401).json({ error: "Unauthorized" }); + } + const fileName = `dental_backup_${Date.now()}.dump`; const tmpFile = path.join(os.tmpdir(), fileName); @@ -56,8 +62,16 @@ router.post("/backup", async (req: Request, res: Response) => { const fileStream = fs.createReadStream(tmpFile); fileStream.pipe(res); - fileStream.on("close", () => { + fileStream.on("close", async () => { fs.unlink(tmpFile, () => {}); // cleanup temp file + + // ✅ Then, in background, update DB + try { + await storage.createBackup(userId); + await storage.deleteNotificationsByType(userId, "BACKUP"); + } catch (err) { + console.error("Backup saved but metadata update failed:", err); + } }); } else { console.error("pg_dump failed:", errorMessage); @@ -91,18 +105,25 @@ router.post("/backup", async (req: Request, res: Response) => { /** * Get database status (connected, size, records count) */ -router.get("/status", async (req: Request, res: Response) => { +router.get("/status", async (req: Request, res: Response): Promise => { try { + const userId = req.user?.id; + if (!userId) { + return res.status(401).json({ error: "Unauthorized" }); + } + const size = await prisma.$queryRawUnsafe<{ size: string }[]>( "SELECT pg_size_pretty(pg_database_size(current_database())) as size" ); - const patientsCount = await prisma.patient.count(); + const patientsCount = await storage.getTotalPatientCount(); + const lastBackup = await storage.getLastBackup(userId); res.json({ connected: true, size: size[0]?.size, patients: patientsCount, + lastBackup: lastBackup?.createdAt ?? null, }); } catch (err) { console.error("Status error:", err); diff --git a/apps/Backend/src/routes/index.ts b/apps/Backend/src/routes/index.ts index 08a787b..e177dfb 100644 --- a/apps/Backend/src/routes/index.ts +++ b/apps/Backend/src/routes/index.ts @@ -10,6 +10,7 @@ import documentsRoutes from "./documents"; import insuranceEligibilityRoutes from "./insuranceEligibility"; import paymentsRoutes from "./payments"; import databaseManagementRoutes from "./database-management"; +import notificationsRoutes from "./notifications"; const router = Router(); @@ -24,5 +25,6 @@ router.use("/documents", documentsRoutes); router.use("/insuranceEligibility", insuranceEligibilityRoutes); router.use("/payments", paymentsRoutes); router.use("/database-management", databaseManagementRoutes); +router.use("/notifications", notificationsRoutes); export default router; diff --git a/apps/Backend/src/routes/notifications.ts b/apps/Backend/src/routes/notifications.ts new file mode 100644 index 0000000..72b583b --- /dev/null +++ b/apps/Backend/src/routes/notifications.ts @@ -0,0 +1,34 @@ +import { Router, Request, Response } from "express"; +import { prisma } from "@repo/db/client"; + +const router = Router(); + +router.get("/", async (req, res) => { + const userId = (req as any).user?.id; + const notifications = await prisma.notification.findMany({ + where: { userId }, + orderBy: { createdAt: "desc" }, + take: 20, + }); + res.json(notifications); +}); + +router.post("/:id/read", async (req, res) => { + const userId = (req as any).user?.id; + await prisma.notification.updateMany({ + where: { id: Number(req.params.id), userId }, + data: { read: true }, + }); + res.json({ success: true }); +}); + +router.post("/read-all", async (req, res) => { + const userId = (req as any).user?.id; + await prisma.notification.updateMany({ + where: { userId }, + data: { read: true }, + }); + res.json({ success: true }); +}); + +export default router; diff --git a/apps/Backend/src/storage/index.ts b/apps/Backend/src/storage/index.ts index 3d16563..e37a507 100644 --- a/apps/Backend/src/storage/index.ts +++ b/apps/Backend/src/storage/index.ts @@ -4,6 +4,7 @@ import { Appointment, Claim, ClaimWithServiceLines, + DatabaseBackup, InsertAppointment, InsertClaim, InsertInsuranceCredential, @@ -11,6 +12,8 @@ import { InsertPayment, InsertUser, InsuranceCredential, + Notification, + NotificationTypes, Patient, Payment, PaymentWithExtras, @@ -27,6 +30,7 @@ import { export interface IStorage { // User methods getUser(id: number): Promise; + getUsers(limit: number, offset: number): Promise; getUserByUsername(username: string): Promise; createUser(user: InsertUser): Promise; updateUser(id: number, updates: Partial): Promise; @@ -176,10 +180,7 @@ export interface IStorage { // Payment methods: createPayment(data: InsertPayment): Promise; - updatePayment( - id: number, - updates: UpdatePayment, - ): Promise; + updatePayment(id: number, updates: UpdatePayment): Promise; deletePayment(id: number, userId: number): Promise; getPaymentById(id: number): Promise; getRecentPaymentsByPatientId( @@ -188,19 +189,41 @@ export interface IStorage { offset: number ): Promise; getTotalPaymentCountByPatient(patientId: number): Promise; - getPaymentsByClaimId( - claimId: number, - ): Promise; + getPaymentsByClaimId(claimId: number): Promise; getRecentPaymentsByUser( userId: number, limit: number, offset: number ): Promise; - getPaymentsByDateRange( - from: Date, - to: Date - ): Promise; + getPaymentsByDateRange(from: Date, to: Date): Promise; getTotalPaymentCountByUser(userId: number): Promise; + + // Database Backup methods + createBackup(userId: number): Promise; + getLastBackup(userId: number): Promise; + getBackups(userId: number, limit?: number): Promise; + deleteBackups(userId: number): Promise; // clears all for user + + // Notification methods + createNotification( + userId: number, + type: NotificationTypes, + message: string + ): Promise; + getNotifications( + userId: number, + limit?: number, + offset?: number + ): Promise; + markNotificationRead( + userId: number, + notificationId: number + ): Promise; + markAllNotificationsRead(userId: number): Promise; + deleteNotificationsByType( + userId: number, + type: NotificationTypes + ): Promise; } export const storage: IStorage = { @@ -210,6 +233,10 @@ export const storage: IStorage = { return user ?? undefined; }, + async getUsers(limit: number, offset: number): Promise { + return await db.user.findMany({ skip: offset, take: limit }); + }, + async getUserByUsername(username: string): Promise { const user = await db.user.findUnique({ where: { username } }); return user ?? undefined; @@ -736,10 +763,7 @@ export const storage: IStorage = { return db.payment.create({ data: payment as Payment }); }, - async updatePayment( - id: number, - updates: UpdatePayment, - ): Promise { + async updatePayment(id: number, updates: UpdatePayment): Promise { const existing = await db.payment.findFirst({ where: { id } }); if (!existing) { throw new Error("Payment not found"); @@ -799,9 +823,7 @@ export const storage: IStorage = { }); }, - async getPaymentById( - id: number, - ): Promise { + async getPaymentById(id: number): Promise { const payment = await db.payment.findFirst({ where: { id }, include: { @@ -830,7 +852,7 @@ export const storage: IStorage = { }, async getPaymentsByClaimId( - claimId: number, + claimId: number ): Promise { const payment = await db.payment.findFirst({ where: { claimId }, @@ -930,4 +952,76 @@ export const storage: IStorage = { async getTotalPaymentCountByUser(userId: number): Promise { return db.payment.count({ where: { userId } }); }, + + // ============================== + // Database Backup methods + // ============================== + async createBackup(userId) { + return await db.databaseBackup.create({ data: { userId } }); + }, + + async getLastBackup(userId) { + return await db.databaseBackup.findFirst({ + where: { userId }, + orderBy: { createdAt: "desc" }, + }); + }, + + async getBackups(userId, limit = 10) { + return await db.databaseBackup.findMany({ + where: { userId }, + orderBy: { createdAt: "desc" }, + take: limit, + }); + }, + + async deleteBackups(userId) { + const result = await db.databaseBackup.deleteMany({ where: { userId } }); + return result.count; + }, + + // ============================== + // Notification methods + // ============================== + async createNotification(userId, type, message) { + return await db.notification.create({ + data: { userId, type, message }, + }); + }, + + async getNotifications( + userId: number, + limit = 50, + offset = 0 + ): Promise { + return await db.notification.findMany({ + where: { userId }, + orderBy: { createdAt: "desc" }, + take: limit, + skip: offset, + }); + }, + + async markNotificationRead(userId, notificationId) { + const result = await db.notification.updateMany({ + where: { id: notificationId, userId }, + data: { read: true }, + }); + return result.count > 0; + }, + + async markAllNotificationsRead(userId) { + const result = await db.notification.updateMany({ + where: { userId }, + data: { read: true }, + }); + return result.count; + }, + + async deleteNotificationsByType(userId, type) { + const result = await db.notification.deleteMany({ + where: { userId, type }, + }); + return result.count; + }, }; diff --git a/apps/Frontend/src/components/layout/notification-bell.tsx b/apps/Frontend/src/components/layout/notification-bell.tsx new file mode 100644 index 0000000..bce0754 --- /dev/null +++ b/apps/Frontend/src/components/layout/notification-bell.tsx @@ -0,0 +1,287 @@ +import { useMemo, useState } from "react"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { motion, AnimatePresence } from "framer-motion"; +import { Bell, Check, Loader2 } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { apiRequest, queryClient } from "@/lib/queryClient"; +import { useToast } from "@/hooks/use-toast"; +import { Notification } from "@repo/db/types"; +import { formatDateToHumanReadable} from "@/utils/dateUtils"; + +const PAGE_SIZE = 5; + +export function NotificationsBell() { + const { toast } = useToast(); + + // dialog / pagination state (client-side over fetched 20) + const [open, setOpen] = useState(false); + const [pageIndex, setPageIndex] = useState(0); // 0..N (each page size 5) + + // ------- Single load (no polling): fetch up to 20 latest notifications ------- + const listQuery = useQuery({ + queryKey: ["/notifications"], + queryFn: async (): Promise => { + const res = await apiRequest("GET", "/api/notifications"); + if (!res.ok) throw new Error("Failed to fetch notifications"); + return res.json(); + }, + refetchOnWindowFocus: false, + staleTime: Infinity, + gcTime: Infinity, + }); + + const all = listQuery.data ?? []; + const unread = useMemo(() => all.filter((n) => !n.read), [all]); + const unreadCount = unread.length; + + // latest unread for spotlight + const latestUnread = unread[0] ?? null; + + // client-side dialog pagination over the fetched 20 + const totalPages = Math.max(1, Math.ceil(all.length / PAGE_SIZE)); + const currentPageItems = useMemo(() => { + const start = pageIndex * PAGE_SIZE; + return all.slice(start, start + PAGE_SIZE); + }, [all, pageIndex]); + + // ------- mutations ------- + const markRead = useMutation({ + mutationFn: async (id: number) => { + const res = await apiRequest("POST", `/api/notifications/${id}/read`); + if (!res.ok) throw new Error("Failed to mark as read"); + }, + onMutate: async (id) => { + // optimistic update in cache + await queryClient.cancelQueries({ queryKey: ["/notifications"] }); + const prev = queryClient.getQueryData(["/notifications"]); + if (prev) { + queryClient.setQueryData( + ["/notifications"], + prev.map((n) => (n.id === id ? { ...n, read: true } : n)) + ); + } + return { prev }; + }, + onError: (_e, _id, ctx) => { + if (ctx?.prev) queryClient.setQueryData(["/notifications"], ctx.prev); + toast({ + title: "Error", + description: "Failed to update notification", + variant: "destructive", + }); + }, + }); + + const markAllRead = useMutation({ + mutationFn: async () => { + const res = await apiRequest("POST", "/api/notifications/read-all"); + if (!res.ok) throw new Error("Failed to mark all as read"); + }, + onMutate: async () => { + await queryClient.cancelQueries({ queryKey: ["/notifications"] }); + const prev = queryClient.getQueryData(["/notifications"]); + if (prev) { + queryClient.setQueryData( + ["/notifications"], + prev.map((n) => ({ ...n, read: true })) + ); + } + return { prev }; + }, + onError: (_e, _id, ctx) => { + if (ctx?.prev) queryClient.setQueryData(["/notifications"], ctx.prev); + toast({ + title: "Error", + description: "Failed to mark all as read", + variant: "destructive", + }); + }, + }); + + // when opening dialog, reset to first page + const onOpenChange = async (v: boolean) => { + setOpen(v); + if (v) { + setPageIndex(0); + await listQuery.refetch(); + } + }; + + return ( +
+ {/* Bell + unread badge */} + + + + + + {/* Dialog (client-side pagination over the 20 we already fetched) */} + + + Notifications + + + {listQuery.isLoading ? ( +
+ +
+ ) : all.length === 0 ? ( +

No notifications yet.

+ ) : ( + <> +
+ {currentPageItems.map((n) => ( +
+
+

{n.message}

+

+ {formatDateToHumanReadable(n.createdAt)} +

+
+ {!n.read ? ( + + ) : ( + Read + )} +
+ ))} +
+ +
+ +
+ Page {pageIndex + 1} / {totalPages} +
+ +
+ +
+ +
+ + )} +
+
+ + {/* Spotlight: ONE latest unread (animates in; collapses when marked read) */} + + {latestUnread && ( + +
+ {/* animated halo */} + +
+
+
+ {/* ping dot */} + + + + +
+
+

+ {latestUnread.message} +

+

+ {formatDateToHumanReadable(latestUnread.createdAt)} +

+
+
+ +
+ +
+
+
+
+ )} +
+
+ ); +} diff --git a/apps/Frontend/src/components/layout/top-app-bar.tsx b/apps/Frontend/src/components/layout/top-app-bar.tsx index eb8ad2b..8fdb977 100644 --- a/apps/Frontend/src/components/layout/top-app-bar.tsx +++ b/apps/Frontend/src/components/layout/top-app-bar.tsx @@ -10,6 +10,7 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { useLocation } from "wouter"; +import { NotificationsBell } from "@/components/layout/notification-bell"; interface TopAppBarProps { toggleMobileMenu: () => void; @@ -49,14 +50,7 @@ export function TopAppBar({ toggleMobileMenu }: TopAppBarProps) {
- + diff --git a/package-lock.json b/package-lock.json index e2fedef..f653d58 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,6 +46,7 @@ "form-data": "^4.0.2", "jsonwebtoken": "^9.0.2", "multer": "^2.0.0", + "node-cron": "^4.2.1", "passport": "^0.7.0", "passport-local": "^1.0.0", "ws": "^8.18.0", @@ -9378,6 +9379,15 @@ "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", "license": "MIT" }, + "node_modules/node-cron": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-4.2.1.tgz", + "integrity": "sha512-lgimEHPE/QDgFlywTd8yTR61ptugX3Qer29efeyWw2rv259HtGBNn1vZVmp8lB9uo9wC0t/AT4iGqXxia+CJFg==", + "license": "ISC", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", diff --git a/packages/db/prisma/schema.prisma b/packages/db/prisma/schema.prisma index cbb82c7..a39f3c5 100644 --- a/packages/db/prisma/schema.prisma +++ b/packages/db/prisma/schema.prisma @@ -27,8 +27,9 @@ model User { appointments Appointment[] claims Claim[] insuranceCredentials InsuranceCredential[] - // reverse relations updatedPayments Payment[] @relation("PaymentUpdatedBy") + backups DatabaseBackup[] + notifications Notification[] } model Patient { @@ -258,3 +259,35 @@ enum PaymentMethod { CARD OTHER } + +model DatabaseBackup { + id Int @id @default(autoincrement()) + userId Int + createdAt DateTime @default(now()) + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@index([userId]) + @@index([createdAt]) +} + +model Notification { + id Int @id @default(autoincrement()) + userId Int + type NotificationTypes + message String + createdAt DateTime @default(now()) + read Boolean @default(false) + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@index([userId]) + @@index([createdAt]) +} + +enum NotificationTypes { + BACKUP + CLAIM + PAYMENT + ETC +} diff --git a/packages/db/types/databaseBackup-types.ts b/packages/db/types/databaseBackup-types.ts new file mode 100644 index 0000000..cff1444 --- /dev/null +++ b/packages/db/types/databaseBackup-types.ts @@ -0,0 +1,6 @@ +import { DatabaseBackupUncheckedCreateInputObjectSchema } from "@repo/db/usedSchemas"; +import { z } from "zod"; + +export type DatabaseBackup = z.infer< + typeof DatabaseBackupUncheckedCreateInputObjectSchema +>; diff --git a/packages/db/types/index.ts b/packages/db/types/index.ts index f1c72d7..aef115d 100644 --- a/packages/db/types/index.ts +++ b/packages/db/types/index.ts @@ -5,4 +5,6 @@ export * from "./patient-types";; export * from "./payment-types"; export * from "./pdf-types"; export * from "./staff-types"; -export * from "./user-types"; \ No newline at end of file +export * from "./user-types"; +export * from "./databaseBackup-types"; +export * from "./notifications-types"; diff --git a/packages/db/types/notifications-types.ts b/packages/db/types/notifications-types.ts new file mode 100644 index 0000000..64219af --- /dev/null +++ b/packages/db/types/notifications-types.ts @@ -0,0 +1,11 @@ +import { + NotificationTypesSchema, + NotificationUncheckedCreateInputObjectSchema, +} from "@repo/db/usedSchemas"; +import { z } from "zod"; + +export type Notification = z.infer< + typeof NotificationUncheckedCreateInputObjectSchema +>; + +export type NotificationTypes = z.infer; diff --git a/packages/db/usedSchemas/index.ts b/packages/db/usedSchemas/index.ts index 2a16023..4de9d82 100644 --- a/packages/db/usedSchemas/index.ts +++ b/packages/db/usedSchemas/index.ts @@ -12,4 +12,7 @@ export * from '../shared/schemas/enums/ClaimStatus.schema' export * from '../shared/schemas/objects/PaymentUncheckedCreateInput.schema' export * from '../shared/schemas/objects/ServiceLineTransactionCreateInput.schema' export * from '../shared/schemas/enums/PaymentMethod.schema' -export * from '../shared/schemas/enums/PaymentStatus.schema' \ No newline at end of file +export * from '../shared/schemas/enums/PaymentStatus.schema' +export * from '../shared/schemas/enums/NotificationTypes.schema' +export * from '../shared/schemas/objects/NotificationUncheckedCreateInput.schema' +export * from '../shared/schemas/objects/DatabaseBackupUncheckedCreateInput.schema'