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:
ff
2026-05-17 22:31:12 -04:00
parent b9e888fc7f
commit 5508a90d28
231 changed files with 1629 additions and 14854 deletions

View File

@@ -30,7 +30,6 @@ model User {
npiProviders NpiProvider[]
claims Claim[]
insuranceCredentials InsuranceCredential[]
shoppingVendors ShoppingVendor[]
updatedPayments Payment[] @relation("PaymentUpdatedBy")
backups DatabaseBackup[]
backupDestinations BackupDestination[]
@@ -43,8 +42,6 @@ model User {
officeHours OfficeHours?
officeContact OfficeContact?
procedureTimeslot ProcedureTimeslot?
insuranceContacts InsuranceContact[]
patientConversations PatientConversation[]
}
model Patient {
@@ -64,7 +61,6 @@ model Patient {
policyHolder String?
allergies String?
medicalConditions String?
preferredLanguage String? @default("English")
status PatientStatus @default(UNKNOWN)
userId Int
createdAt DateTime @default(now())
@@ -77,7 +73,6 @@ model Patient {
payment Payment[]
communications Communication[]
documents PatientDocument[]
conversation PatientConversation?
@@index([insuranceId])
@@index([createdAt])
@@ -103,7 +98,6 @@ model Appointment {
notes String?
procedureCodeNotes String?
status String @default("scheduled") // "scheduled", "completed", "cancelled", "no-show"
movedByAi Boolean @default(false)
createdAt DateTime @default(now())
eligibilityStatus PatientStatus @default(UNKNOWN)
@@ -153,8 +147,6 @@ model NpiProvider {
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
claims Claim[]
payments Payment[]
commissionBatches CommissionBatch[]
appointmentProcedures AppointmentProcedure[]
@@unique([userId, npiNumber])
@@ -198,7 +190,7 @@ model AppointmentProcedure {
model Claim {
id Int @id @default(autoincrement())
patientId Int
appointmentId Int?
appointmentId Int
userId Int
staffId Int
patientName String
@@ -213,11 +205,10 @@ model Claim {
updatedAt DateTime @updatedAt
status ClaimStatus @default(PENDING)
claimNumber String?
preAuthNumber String?
npiProviderId Int?
patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
appointment Appointment? @relation(fields: [appointmentId], references: [id], onDelete: Cascade)
appointment Appointment @relation(fields: [appointmentId], references: [id], onDelete: Cascade)
user User? @relation(fields: [userId], references: [id])
staff Staff? @relation("ClaimStaff", fields: [staffId], references: [id])
npiProvider NpiProvider? @relation(fields: [npiProviderId], references: [id])
@@ -233,7 +224,6 @@ enum ClaimStatus {
CANCELLED
REVIEW
VOID
PREAUTH
}
enum MissingTeethStatus {
@@ -252,9 +242,6 @@ model ServiceLine {
arch String?
toothNumber String?
toothSurface String?
icn String?
paidCode String?
allowedAmount Decimal? @db.Decimal(10, 2)
totalBilled Decimal @db.Decimal(10, 2)
totalPaid Decimal @default(0.00) @db.Decimal(10, 2)
totalAdjusted Decimal @default(0.00) @db.Decimal(10, 2)
@@ -300,19 +287,6 @@ model InsuranceCredential {
@@index([userId])
}
model ShoppingVendor {
id Int @id @default(autoincrement())
userId Int
vendorName String
websiteUrl String
loginUsername String
loginPassword String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
}
model PdfGroup {
id Int @id @default(autoincrement())
title String
@@ -351,14 +325,10 @@ model Payment {
patientId Int
userId Int
updatedById Int?
npiProviderId Int?
totalBilled Decimal @db.Decimal(10, 2)
totalPaid Decimal @default(0.00) @db.Decimal(10, 2)
totalAdjusted Decimal @default(0.00) @db.Decimal(10, 2)
totalDue Decimal @db.Decimal(10, 2)
mhPaidAmount Decimal? @db.Decimal(10, 2)
copayment Decimal @default(0.00) @db.Decimal(10, 2)
adjustment Decimal @default(0.00) @db.Decimal(10, 2)
status PaymentStatus @default(PENDING)
notes String?
icn String?
@@ -368,10 +338,8 @@ model Payment {
claim Claim? @relation(fields: [claimId], references: [id], onDelete: Cascade)
patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
updatedBy User? @relation("PaymentUpdatedBy", fields: [updatedById], references: [id])
npiProvider NpiProvider? @relation(fields: [npiProviderId], references: [id])
serviceLineTransactions ServiceLineTransaction[]
serviceLines ServiceLine[]
commissionBatchItems CommissionBatchItem[]
@@index([claimId])
@@index([patientId])
@@ -596,11 +564,9 @@ model TwilioSettings {
}
model AiSettings {
id Int @id @default(autoincrement())
userId Int @unique
apiKey String
afterHoursEnabled Boolean @default(true)
openPhoneReply Boolean @default(false)
id Int @id @default(autoincrement())
userId Int @unique
apiKey String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@ -620,34 +586,17 @@ model OfficeHours {
model OfficeContact {
id Int @id @default(autoincrement())
userId Int @unique
officeName String?
receptionistName String?
dentistName String?
phoneNumber String?
email String?
fax String?
streetAddress String?
city String?
state String?
zipCode String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("office_contact")
}
model InsuranceContact {
id Int @id @default(autoincrement())
userId Int
name String
phoneNumber String?
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("insurance_contact")
}
model ProcedureTimeslot {
id Int @id @default(autoincrement())
userId Int @unique
@@ -657,45 +606,3 @@ model ProcedureTimeslot {
@@map("procedure_timeslot")
}
model PatientConversation {
id Int @id @default(autoincrement())
patientId Int @unique
userId Int
stage String @default("initial")
aiHandoff Boolean @default(true)
updatedAt DateTime @updatedAt
patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("patient_conversation")
}
// Commission tracking
model CommissionBatch {
id Int @id @default(autoincrement())
npiProviderId Int
totalCollection Decimal @db.Decimal(14, 2)
commissionAmount Decimal @db.Decimal(14, 2)
notes String?
createdAt DateTime @default(now())
npiProvider NpiProvider @relation(fields: [npiProviderId], references: [id])
items CommissionBatchItem[]
@@index([npiProviderId])
}
model CommissionBatchItem {
id Int @id @default(autoincrement())
commissionBatchId Int
paymentId Int
collectionAmount Decimal @db.Decimal(14, 2)
commissionBatch CommissionBatch @relation(fields: [commissionBatchId], references: [id], onDelete: Cascade)
payment Payment @relation(fields: [paymentId], references: [id])
@@unique([commissionBatchId, paymentId])
@@index([paymentId])
}