Preview: schema.prisma
Size: 16.69 KB
/home/byroehnu/easepaybiz.easetack.com/prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(uuid())
email String @unique
password String
firstName String
lastName String
phone String @unique
businessName String?
role UserRole @default(OWNER)
isActive Boolean @default(true)
emailVerified Boolean @default(false)
// OTP Fields
otp String?
otpVerificationId String? // OTP.dev verification ID
otpExpiresAt DateTime?
otpAttempts Int @default(0)
otpLockedUntil DateTime?
lastOtpSentAt DateTime?
phoneVerified Boolean @default(false)
// Authentication & Security
pin String? // 4-6 digit PIN for quick login
pinSetAt DateTime? // When PIN was set
biometricEnabled Boolean @default(false)
biometricHash String? // Hashed biometric template reference
lastLoginAt DateTime? // Last successful login
sessionToken String? // Current active session
sessionExpiresAt DateTime? // Session expiration
// Security Settings
autoLoginEnabled Boolean @default(true)
requirePinForTransactions Boolean @default(true)
loginAttempts Int @default(0)
lockedUntil DateTime? // Account lockout
// Device Management
deviceTokens DeviceToken[]
// Relations
businesses Business[]
sales Sale[]
expenses Expense[]
// New Invoice Relations
invoices Invoice[]
inventoryItems InventoryItem[]
// Subscription Details
subscription UserSubscription?
subscriptions Subscription[]
creditScores CreditScore[]
// Usage Tracking for Middleware
usage UserUsage?
// User Settings
settings UserSettings?
// Plan Limits (Set based on subscription plan)
limits UserLimits?
// Staff Roles (User can be staff in multiple businesses)
staffRoles BusinessStaff[]
// Invitations
sentInvitations StaffInvitation[] @relation("InvitedBy")
acceptedInvitations StaffInvitation[] @relation("AcceptedBy")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model DeviceToken {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
deviceId String // Unique device identifier
deviceName String? // User-friendly device name
deviceType String // ios, android, web
fcmToken String? // Firebase/push notification token
biometricId String? // Device biometric identifier
isActive Boolean @default(true)
lastUsedAt DateTime @default(now())
createdAt DateTime @default(now())
@@unique([userId, deviceId])
}
model Business {
id String @id @default(uuid())
name String
type BusinessType
ownerId String
owner User @relation(fields: [ownerId], references: [id])
vatRegistered Boolean @default(false)
hasStaff Boolean @default(false)
sales Sale[]
expenses Expense[]
// New Invoice Relations
invoices Invoice[]
inventoryItems InventoryItem[]
profile BusinessProfile?
// Staff
staff BusinessStaff[]
invitations StaffInvitation[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model StaffInvitation {
id String @id @default(uuid())
token String @unique
email String?
phone String?
role String @default("Staff")
permissions String[]
status InvitationStatus @default(PENDING)
expiresAt DateTime
businessId String
business Business @relation(fields: [businessId], references: [id])
invitedById String
invitedBy User @relation("InvitedBy", fields: [invitedById], references: [id])
acceptedById String?
acceptedBy User? @relation("AcceptedBy", fields: [acceptedById], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Sale {
id String @id @default(uuid())
amount Decimal @db.Decimal(12, 2)
description String?
paymentMethod String @default("CASH") // CASH, TRANSFER, POS
date DateTime @default(now())
userId String
user User @relation(fields: [userId], references: [id])
businessId String?
business Business? @relation(fields: [businessId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Expense {
id String @id @default(uuid())
amount Decimal @db.Decimal(12, 2)
description String
category String?
paymentMethod String @default("CASH") // CASH, TRANSFER, POS
date DateTime @default(now())
userId String
user User @relation(fields: [userId], references: [id])
businessId String?
business Business? @relation(fields: [businessId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// --- Enhanced Subscription Models with Flutterwave Integration ---
model UserSubscription {
id String @id @default(uuid())
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
// Flutterwave Integration
planId String? // Flutterwave Plan ID
planName String @default("Free")
flwCustomerId String? // Flutterwave Customer ID
flwSubscriptionId String? // Flutterwave Subscription ID
// Subscription Status
status SubscriptionStatus @default(INACTIVE)
nextBillingDate DateTime?
gracePeriodEnd DateTime? // 7 days after payment failure
// Billing
amount Decimal? @db.Decimal(10, 2)
currency String @default("NGN")
interval String? // "monthly", "yearly"
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model UserSettings {
id String @id @default(uuid())
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
// Preferences
language String @default("en")
fontSize String @default("medium")
currency String @default("NGN")
dateFormat String @default("DD/MM/YYYY")
// Toggles
lowStockAlert Boolean @default(true)
pushNotifications Boolean @default(true)
smsAlerts Boolean @default(false)
usePinCode Boolean @default(false)
useBiometrics Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model UserUsage {
id String @id @default(uuid())
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
// Usage Counters
invoiceCount Int @default(0)
teamMemberCount Int @default(1)
reportExports Int @default(0)
// Monthly Reset Tracking
lastResetDate DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model UserLimits {
id String @id @default(uuid())
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
// Plan Limits
maxInvoices Int @default(5) // Free tier limit
maxTeamMembers Int @default(1)
maxReportExports Int @default(2)
hasAdvancedReports Boolean @default(false)
hasAPIAccess Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Plan {
id String @id @default(uuid())
name String @unique // e.g., "Free", "Basic", "Pro", "Enterprise"
description String?
// Pricing
priceMonthly Decimal @db.Decimal(10, 2)
priceYearly Decimal @db.Decimal(10, 2)
currency String @default("NGN")
// Flutterwave Integration
flwPlanIdMonthly String? // Flutterwave Plan ID for monthly
flwPlanIdYearly String? // Flutterwave Plan ID for yearly
// Plan Features
maxInvoices Int
maxTeamMembers Int
maxReportExports Int
hasAdvancedReports Boolean @default(false)
hasAPIAccess Boolean @default(false)
hasPrioritySupport Boolean @default(false)
// Status
isActive Boolean @default(true)
sortOrder Int @default(0)
features Feature[]
subscriptions Subscription[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Feature {
id String @id @default(uuid())
name String @unique // e.g., "add_staff", "export_reports"
description String?
plans Plan[] // Many-to-many: Plans have features
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Subscription {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id])
planId String
plan Plan @relation(fields: [planId], references: [id])
status SubscriptionStatus @default(ACTIVE)
frequency BillingFrequency @default(MONTHLY)
startDate DateTime @default(now())
endDate DateTime // Calculated based on frequency
autoRenew Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// --- RBAC / Staff Models ---
model BusinessStaff {
id String @id @default(uuid())
businessId String
business Business @relation(fields: [businessId], references: [id])
userId String
user User @relation(fields: [userId], references: [id])
role String // e.g., "Manager", "Cashier", "Accountant"
permissions String[] // Array of permission strings e.g., ["create_sale", "view_reports"]
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([businessId, userId]) // User can only have one staff entry per business
}
// --- Enums ---
enum UserRole {
OWNER
STAFF
ADMIN
}
enum InvitationStatus {
PENDING
ACCEPTED
EXPIRED
CANCELLED
}
enum SubscriptionStatus {
ACTIVE
INACTIVE
EXPIRED
CANCELLED
PAST_DUE
SUSPENDED
}
enum BillingFrequency {
MONTHLY
YEARLY
}
enum BusinessType {
RETAIL
SERVICE
MANUFACTURING
TECHNOLOGY
CONSULTING
RESTAURANT
HEALTHCARE
EDUCATION
REAL_ESTATE
OTHER
}
model CreditScore {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id])
score Int
factors Json
recommendations Json
paymentHistoryScore Int
revenueStabilityScore Int
businessAgeScore Int
expenseManagementScore Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// --- Invoice Management Models ---
model Invoice {
id String @id @default(uuid())
invoiceNumber String @unique
// Customer Details
customerName String
customerEmail String?
customerPhone String?
customerAddress String?
// Business Details
businessId String?
business Business? @relation(fields: [businessId], references: [id])
userId String
user User @relation(fields: [userId], references: [id])
// Invoice Details
invoiceDate DateTime @default(now())
dueDate DateTime?
paymentMethod String? // Cash, Bank Transfer, Card, etc.
// Financial Details
subtotal Decimal @db.Decimal(15, 2)
discount Decimal @default(0) @db.Decimal(15, 2)
discountType DiscountType @default(FIXED) // FIXED or PERCENTAGE
vatRate Decimal @default(0) @db.Decimal(5, 2)
vatAmount Decimal @default(0) @db.Decimal(15, 2)
total Decimal @db.Decimal(15, 2)
// Status & Metadata
status InvoiceStatus @default(CREATED)
notes String?
currency String @default("NGN")
// Digital Features
qrCodeUrl String?
qrCodeData String? // Base64 encoded QR code
downloadUrl String?
shareUrl String?
// Payment Tracking
paidAmount Decimal @default(0) @db.Decimal(15, 2)
paidAt DateTime?
// Relations
items InvoiceItem[]
payments InvoicePayment[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([businessId])
@@index([userId])
@@index([status])
@@index([invoiceDate])
}
model InvoiceItem {
id String @id @default(uuid())
invoiceId String
invoice Invoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
// Item Details
itemName String
description String?
quantity Decimal @db.Decimal(10, 2)
unitPrice Decimal @db.Decimal(15, 2)
total Decimal @db.Decimal(15, 2)
// Inventory Reference (optional)
inventoryItemId String?
inventoryItem InventoryItem? @relation(fields: [inventoryItemId], references: [id])
createdAt DateTime @default(now())
}
model InvoicePayment {
id String @id @default(uuid())
invoiceId String
invoice Invoice @relation(fields: [invoiceId], references: [id])
amount Decimal @db.Decimal(15, 2)
paymentMethod String
paymentDate DateTime @default(now())
reference String? // Payment gateway reference
createdAt DateTime @default(now())
}
model InventoryItem {
id String @id @default(uuid())
businessId String?
business Business? @relation(fields: [businessId], references: [id])
userId String
user User @relation(fields: [userId], references: [id])
// Item Details
name String
description String?
category String?
// Pricing
unitPrice Decimal @db.Decimal(15, 2)
costPrice Decimal? @db.Decimal(15, 2)
// Inventory
stock Decimal @default(0) @db.Decimal(10, 2)
unit String? // piece, kg, liter, etc.
minStock Decimal? @db.Decimal(10, 2) // Reorder level
// Status
isActive Boolean @default(true)
// Relations
invoiceItems InvoiceItem[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([businessId])
@@index([userId])
@@index([category])
}
model BusinessProfile {
id String @id @default(uuid())
businessId String @unique
business Business @relation(fields: [businessId], references: [id])
// Business Information
registrationName String?
tradingName String?
email String?
phone String?
website String?
// Address
address String?
city String?
state String?
country String @default("Nigeria")
postalCode String?
// Tax Information
vatRegistration String?
tinNumber String?
rcNumber String?
bnNumber String?
// Operations
receiveMoneyMethods String[] @default(["CASH", "TRANSFER", "POS"])
// Settings
defaultCurrency String @default("NGN")
defaultVatRate Decimal @default(7.5) @db.Decimal(5, 2)
// Invoice Settings
invoicePrefix String @default("INV")
nextInvoiceNumber Int @default(1)
// Logo & Branding
logoUrl String?
brandColor String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// --- New Enums ---
enum InvoiceStatus {
DRAFT
CREATED
SENT
VIEWED
PAID
PARTIALLY_PAID
OVERDUE
CANCELLED
REFUNDED
}
enum DiscountType {
FIXED
PERCENTAGE
}
Directory Contents
Dirs: 1 × Files: 2