Files
nixpanel-server/server/prisma/schema.prisma
T
2026-04-05 10:45:21 -05:00

439 lines
16 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
// ─── Admin / WHM Users ───────────────────────────────────────────────────────
model AdminUser {
id Int @id @default(autoincrement())
username String @unique @db.VarChar(64)
passwordHash String @db.VarChar(255)
email String @unique @db.VarChar(255)
twoFactorSecret String? @db.VarChar(64)
twoFactorEnabled Boolean @default(false)
lastLogin DateTime?
lastLoginIp String? @db.VarChar(45)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
refreshTokens RefreshToken[]
auditLogs AuditLog[]
@@map("admin_users")
}
// ─── Resellers ───────────────────────────────────────────────────────────────
model Reseller {
id Int @id @default(autoincrement())
username String @unique @db.VarChar(64)
passwordHash String @db.VarChar(255)
email String @unique @db.VarChar(255)
contactName String? @db.VarChar(255)
company String? @db.VarChar(255)
maxAccounts Int @default(0)
diskLimitMb BigInt @default(0)
bandwidthLimitMb BigInt @default(0)
diskUsedMb BigInt @default(0)
bandwidthUsedMb BigInt @default(0)
status String @default("active") @db.VarChar(20)
brandName String? @db.VarChar(255)
brandLogo String? @db.VarChar(500)
notes String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accounts Account[]
refreshTokens RefreshToken[]
@@map("resellers")
}
// ─── Hosting Packages ────────────────────────────────────────────────────────
model Package {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(100)
diskMb BigInt @default(1024)
bandwidthMb BigInt @default(10240)
maxDatabases Int @default(5)
maxEmailAccounts Int @default(10)
maxSubdomains Int @default(10)
maxAddonDomains Int @default(5)
maxParkedDomains Int @default(5)
maxFtpAccounts Int @default(3)
maxCronJobs Int @default(5)
phpVersion String @default("8.3") @db.VarChar(10)
sslEnabled Boolean @default(true)
backupEnabled Boolean @default(true)
dedicatedIp Boolean @default(false)
notes String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accounts Account[]
@@map("packages")
}
// ─── Hosting Accounts (cPanel users) ─────────────────────────────────────────
model Account {
id Int @id @default(autoincrement())
username String @unique @db.VarChar(64)
passwordHash String @db.VarChar(255)
email String @db.VarChar(255)
domain String @unique @db.VarChar(255)
homedir String @db.VarChar(500)
shell String @default("/bin/false") @db.VarChar(100)
status String @default("active") @db.VarChar(20)
diskUsedMb BigInt @default(0)
bandwidthUsedMb BigInt @default(0)
ipAddress String? @db.VarChar(45)
nameservers String? @db.VarChar(500)
notes String? @db.Text
suspendedAt DateTime?
suspendReason String? @db.VarChar(500)
terminatedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
resellerId Int?
reseller Reseller? @relation(fields: [resellerId], references: [id])
packageId Int?
package Package? @relation(fields: [packageId], references: [id])
ipId Int?
ip IpAddress? @relation(fields: [ipId], references: [id])
dnsZones DnsZone[]
emailAccounts EmailAccount[]
emailForwarders EmailForwarder[]
ftpAccounts FtpAccount[]
databases Database[]
subdomains Subdomain[]
addonDomains AddonDomain[]
parkedDomains ParkedDomain[]
sslCertificates SslCertificate[]
cronJobs CronJob[]
refreshTokens RefreshToken[]
@@map("accounts")
}
// ─── IP Addresses ─────────────────────────────────────────────────────────────
model IpAddress {
id Int @id @default(autoincrement())
address String @unique @db.VarChar(45)
netmask String? @db.VarChar(45)
gateway String? @db.VarChar(45)
type String @default("shared") @db.VarChar(20)
status String @default("available") @db.VarChar(20)
notes String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accounts Account[]
@@map("ip_addresses")
}
// ─── DNS ──────────────────────────────────────────────────────────────────────
model DnsZone {
id Int @id @default(autoincrement())
domain String @unique @db.VarChar(255)
zoneFile String? @db.VarChar(500)
serial BigInt @default(1)
status String @default("active") @db.VarChar(20)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accountId Int
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
records DnsRecord[]
@@map("dns_zones")
}
model DnsRecord {
id Int @id @default(autoincrement())
type String @db.VarChar(10)
name String @db.VarChar(255)
value String @db.VarChar(500)
ttl Int @default(3600)
priority Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
zoneId Int
zone DnsZone @relation(fields: [zoneId], references: [id], onDelete: Cascade)
@@map("dns_records")
}
// ─── Email ────────────────────────────────────────────────────────────────────
model EmailAccount {
id Int @id @default(autoincrement())
username String @db.VarChar(64)
domain String @db.VarChar(255)
address String @unique @db.VarChar(320)
passwordHash String @db.VarChar(255)
quotaMb Int @default(500)
usedMb Int @default(0)
status String @default("active") @db.VarChar(20)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accountId Int
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
@@map("email_accounts")
}
model EmailForwarder {
id Int @id @default(autoincrement())
source String @db.VarChar(320)
destination String @db.VarChar(320)
createdAt DateTime @default(now())
accountId Int
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
@@map("email_forwarders")
}
// ─── FTP ──────────────────────────────────────────────────────────────────────
model FtpAccount {
id Int @id @default(autoincrement())
username String @db.VarChar(64)
passwordHash String @db.VarChar(255)
homedir String @db.VarChar(500)
quotaMb Int @default(0)
status String @default("active") @db.VarChar(20)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accountId Int
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
@@map("ftp_accounts")
}
// ─── Databases ────────────────────────────────────────────────────────────────
model Database {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(64)
charset String @default("utf8mb4") @db.VarChar(32)
collation String @default("utf8mb4_unicode_ci") @db.VarChar(64)
sizeMb Float @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accountId Int
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
dbUsers DatabaseUser[]
@@map("databases")
}
model DatabaseUser {
id Int @id @default(autoincrement())
username String @db.VarChar(64)
passwordHash String @db.VarChar(255)
host String @default("localhost") @db.VarChar(255)
privileges String @default("ALL") @db.VarChar(255)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
databaseId Int
database Database @relation(fields: [databaseId], references: [id], onDelete: Cascade)
@@map("database_users")
}
// ─── Subdomains / Addon / Parked Domains ─────────────────────────────────────
model Subdomain {
id Int @id @default(autoincrement())
subdomain String @db.VarChar(255)
domain String @db.VarChar(255)
fqdn String @unique @db.VarChar(510)
documentRoot String @db.VarChar(500)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accountId Int
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
@@map("subdomains")
}
model AddonDomain {
id Int @id @default(autoincrement())
domain String @unique @db.VarChar(255)
subdomain String @db.VarChar(255)
documentRoot String @db.VarChar(500)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accountId Int
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
@@map("addon_domains")
}
model ParkedDomain {
id Int @id @default(autoincrement())
domain String @unique @db.VarChar(255)
createdAt DateTime @default(now())
accountId Int
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
@@map("parked_domains")
}
// ─── SSL ──────────────────────────────────────────────────────────────────────
model SslCertificate {
id Int @id @default(autoincrement())
domain String @db.VarChar(255)
type String @default("letsencrypt") @db.VarChar(30)
certPath String? @db.VarChar(500)
keyPath String? @db.VarChar(500)
chainPath String? @db.VarChar(500)
issuedAt DateTime?
expiresAt DateTime?
autoRenew Boolean @default(true)
status String @default("pending") @db.VarChar(20)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accountId Int
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
@@map("ssl_certificates")
}
// ─── Cron Jobs ────────────────────────────────────────────────────────────────
model CronJob {
id Int @id @default(autoincrement())
schedule String @db.VarChar(100)
command String @db.VarChar(1000)
comment String? @db.VarChar(255)
enabled Boolean @default(true)
lastRun DateTime?
nextRun DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accountId Int
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
@@map("cron_jobs")
}
// ─── Security ─────────────────────────────────────────────────────────────────
model SecurityEvent {
id Int @id @default(autoincrement())
type String @db.VarChar(50)
severity String @default("info") @db.VarChar(20)
message String @db.Text
sourceIp String? @db.VarChar(45)
resolved Boolean @default(false)
resolvedAt DateTime?
createdAt DateTime @default(now())
@@map("security_events")
}
model BlockedIp {
id Int @id @default(autoincrement())
ip String @unique @db.VarChar(45)
reason String? @db.VarChar(500)
expiresAt DateTime?
createdAt DateTime @default(now())
@@map("blocked_ips")
}
model WhitelistedIp {
id Int @id @default(autoincrement())
ip String @unique @db.VarChar(45)
note String? @db.VarChar(255)
createdAt DateTime @default(now())
@@map("whitelisted_ips")
}
// ─── Audit Log ────────────────────────────────────────────────────────────────
model AuditLog {
id Int @id @default(autoincrement())
action String @db.VarChar(100)
target String? @db.VarChar(255)
details String? @db.Text
sourceIp String? @db.VarChar(45)
createdAt DateTime @default(now())
adminId Int?
admin AdminUser? @relation(fields: [adminId], references: [id])
@@map("audit_log")
}
// ─── Auth ─────────────────────────────────────────────────────────────────────
model RefreshToken {
id Int @id @default(autoincrement())
token String @unique @db.VarChar(500)
role String @db.VarChar(20)
expiresAt DateTime
revokedAt DateTime?
createdAt DateTime @default(now())
adminId Int?
admin AdminUser? @relation(fields: [adminId], references: [id])
resellerId Int?
reseller Reseller? @relation(fields: [resellerId], references: [id])
accountId Int?
account Account? @relation(fields: [accountId], references: [id])
@@map("refresh_tokens")
}
// ─── Settings ─────────────────────────────────────────────────────────────────
model Setting {
key String @id @db.VarChar(100)
value String @db.Text
updatedAt DateTime @updatedAt
@@map("settings")
}
// ─── Terminal Sessions ────────────────────────────────────────────────────────
model TerminalSession {
id Int @id @default(autoincrement())
adminId Int
sourceIp String? @db.VarChar(45)
startedAt DateTime @default(now())
endedAt DateTime?
@@map("terminal_sessions")
}