Database Schema
Complete Prisma database schema reference for the Keshless API.
Overview
| Metric | Count |
|---|---|
| Models | 41 |
| Enums | 25 |
| Total Lines | 1,279 |
Model Categories
| Category | Models |
|---|---|
| Core Entities | User, Vendor, VendorSubUser, AdminEmployee, NFCCard, OTP, Notification |
| Transactions | WalletTransaction, UserWalletTransaction, VendorWalletTransaction, UserTransactionTracking, WithdrawalRequest |
| Accounting | ChartOfAccounts, JournalEntry, LedgerEntry, AccountBalance, UserAccountBalance, VendorAccountBalance, UserJournalEntry, VendorJournalEntry, Reconciliation |
| AML/Compliance | CustomerRiskProfile, Alert, AMLRule, RuleViolation, SAR, PEP, SanctionsListSync, RiskScoreHistory, MonitoringConfig, MonitoringAuditLog |
| System | AuditLog, EmergencyControl, SystemEmergencyControl, Job, Integration, KeshlessUserAccess |
| Configuration | FeeConfig, TransactionLimitConfig, PINConfig, FAQ |
| Other | Till, CardOperationRequest, ParkingRate, ParkingSession |
Entity Relationship Diagrams
Core Entities
Transaction Flow
Accounting System
AML/Compliance System
Relationships Reference
User Relationships
| Relation | Type | Target | Description |
|---|---|---|---|
| assignedCard | 1:1 | NFCCard | Physical NFC card |
| customerRiskProfile | 1:1 | CustomerRiskProfile | AML risk assessment |
| walletTransactions | 1:many | UserWalletTransaction | Transaction links |
| journalEntries | 1:many | UserJournalEntry | Accounting entries |
| accountBalances | 1:many | UserAccountBalance | Balance records |
| transactionTracking | 1:many | UserTransactionTracking | Limit tracking |
| alerts | 1:many | Alert | Compliance alerts |
| sars | 1:many | SAR | Suspicious activity reports |
| referredBy | self | User | Referral source |
| referrals | self | User[] | Users referred |
Vendor Relationships
| Relation | Type | Target | Description |
|---|---|---|---|
| subUsers | 1:many | VendorSubUser | Cashiers/employees |
| walletTransactions | 1:many | VendorWalletTransaction | Transaction links |
| journalEntries | 1:many | VendorJournalEntry | Accounting entries |
| accountBalances | 1:many | VendorAccountBalance | Balance records |
| integrations | 1:many | Integration | API integrations |
| tills | 1:many | Till | Cash registers |
| withdrawalRequests | 1:many | WithdrawalRequest | Withdrawal requests |
| alerts | 1:many | Alert | Compliance alerts |
| sars | 1:many | SAR | Suspicious activity reports |
Transaction Relationships
| Model | Relation | Target |
|---|---|---|
| WalletTransaction | userLink | UserWalletTransaction |
| WalletTransaction | vendorLink | VendorWalletTransaction |
| WalletTransaction | alerts | Alert[] |
| JournalEntry | ledgerEntries | LedgerEntry[] |
| JournalEntry | userLink | UserJournalEntry |
| JournalEntry | vendorLink | VendorJournalEntry |
| AccountBalance | userLink | UserAccountBalance |
| AccountBalance | vendorLink | VendorAccountBalance |
Full Schema
Core Models
User
prisma
model User {
id String @id @default(cuid())
email String? @unique
password String?
firstName String?
lastName String?
phoneNumber String? @unique
isActive Boolean @default(true)
isVerified Boolean @default(false)
role UserRole @default(USER)
walletBalance Decimal @default(0) @db.Decimal(15, 2)
walletId String? @unique
walletPin String?
nfcCardNumber String? @unique
cardLinkedAt DateTime?
surname String?
names String?
personalIdNumber String? @unique
dateOfBirth DateTime?
sex String?
gender String?
chiefCode String?
sourceOfFunds String?
occupation String?
expectedMonthlySalary Decimal? @db.Decimal(15, 2)
idFrontImage String?
idBackImage String?
selfieImage String?
verificationStatus VerificationStatus @default(PENDING)
ocrExtractedData Json?
currentRiskScore Int @default(0)
riskRating RiskRating @default(LOW)
isPEP Boolean @default(false)
pepDetails Json?
accountRestrictions Json?
enhancedMonitoring Boolean @default(false)
rewardsPoints Int @default(0)
totalRewardsEarned Int @default(0)
referralCode String? @unique
referredById String?
totalReferrals Int @default(0)
profilePhoto String?
preferences Json?
deletionRequested Boolean @default(false)
deletionRequestedAt DateTime?
deletionScheduledFor DateTime?
deletedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
isSanctioned Boolean @default(false)
sanctionsDetails Json?
assignedAlerts Alert[] @relation("AlertAssignedTo")
alerts Alert[] @relation("UserAlerts")
resolvedAlerts Alert[] @relation("AlertResolvedBy")
customerRiskProfile CustomerRiskProfile?
assignedCard NFCCard?
sars SAR[] @relation("UserSARs")
filedSars SAR[] @relation("SARFiledBy")
accountBalances UserAccountBalance[]
journalEntries UserJournalEntry[]
transactionTracking UserTransactionTracking[]
walletTransactions UserWalletTransaction[]
referredBy User? @relation("UserReferrals", fields: [referredById], references: [id])
referrals User[] @relation("UserReferrals")
@@index([verificationStatus])
@@index([riskRating])
@@index([currentRiskScore])
@@index([isPEP])
@@index([isSanctioned])
@@index([createdAt])
@@map("users")
}Vendor
prisma
model Vendor {
id String @id @default(cuid())
email String? @unique
phoneNumber String? @unique
password String
businessName String
slug String @unique
subUserCounter Int @default(0)
businessType BusinessType @default(OTHER)
vendorType VendorType?
businessRegistration String? @unique
taxNumber String? @unique
primaryContact String?
address Json?
location Json?
leaseAgreement String?
directorIdFront String?
directorIdBack String?
formJ String?
formC String?
kycDocuments Json?
verificationStatus VendorVerificationStatus @default(PENDING)
verifiedAt DateTime?
verifiedById String?
rejectionReason String?
walletBalance Decimal @default(0) @db.Decimal(15, 2)
walletId String? @unique
walletPin String?
firstLoginPin String?
firstLoginPinExpiry DateTime?
firstLoginPinUsed Boolean @default(false)
mustChangePassword Boolean @default(true)
firstLogin Boolean @default(true)
acceptsNFC Boolean @default(true)
terminalId String? @unique
isActive Boolean @default(true)
isVerified Boolean @default(false)
deletionRequested Boolean @default(false)
deletionRequestedAt DateTime?
deletionScheduledFor DateTime?
deletedById String?
currentRiskScore Int @default(0)
riskRating RiskRating @default(LOW)
isPEP Boolean @default(false)
accountRestrictions Json?
enhancedMonitoring Boolean @default(false)
apps Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
alerts Alert[] @relation("VendorAlerts")
integrations Integration[]
sars SAR[] @relation("VendorSARs")
tills Till[]
accountBalances VendorAccountBalance[]
journalEntries VendorJournalEntry[]
subUsers VendorSubUser[]
walletTransactions VendorWalletTransaction[]
withdrawalRequests WithdrawalRequest[]
@@index([verificationStatus, createdAt])
@@index([isActive, isVerified])
@@index([riskRating])
@@index([currentRiskScore])
@@map("vendors")
}VendorSubUser
prisma
model VendorSubUser {
id String @id @default(cuid())
vendorId String
name String
username String @unique
email String? @unique
phoneNumber String? @unique
password String?
pin String?
role String @default("cashier")
permissions Json?
isActive Boolean @default(true)
firstLogin Boolean @default(true)
mustChangePassword Boolean @default(true)
firstLoginPin String?
firstLoginPinExpiry DateTime?
firstLoginPinUsed Boolean @default(false)
lastLoginAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
vendor Vendor @relation(fields: [vendorId], references: [id], onDelete: Cascade)
@@index([vendorId])
@@map("vendor_sub_users")
}AdminEmployee
prisma
model AdminEmployee {
id String @id @default(cuid())
email String @unique
password String
firstName String
lastName String
phoneNumber String? @unique
role AdminEmployeeRole @default(CUSTOM)
permissions Json
isActive Boolean @default(true)
createdById String?
firstLogin Boolean @default(true)
mustChangePassword Boolean @default(true)
lastLoginAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([role])
@@index([isActive])
@@index([email])
@@map("admin_employees")
}NFCCard
prisma
model NFCCard {
id String @id @default(cuid())
cardNumber String @unique
status CardStatus @default(AVAILABLE)
assignedUserId String? @unique
linkedAt DateTime?
expiryMonth Int?
expiryYear Int?
blockedReason String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
assignedUser User? @relation(fields: [assignedUserId], references: [id])
@@index([status])
@@map("nfc_cards")
}OTP
prisma
model OTP {
id String @id @default(cuid())
phoneNumber String
otp String
purpose OTPPurpose
isVerified Boolean @default(false)
attempts Int @default(0)
expiresAt DateTime
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([phoneNumber, purpose, isVerified])
@@index([expiresAt])
@@map("otps")
}Notification
prisma
model Notification {
id String @id @default(cuid())
recipientType String
recipientUserId String?
recipientVendorId String?
title String
message String
type String
data Json?
isRead Boolean @default(false)
readAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([recipientUserId, isRead, createdAt])
@@index([recipientVendorId, isRead, createdAt])
@@map("notifications")
}Transaction Models
WalletTransaction
prisma
model WalletTransaction {
id String @id @default(cuid())
type WalletTransactionType
amount Decimal @db.Decimal(15, 2)
balanceBefore Decimal @db.Decimal(15, 2)
balanceAfter Decimal @db.Decimal(15, 2)
status WalletTransactionStatus @default(PENDING)
description String?
reference String? @unique
counterpartyUserId String?
counterpartyVendorId String?
performedById String?
performedByType String?
vendorContextId String?
metadata Json?
processedAt DateTime?
failureReason String?
amlScreened Boolean @default(false)
amlStatus AMLStatus @default(NOT_SCREENED)
amlScreenedAt DateTime?
riskFlags String[]
suspicionScore Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
counterpartyType String?
entityType String?
entityUserId String?
entityVendorId String?
userLink UserWalletTransaction?
vendorLink VendorWalletTransaction?
alerts Alert[] @relation("AlertToWalletTransaction")
@@index([status, createdAt])
@@index([type, status, createdAt])
@@index([entityUserId, createdAt])
@@index([entityVendorId, createdAt])
@@index([entityType, createdAt])
@@map("wallet_transactions")
}UserWalletTransaction
prisma
model UserWalletTransaction {
id String @id @default(cuid())
userId String
transactionId String @unique
transaction WalletTransaction @relation(fields: [transactionId], references: [id])
user User @relation(fields: [userId], references: [id])
@@index([userId])
@@map("user_wallet_transactions")
}VendorWalletTransaction
prisma
model VendorWalletTransaction {
id String @id @default(cuid())
vendorId String
transactionId String @unique
transaction WalletTransaction @relation(fields: [transactionId], references: [id])
vendor Vendor @relation(fields: [vendorId], references: [id])
@@index([vendorId])
@@map("vendor_wallet_transactions")
}UserTransactionTracking
prisma
model UserTransactionTracking {
id String @id @default(cuid())
userId String
transactionType String
periodStart DateTime
periodEnd DateTime
dailyAmount Decimal @default(0) @db.Decimal(15, 2)
dailyCount Int @default(0)
monthlyAmount Decimal @default(0) @db.Decimal(15, 2)
monthlyCount Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
userType String?
user User @relation(fields: [userId], references: [id])
@@unique([userId, transactionType, periodStart])
@@index([userId, transactionType])
@@map("user_transaction_trackings")
}WithdrawalRequest
prisma
model WithdrawalRequest {
id String @id @default(cuid())
requesterType String
requesterUserId String?
requesterVendorId String?
amount Decimal @db.Decimal(15, 2)
fee Decimal @default(0) @db.Decimal(15, 2)
netAmount Decimal @db.Decimal(15, 2)
status WithdrawalRequestStatus @default(PENDING)
bankName String?
accountNumber String?
accountHolder String?
processedById String?
processedAt DateTime?
rejectionReason String?
walletTransactionId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
vendor Vendor? @relation(fields: [requesterVendorId], references: [id])
@@index([requesterVendorId, status])
@@index([status, createdAt])
@@map("withdrawal_requests")
}Accounting Models
ChartOfAccounts
prisma
model ChartOfAccounts {
id String @id @default(cuid())
accountCode String @unique
accountName String
accountType AccountType
normalBalance NormalBalance
parentCode String?
level Int @default(1)
description String?
isActive Boolean @default(true)
isSummary Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([accountType])
@@index([isActive])
@@map("chart_of_accounts")
}JournalEntry
prisma
model JournalEntry {
id String @id @default(cuid())
journalId String @unique
entryType JournalEntryType
transactionDate DateTime
postingDate DateTime?
status JournalEntryStatus @default(PENDING)
totalDebits Decimal @db.Decimal(15, 2)
totalCredits Decimal @db.Decimal(15, 2)
currency String @default("E")
walletTransactionId String?
transactionId String?
reversedByJournalId String?
reversalOfJournalId String?
description String
notes String?
metadata Json?
amlScreened Boolean @default(false)
amlStatus String?
riskScore Int?
createdById String?
postedById String?
reversedById String?
ipAddress String?
deviceId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
ledgerEntries LedgerEntry[]
userLink UserJournalEntry?
vendorLink VendorJournalEntry?
@@index([status, transactionDate])
@@index([entryType, status, transactionDate])
@@index([walletTransactionId])
@@index([amlStatus, status])
@@index([createdAt])
@@map("journal_entries")
}LedgerEntry
prisma
model LedgerEntry {
id String @id @default(cuid())
entryId String @unique
journalEntryId String
accountCode String
accountName String
debit Decimal @default(0) @db.Decimal(15, 2)
credit Decimal @default(0) @db.Decimal(15, 2)
runningBalance Decimal @default(0) @db.Decimal(15, 2)
currency String @default("E")
entityType String?
entityUserId String?
entityVendorId String?
counterpartyType String?
counterpartyUserId String?
counterpartyVendorId String?
walletTransactionId String?
transactionId String?
transactionDate DateTime
postingDate DateTime?
description String?
createdById String?
ipAddress String?
deviceId String?
isPosted Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
journalEntry JournalEntry @relation(fields: [journalEntryId], references: [id])
@@index([journalEntryId])
@@index([accountCode, isPosted])
@@index([entityUserId, transactionDate])
@@index([entityVendorId, transactionDate])
@@map("ledger_entries")
}AccountBalance
prisma
model AccountBalance {
id String @id @default(cuid())
accountCode String
accountName String
balance Decimal @default(0) @db.Decimal(15, 2)
debitTotal Decimal @default(0) @db.Decimal(15, 2)
creditTotal Decimal @default(0) @db.Decimal(15, 2)
currency String @default("E")
lastLedgerEntryId String?
lastJournalEntryId String?
lastTransactionDate DateTime?
version Int @default(0)
isReconciled Boolean @default(true)
lastReconciledAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
userLink UserAccountBalance?
vendorLink VendorAccountBalance?
@@index([accountCode])
@@map("account_balances")
}UserAccountBalance
prisma
model UserAccountBalance {
id String @id @default(cuid())
userId String
accountBalanceId String @unique
accountBalance AccountBalance @relation(fields: [accountBalanceId], references: [id])
user User @relation(fields: [userId], references: [id])
@@unique([userId, accountBalanceId])
@@index([userId])
@@map("user_account_balances")
}VendorAccountBalance
prisma
model VendorAccountBalance {
id String @id @default(cuid())
vendorId String
accountBalanceId String @unique
accountBalance AccountBalance @relation(fields: [accountBalanceId], references: [id])
vendor Vendor @relation(fields: [vendorId], references: [id])
@@unique([vendorId, accountBalanceId])
@@index([vendorId])
@@map("vendor_account_balances")
}UserJournalEntry
prisma
model UserJournalEntry {
id String @id @default(cuid())
userId String
journalEntryId String @unique
journalEntry JournalEntry @relation(fields: [journalEntryId], references: [id])
user User @relation(fields: [userId], references: [id])
@@index([userId])
@@map("user_journal_entries")
}VendorJournalEntry
prisma
model VendorJournalEntry {
id String @id @default(cuid())
vendorId String
journalEntryId String @unique
journalEntry JournalEntry @relation(fields: [journalEntryId], references: [id])
vendor Vendor @relation(fields: [vendorId], references: [id])
@@index([vendorId])
@@map("vendor_journal_entries")
}Reconciliation
prisma
model Reconciliation {
id String @id @default(cuid())
reconciliationType String
periodStart DateTime
periodEnd DateTime
accountCode String?
entityType String?
entityUserId String?
entityVendorId String?
systemBalance Decimal @db.Decimal(15, 2)
calculatedBalance Decimal @db.Decimal(15, 2)
difference Decimal @db.Decimal(15, 2)
isReconciled Boolean @default(false)
discrepancies Json?
resolution String?
reconciledById String?
reconciledAt DateTime?
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([periodStart, periodEnd])
@@index([accountCode])
@@map("reconciliations")
}AML/Compliance Models
CustomerRiskProfile
prisma
model CustomerRiskProfile {
id String @id @default(cuid())
userId String @unique
overallRiskScore Int @default(0)
riskRating RiskRating @default(UNRATED)
identityRiskScore Int @default(0)
behavioralRiskScore Int @default(0)
geographicRiskScore Int @default(0)
transactionRiskScore Int @default(0)
pepStatus Boolean @default(false)
pepMatches Json?
sanctionsScreened Boolean @default(false)
sanctionsMatches Json?
lastAssessmentDate DateTime?
nextReviewDate DateTime?
enhancedDueDiligence Boolean @default(false)
riskFactors Json?
mitigatingFactors Json?
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id])
@@index([riskRating])
@@index([overallRiskScore])
@@map("customer_risk_profiles")
}Alert
prisma
model Alert {
id String @id @default(cuid())
alertId String @unique
entityType String
entityUserId String?
entityVendorId String?
alertType String
severity AlertSeverity @default(MEDIUM)
status AlertStatus @default(OPEN)
title String
description String
triggerData Json?
relatedTransactions Json?
riskIndicators Json?
assignedTo String?
assignedAt DateTime?
escalatedTo String?
escalatedAt DateTime?
escalationReason String?
resolvedById String?
resolvedAt DateTime?
resolutionNotes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
attachments Json?
escalationHistory Json?
linkedAlertIds String[]
notes Json?
priority String? @default("medium")
resolution Json?
assignedToUser User? @relation("AlertAssignedTo", fields: [assignedTo], references: [id])
entityUser User? @relation("UserAlerts", fields: [entityUserId], references: [id])
entityVendor Vendor? @relation("VendorAlerts", fields: [entityVendorId], references: [id])
resolvedByUser User? @relation("AlertResolvedBy", fields: [resolvedById], references: [id])
transactions WalletTransaction[] @relation("AlertToWalletTransaction")
alerts_A Alert[] @relation("LinkedAlerts")
alerts_B Alert[] @relation("LinkedAlerts")
@@index([status, severity, createdAt])
@@index([entityUserId])
@@index([entityVendorId])
@@index([alertType, status])
@@map("alerts")
}AMLRule
prisma
model AMLRule {
id String @id @default(cuid())
ruleId String @unique
name String
description String?
category String
conditions Json
actions Json
severity AlertSeverity @default(MEDIUM)
isActive Boolean @default(true)
priority Int @default(100)
createdById String?
updatedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([category, isActive])
@@index([priority])
@@map("aml_rules")
}RuleViolation
prisma
model RuleViolation {
id String @id @default(cuid())
ruleId String
alertId String?
entityType String
entityUserId String?
entityVendorId String?
transactionId String?
violationDetails Json?
severity AlertSeverity
createdAt DateTime @default(now())
@@index([ruleId])
@@index([alertId])
@@index([entityUserId])
@@index([entityVendorId])
@@map("rule_violations")
}SAR
prisma
model SAR {
id String @id @default(cuid())
sarId String @unique
entityType String
entityUserId String?
entityVendorId String?
alertIds String[]
reportingReason String
suspiciousActivity Json
supportingDocuments Json?
status String @default("DRAFT")
submittedAt DateTime?
submittedById String?
fiuReference String?
fiuResponseDate DateTime?
fiuResponse Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
approvedAt DateTime?
approvedBy String?
draftedAt DateTime?
filedById String?
reviewedAt DateTime?
reviewedBy String?
entityUser User? @relation("UserSARs", fields: [entityUserId], references: [id])
entityVendor Vendor? @relation("VendorSARs", fields: [entityVendorId], references: [id])
filedBy User? @relation("SARFiledBy", fields: [filedById], references: [id])
@@index([status])
@@index([entityUserId])
@@index([entityVendorId])
@@map("sars")
}PEP
prisma
model PEP {
id String @id @default(cuid())
name String
normalizedName String
category String
position String?
country String?
source String?
sourceDate DateTime?
additionalInfo Json?
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([normalizedName])
@@index([category])
@@index([isActive])
@@map("peps")
}SanctionsListSync
prisma
model SanctionsListSync {
id String @id @default(cuid())
listType String
syncedAt DateTime @default(now())
status String
etag String?
lastModified DateTime?
fileHash String?
individualsCount Int?
entitiesCount Int?
errorMessage String?
syncDuration Int?
@@index([listType, syncedAt])
@@map("sanctions_list_syncs")
}RiskScoreHistory
prisma
model RiskScoreHistory {
id String @id @default(cuid())
entityType String
entityUserId String?
entityVendorId String?
previousScore Int
newScore Int
previousRating RiskRating
newRating RiskRating
changeReason String
changeFactors Json?
changedById String?
createdAt DateTime @default(now())
@@index([entityUserId, createdAt])
@@index([entityVendorId, createdAt])
@@map("risk_score_histories")
}MonitoringConfig
prisma
model MonitoringConfig {
id String @id @default(cuid())
configKey String @unique
configValue Json
description String?
isActive Boolean @default(true)
updatedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("monitoring_configs")
}MonitoringAuditLog
prisma
model MonitoringAuditLog {
id String @id @default(cuid())
action String
performedById String?
targetType String?
targetId String?
details Json?
ipAddress String?
createdAt DateTime @default(now())
@@index([action, createdAt])
@@index([targetType, targetId])
@@map("monitoring_audit_logs")
}System Models
AuditLog
prisma
model AuditLog {
id String @id @default(cuid())
eventType AuditEventType
description String
actorId String?
actorType String?
targetType String?
targetId String?
entityType String?
entityUserId String?
entityVendorId String?
amount Decimal? @db.Decimal(15, 2)
currency String?
ipAddress String?
userAgent String?
deviceId String?
requestId String?
metadata Json?
previousState Json?
newState Json?
hashPrevious String?
hashCurrent String?
createdAt DateTime @default(now())
@@index([eventType, createdAt])
@@index([targetType, targetId])
@@index([entityUserId])
@@index([entityVendorId])
@@index([createdAt])
@@map("audit_logs")
}EmergencyControl
prisma
model EmergencyControl {
id String @id @default(cuid())
controlType String @unique
isActive Boolean @default(false)
activatedAt DateTime?
activatedById String?
reason String?
affectedServices String[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("emergency_controls")
}SystemEmergencyControl
prisma
model SystemEmergencyControl {
id String @id @default(cuid())
activatedAt DateTime @default(now())
activatedById String
reason String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
auditLog Json?
controlType SystemEmergencyType
deactivatedAt DateTime?
deactivatedById String?
parameters Json?
resolution String?
scope String @default("global")
status SystemEmergencyStatus @default(ACTIVE)
triggerEvent Json?
@@index([controlType, status])
@@index([status, activatedAt(sort: Desc)])
@@map("system_emergency_controls")
}Job
prisma
model Job {
id String @id @default(cuid())
jobType String
status String @default("PENDING")
entityType String?
entityUserId String?
entityVendorId String?
inputData Json?
outputData Json?
errorMessage String?
startedAt DateTime?
completedAt DateTime?
retryCount Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([jobType, status])
@@index([entityUserId])
@@index([entityVendorId])
@@map("jobs")
}Integration
prisma
model Integration {
id String @id @default(cuid())
name String? @unique
type String?
config Json?
credentials Json?
isActive Boolean @default(true)
lastSyncAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
apiKey String?
apiKeyPrefix String?
appName String?
expiresAt DateTime?
ipWhitelist String[]
lastUsedAt DateTime?
requestCount Int @default(0)
status IntegrationStatus @default(ACTIVE)
vendorId String?
vendor Vendor? @relation(fields: [vendorId], references: [id])
@@index([vendorId])
@@index([apiKeyPrefix])
@@map("integrations")
}KeshlessUserAccess
prisma
model KeshlessUserAccess {
id String @id @default(cuid())
userId String
accessType String
permissions Json?
isActive Boolean @default(true)
grantedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([userId, accessType])
@@map("keshless_user_accesses")
}Configuration Models
FeeConfig
prisma
model FeeConfig {
id String @id @default(cuid())
type FeeType @unique
name String
description String?
tiers Json
currency String @default("SZL")
isActive Boolean @default(true)
createdById String?
updatedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([type, isActive])
@@map("fee_configs")
}TransactionLimitConfig
prisma
model TransactionLimitConfig {
id String @id @default(cuid())
limitType TransactionLimitType @unique
name String
description String?
dailyAmountLimit Decimal @default(5000) @db.Decimal(15, 2)
monthlyAmountLimit Decimal @default(100000) @db.Decimal(15, 2)
dailyCountLimit Int @default(50)
monthlyCountLimit Int @default(500)
isActive Boolean @default(true)
createdById String?
updatedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([limitType, isActive])
@@map("transaction_limit_configs")
}PINConfig
prisma
model PINConfig {
id String @id @default(cuid())
name String @default("Default PIN Configuration")
description String?
pinlessAmountLimit Decimal @default(50) @db.Decimal(15, 2)
pinlessDailyTapLimit Int @default(10)
isActive Boolean @default(true)
createdById String?
updatedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([isActive])
@@map("pin_configs")
}FAQ
prisma
model FAQ {
id String @id @default(cuid())
question String
answer String
category String?
order Int @default(0)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([category, order])
@@index([isActive])
@@map("faqs")
}Other Models
Till
prisma
model Till {
id String @id @default(cuid())
vendorId String
name String
openingBalance Decimal @default(0) @db.Decimal(15, 2)
currentBalance Decimal @default(0) @db.Decimal(15, 2)
isOpen Boolean @default(false)
openedAt DateTime?
closedAt DateTime?
openedById String?
closedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
vendor Vendor @relation(fields: [vendorId], references: [id])
@@index([vendorId, isOpen])
@@map("tills")
}CardOperationRequest
prisma
model CardOperationRequest {
id String @id @default(cuid())
userId String
cardNumber String?
operationType String
status String @default("PENDING")
otpVerified Boolean @default(false)
pinVerified Boolean @default(false)
processedAt DateTime?
processedById String?
rejectionReason String?
metadata Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([userId, status])
@@index([cardNumber])
@@map("card_operation_requests")
}ParkingRate
prisma
model ParkingRate {
id String @id @default(cuid())
name String
ratePerHour Decimal @db.Decimal(10, 2)
ratePerDay Decimal? @db.Decimal(10, 2)
maxDailyRate Decimal? @db.Decimal(10, 2)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
sessions ParkingSession[]
@@map("parking_rates")
}ParkingSession
prisma
model ParkingSession {
id String @id @default(cuid())
userId String
vehicleNumber String
rateId String
startTime DateTime
endTime DateTime?
duration Int?
amount Decimal? @db.Decimal(10, 2)
status String @default("ACTIVE")
paymentStatus String @default("PENDING")
walletTransactionId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
rate ParkingRate @relation(fields: [rateId], references: [id])
@@index([userId, status])
@@index([vehicleNumber])
@@map("parking_sessions")
}Enums
User & Authentication
prisma
enum UserRole {
USER
ADMIN
SUPER_ADMIN
}
enum VerificationStatus {
PENDING
IN_PROGRESS
VERIFIED
REJECTED
NEEDS_REVIEW
}
enum VendorVerificationStatus {
PENDING
IN_PROGRESS
VERIFIED
REJECTED
NEEDS_REVIEW
}
enum AdminEmployeeRole {
SUPER_ADMIN
ADMIN
SUPPORT_AGENT
COMPLIANCE_OFFICER
FINANCE_MANAGER
AUDITOR
CUSTOM
}
enum OTPPurpose {
REGISTRATION
PASSWORD_RESET
PHONE_VERIFICATION
TRANSACTION_VERIFICATION
CARD_OPERATION
PIN_RESET
CARD_BLOCK
CARD_UNBLOCK
CARD_RELINK
CARD_LINK
VENDOR_PIN_SETUP
LOGOUT
}Risk & Compliance
prisma
enum RiskRating {
LOW
MEDIUM
HIGH
CRITICAL
UNRATED
MEDIUM_LOW
MEDIUM_HIGH
}
enum AMLStatus {
NOT_SCREENED
CLEAR
FLAGGED
BLOCKED
PENDING_REVIEW
}
enum AlertStatus {
OPEN
UNDER_REVIEW
ESCALATED
RESOLVED
FALSE_POSITIVE
RESOLVED_FALSE_POSITIVE
RESOLVED_TRUE_POSITIVE
CLOSED
}
enum AlertSeverity {
LOW
MEDIUM
HIGH
CRITICAL
}Cards & NFC
prisma
enum CardStatus {
AVAILABLE
ASSIGNED
BLOCKED
EXPIRED
LOST
DEACTIVATED
}Transactions
prisma
enum WalletTransactionType {
VENDOR_PAYMENT_RECEIVED
VENDOR_TOPUP_ISSUED
VENDOR_TOPUP_RECEIVED
VENDOR_WITHDRAWAL_PROCESSED
VENDOR_COMMISSION_EARNED
VENDOR_TRANSFER_SENT
VENDOR_TRANSFER_RECEIVED
USER_PAYMENT_SENT
USER_TOPUP_RECEIVED
USER_WITHDRAWAL_SENT
USER_TRANSFER_SENT
USER_TRANSFER_RECEIVED
USER_REFUND_RECEIVED
FEE
ADMIN_TOPUP
AIRTIME
BILL_PAYMENT
TICKET_PURCHASE
REFUND
ADJUSTMENT
REVERSAL
}
enum WalletTransactionStatus {
PENDING
COMPLETED
FAILED
CANCELLED
REVERSED
}
enum WithdrawalRequestStatus {
PENDING
APPROVED
COMPLETED
REJECTED
CANCELLED
}
enum TransactionLimitType {
TOPUP
WITHDRAWAL
SEND_MONEY
RECEIVE_MONEY
}
enum FeeType {
P2P
VENDOR_WITHDRAWAL
}Accounting
prisma
enum JournalEntryStatus {
PENDING
POSTED
REVERSED
CANCELLED
}
enum JournalEntryType {
USER_TRANSFER
USER_PAYMENT
USER_TOPUP
USER_WITHDRAWAL
USER_REFUND
VENDOR_COMMISSION
VENDOR_PAYOUT
FEE_COLLECTION
REVERSAL
ADJUSTMENT
AIRTIME_PURCHASE
BILL_PAYMENT
OPENING_BALANCE
}
enum AccountType {
ASSET
LIABILITY
EQUITY
REVENUE
EXPENSE
}
enum NormalBalance {
DEBIT
CREDIT
}
enum AuditEventType {
JOURNAL_CREATED
JOURNAL_POSTED
JOURNAL_REVERSED
JOURNAL_CANCELLED
BALANCE_UPDATED
RECONCILIATION_COMPLETED
MANUAL_ADJUSTMENT
}Business Types
prisma
enum VendorType {
COMPANY
PARTNERSHIP
SOLE_TRADER
COOPERATIVE
CHURCH
SPORTS_TEAM
SCHOOL
NGO
}
enum BusinessType {
RETAIL
RESTAURANT
SERVICE
WHOLESALE
OTHER
}System & Integrations
prisma
enum SystemEmergencyType {
SYSTEM_SHUTDOWN
DISABLE_ALL_TRANSACTIONS
DISABLE_WITHDRAWALS
DISABLE_P2P_TRANSFERS
DISABLE_BILL_PAYMENTS
DISABLE_TOPUPS
READ_ONLY_MODE
RATE_LIMIT_EXTREME
}
enum SystemEmergencyStatus {
ACTIVE
INACTIVE
}
enum IntegrationStatus {
ACTIVE
REVOKED
EXPIRED
}