Skip to content

Instantly share code, notes, and snippets.

@theskillwithin
Created October 20, 2025 20:33
Show Gist options
  • Select an option

  • Save theskillwithin/62f37b473b78a8c2c4c13083275b41ad to your computer and use it in GitHub Desktop.

Select an option

Save theskillwithin/62f37b473b78a8c2c4c13083275b41ad to your computer and use it in GitHub Desktop.
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
provider = "prisma-client"
// previewFeatures = ["queryCompiler", "driverAdapters"]
binaryTargets = ["native", "rhel-openssl-3.0.x"]
output = "../app/generated/prisma/client"
runtime = "nodejs"
moduleFormat = "esm"
generatedFileExtension = "ts"
importFileExtension = "ts"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator typescriptInterfaces {
provider = "prisma-generator-typescript-interfaces"
}
enum CartStatus {
ACTIVE
ABANDONED
COMPLETED
}
enum EmailStatus {
SENT
FAILED
OPENED
}
enum AbandonmentEmailType {
EMAIL_1_REMINDER
EMAIL_2_PENALTY_WARNING
EMAIL_3_URGENCY_COSTS
EMAIL_4_FINAL_NOTICE
}
enum AbandonmentEmailStatus {
SCHEDULED
SENT
FAILED
SKIPPED
}
enum CampaignStatus {
DRAFT
ACTIVE
PAUSED
COMPLETED
}
enum PaymentStatus {
PENDING
COMPLETED
FAILED
REFUNDED
}
enum AdminRole {
STAFF
ADMIN
SUPERADMIN
}
enum Tenant {
TRUCKINGTAXHUB
CLIENTBOOKS
}
model User {
id String @id @default(cuid())
email String
tenant Tenant @default(TRUCKINGTAXHUB)
name String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
stripeCustomerId String?
dataSessions UserDataSession[]
postFulfillmentData UserPostFulfillment[]
carts Cart[]
emailHistory EmailHistory[]
paymentHistory PaymentHistory[]
formSessions FormSession[]
@@unique([email, tenant])
}
model UserDataSession {
id String @id @default(cuid())
userId String?
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
sessionId String @unique
formData Json
step String
completed Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
expiresAt DateTime?
}
model FormSession {
id String @id @default(cuid())
userId String?
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
formId String
tenant Tenant @default(TRUCKINGTAXHUB)
formResponses Json @default("{}")
completedSteps String[] @default([])
completed Boolean @default(false)
orderNumber String?
salesforceContactId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
expiresAt DateTime?
@@index([userId])
@@index([formId])
@@index([tenant])
@@index([salesforceContactId])
}
model UserPostFulfillment {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
data Json
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Cart {
id String @id @default(cuid())
userId String?
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
sessionId String @unique
items CartItem[]
status CartStatus @default(ACTIVE)
total Float
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
completedAt DateTime?
orderNumber String?
salesforceContactId String?
stripeSessionSecret String?
stripeSessionExpiresAt Int?
@@unique([sessionId, status])
@@index([sessionId])
@@index([userId])
@@index([salesforceContactId])
}
model CartItem {
id String @id @default(cuid())
cartId String
cart Cart @relation(fields: [cartId], references: [id], onDelete: Cascade)
productId String
product StripeProduct @relation(fields: [productId], references: [id], onDelete: Cascade)
quantity Int @default(1)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([cartId, productId])
@@index([cartId])
@@index([productId])
}
model EmailHistory {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
template String
subject String
body String
sentAt DateTime @default(now())
status EmailStatus
metadata Json?
}
model PaymentHistory {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
amount Float
currency String @default("USD")
status PaymentStatus
paymentMethod String
paymentId String?
metadata Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model AdminUser {
id String @id @default(cuid())
email String @unique
name String
passwordHash String
role AdminRole @default(STAFF)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lastLoginAt DateTime?
adminSessions AdminSession[]
}
model AdminSession {
id String @id @default(cuid())
adminUserId String
adminUser AdminUser @relation(fields: [adminUserId], references: [id], onDelete: Cascade)
token String @unique
ipAddress String?
userAgent String?
createdAt DateTime @default(now())
expiresAt DateTime
revokedAt DateTime?
}
model StripeProduct {
id String @id @default(cuid())
stripeId String @unique
stripePriceId String? @unique
metadata Json @default("{}")
rawProductData Json @default("{}")
name String
price Float @default(0)
isUpsell Boolean @default(false)
description String?
siteSlug String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
CartItem CartItem[]
@@index([stripeId])
@@index([stripePriceId])
}
model NewsletterSubscriber {
id String @id @default(cuid())
email String @unique
firstName String
lastName String
active Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model CampaignTemplate {
id String @id @default(cuid())
name String @unique
description String?
formId String // e.g., "form-2290"
isDefault Boolean @default(false)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Template configuration
config Json @default("{}")
campaigns AbandonmentEmailCampaign[]
CampaignConfig CampaignConfig[]
@@index([formId])
@@index([isDefault])
}
model CampaignConfig {
id String @id @default(cuid())
name String @unique
description String?
formId String // e.g., "form-2290"
taxYear Int // e.g., 2024
deadlineDate DateTime // e.g., Aug 31, 2024
status CampaignStatus @default(DRAFT)
templateId String?
// Email scheduling (flexible number of emails)
emailConfigs Json @default("[]") // Array of email configurations
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
template CampaignTemplate? @relation(fields: [templateId], references: [id])
campaigns AbandonmentEmailCampaign[]
@@index([formId])
@@index([taxYear])
@@index([status])
@@index([deadlineDate])
}
model AbandonmentEmailCampaign {
id String @id @default(cuid())
formSessionId String
customerEmail String
customerName String
continueFilingUrl String
isActive Boolean @default(true)
configId String? // Links to campaign config
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
config CampaignConfig? @relation(fields: [configId], references: [id])
emails AbandonmentEmailSchedule[]
CampaignTemplate CampaignTemplate? @relation(fields: [campaignTemplateId], references: [id])
campaignTemplateId String?
@@index([formSessionId])
@@index([customerEmail])
@@index([isActive])
@@index([configId])
}
model AbandonmentEmailSchedule {
id String @id @default(cuid())
campaignId String
emailType AbandonmentEmailType
scheduledFor DateTime
sentAt DateTime?
status AbandonmentEmailStatus @default(SCHEDULED)
errorMessage String?
emailData Json @default("{}")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
campaign AbandonmentEmailCampaign @relation(fields: [campaignId], references: [id], onDelete: Cascade)
@@index([campaignId])
@@index([scheduledFor])
@@index([status])
@@index([emailType])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment