904 lines
24 KiB
Plaintext
904 lines
24 KiB
Plaintext
// This is your Prisma schema file,
|
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// ========================
|
|
// Auth
|
|
// ========================
|
|
model User {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
name String
|
|
passwordHash String
|
|
role UserRole @default(VIEWER)
|
|
isActive Boolean @default(true)
|
|
allServersAccess Boolean @default(true)
|
|
activeOrganizationId String?
|
|
lastLogin DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
activeOrganization Organization? @relation("UserActiveOrganization", fields: [activeOrganizationId], references: [id], onDelete: SetNull)
|
|
organizationMemberships OrganizationMembership[]
|
|
createdOrganizations Organization[] @relation("OrganizationCreator")
|
|
apiKeys ApiKey[]
|
|
auditLogs AuditLog[]
|
|
deployments Deployment[]
|
|
settings UserSettings?
|
|
notificationProviders UserNotificationProvider[]
|
|
integrations UserIntegration[]
|
|
gitProviders UserGitProvider[]
|
|
storageDestinations UserStorageDestination[]
|
|
serverAssignments UserServerAccess[]
|
|
sentInvitations UserInvitation[] @relation("InvitationCreator")
|
|
|
|
@@index([activeOrganizationId])
|
|
@@map("users")
|
|
}
|
|
|
|
model Organization {
|
|
id String @id @default(cuid())
|
|
name String
|
|
slug String @unique
|
|
logoUrl String?
|
|
createdById String?
|
|
createdBy User? @relation("OrganizationCreator", fields: [createdById], references: [id], onDelete: SetNull)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
members OrganizationMembership[]
|
|
activeUsers User[] @relation("UserActiveOrganization")
|
|
servers Server[]
|
|
projects Project[]
|
|
domains Domain[]
|
|
apiKeys ApiKey[]
|
|
invitations UserInvitation[]
|
|
auditLogs AuditLog[]
|
|
deployments Deployment[]
|
|
|
|
@@index([createdById])
|
|
@@map("organizations")
|
|
}
|
|
|
|
model OrganizationMembership {
|
|
id String @id @default(cuid())
|
|
organizationId String
|
|
userId String
|
|
isDefault Boolean @default(false)
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([organizationId, userId])
|
|
@@index([userId])
|
|
@@map("organization_memberships")
|
|
}
|
|
|
|
// ========================
|
|
// Projects
|
|
// ========================
|
|
model Project {
|
|
id String @id @default(cuid())
|
|
organizationId String
|
|
name String
|
|
slug String
|
|
description String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
environments Environment[]
|
|
deployments Deployment[]
|
|
|
|
@@unique([organizationId, slug])
|
|
@@index([organizationId])
|
|
@@map("projects")
|
|
}
|
|
|
|
model Environment {
|
|
id String @id @default(cuid())
|
|
projectId String
|
|
serverId String
|
|
name String
|
|
slug String
|
|
kind EnvironmentKind
|
|
description String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
server Server @relation(fields: [serverId], references: [id], onDelete: Restrict)
|
|
containers Container[]
|
|
deployments Deployment[]
|
|
|
|
@@unique([projectId, slug])
|
|
@@index([projectId])
|
|
@@index([projectId, kind])
|
|
@@index([serverId])
|
|
@@map("environments")
|
|
}
|
|
|
|
enum EnvironmentKind {
|
|
PRODUCTION
|
|
STAGING
|
|
DEVELOPMENT
|
|
PREVIEW
|
|
CUSTOM
|
|
}
|
|
|
|
model UserSettings {
|
|
id String @id @default(cuid())
|
|
userId String @unique
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
panelName String @default("DOKTAINER")
|
|
panelUrl String @default("http://localhost:3000")
|
|
timezone String @default("Asia/Jakarta")
|
|
theme String @default("dark")
|
|
sessionTimeoutMinutes Int @default(30)
|
|
twoFactorEnabled Boolean @default(false)
|
|
twoFactorSecretEnc String?
|
|
twoFactorPendingSecretEnc String?
|
|
ipWhitelistEnabled Boolean @default(false)
|
|
ipWhitelist String[] @default([])
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("user_settings")
|
|
}
|
|
|
|
model UserNotificationProvider {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
organizationId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
type NotificationProviderType
|
|
name String
|
|
enabled Boolean @default(true)
|
|
actions String[] @default([])
|
|
channel String?
|
|
webhookUrlEnc String?
|
|
smtpHost String?
|
|
smtpPort Int @default(587)
|
|
smtpSecure Boolean @default(false)
|
|
smtpUsername String?
|
|
smtpPasswordEnc String?
|
|
smtpFromEmail String?
|
|
smtpFromName String?
|
|
telegramChatId String?
|
|
telegramBotTokenEnc String?
|
|
serverUrl String?
|
|
topic String?
|
|
userKey String?
|
|
apiKeyEnc String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([userId, organizationId, type])
|
|
@@index([organizationId])
|
|
@@map("user_notification_providers")
|
|
}
|
|
|
|
model UserIntegration {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
provider IntegrationProviderType
|
|
connected Boolean @default(false)
|
|
zoneId String?
|
|
apiTokenEnc String?
|
|
accessKeyId String?
|
|
secretAccessKeyEnc String?
|
|
region String?
|
|
bucket String?
|
|
tokenEnc String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([userId, provider])
|
|
@@index([userId])
|
|
@@map("user_integrations")
|
|
}
|
|
|
|
model UserStorageDestination {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
organizationId String
|
|
serverId String?
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
server Server? @relation(fields: [serverId], references: [id], onDelete: SetNull)
|
|
name String
|
|
provider S3StorageProvider
|
|
enabled Boolean @default(true)
|
|
accessKeyId String
|
|
secretAccessKeyEnc String?
|
|
region String?
|
|
bucket String
|
|
endpoint String?
|
|
additionalFlags String[] @default([])
|
|
retentionDays Int?
|
|
maxBackupCount Int?
|
|
objectPrefix String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([userId, organizationId])
|
|
@@index([organizationId, serverId])
|
|
@@map("user_storage_destinations")
|
|
}
|
|
|
|
model UserGitProvider {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
organizationId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
containerDeploymentSources ContainerDeploymentSource[]
|
|
provider GitProviderType
|
|
name String
|
|
enabled Boolean @default(true)
|
|
appName String
|
|
appId String?
|
|
clientId String?
|
|
clientSecretEnc String?
|
|
webhookSecretEnc String?
|
|
appUrl String?
|
|
installationUrl String?
|
|
providerUrl String?
|
|
internalUrl String?
|
|
accountUsername String?
|
|
accountEmail String?
|
|
namespace String?
|
|
organizationScoped Boolean @default(false)
|
|
organizationName String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([userId, organizationId, provider])
|
|
@@index([organizationId])
|
|
@@map("user_git_providers")
|
|
}
|
|
|
|
model UserServerAccess {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
serverId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
server Server @relation(fields: [serverId], references: [id], onDelete: Cascade)
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([userId, serverId])
|
|
@@index([serverId])
|
|
@@map("user_server_access")
|
|
}
|
|
|
|
model UserInvitation {
|
|
id String @id @default(cuid())
|
|
organizationId String
|
|
email String
|
|
name String
|
|
role UserRole
|
|
tokenHash String @unique
|
|
allServersAccess Boolean @default(true)
|
|
serverIds String[]
|
|
invitedById String?
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
invitedBy User? @relation("InvitationCreator", fields: [invitedById], references: [id], onDelete: SetNull)
|
|
expiresAt DateTime
|
|
acceptedAt DateTime?
|
|
revokedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([email])
|
|
@@index([expiresAt])
|
|
@@index([organizationId])
|
|
@@map("user_invitations")
|
|
}
|
|
|
|
enum UserRole {
|
|
SUPER_ADMIN
|
|
OPERATOR
|
|
DEVELOPER
|
|
VIEWER
|
|
}
|
|
|
|
enum NotificationProviderType {
|
|
SLACK
|
|
TELEGRAM
|
|
DISCORD
|
|
LARK
|
|
TEAMS
|
|
EMAIL
|
|
RESEND
|
|
GOTIFY
|
|
NTFY
|
|
MATTERMOST
|
|
PUSHOVER
|
|
CUSTOM
|
|
}
|
|
|
|
enum IntegrationProviderType {
|
|
CLOUDFLARE
|
|
AWS_S3
|
|
GITHUB
|
|
GITLAB
|
|
}
|
|
|
|
enum GitProviderType {
|
|
GITHUB
|
|
GITLAB
|
|
BITBUCKET
|
|
GITEA
|
|
}
|
|
|
|
enum S3StorageProvider {
|
|
AWS_S3
|
|
ALIBABA_OSS
|
|
ARVAN_AOS
|
|
CEPH
|
|
CHINA_MOBILE_EOS
|
|
CLOUDFLARE_R2
|
|
DIGITALOCEAN_SPACES
|
|
DREAMOBJECTS
|
|
GOOGLE_CLOUD_STORAGE
|
|
HUAWEI_OBS
|
|
IBM_COS
|
|
CUSTOM
|
|
}
|
|
|
|
model ApiKey {
|
|
id String @id @default(cuid())
|
|
organizationId String
|
|
name String
|
|
keyHash String @unique
|
|
keyPrefix String
|
|
permissions String[]
|
|
userId String
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
lastUsed DateTime?
|
|
expiresAt DateTime?
|
|
isActive Boolean @default(true)
|
|
requestCount Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([organizationId])
|
|
@@map("api_keys")
|
|
}
|
|
|
|
// ========================
|
|
// Servers
|
|
// ========================
|
|
model Server {
|
|
id String @id @default(cuid())
|
|
organizationId String
|
|
name String
|
|
ip String
|
|
sshPort Int @default(22)
|
|
username String @default("root")
|
|
authType SshAuthType @default(PASSWORD)
|
|
sshKeyEnc String? // encrypted private key
|
|
passwordEnc String? // encrypted password
|
|
status ServerStatus @default(UNKNOWN)
|
|
os String?
|
|
location String?
|
|
tags String[]
|
|
lastHealthAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
containers Container[]
|
|
environments Environment[]
|
|
networks Network[]
|
|
storageDestinations UserStorageDestination[]
|
|
domains Domain[]
|
|
auditLogs AuditLog[]
|
|
deployments Deployment[]
|
|
metrics ServerMetric[]
|
|
appInstalls AppInstall[]
|
|
backups Backup[]
|
|
firewallRulePresets FirewallRulePreset[]
|
|
userAssignments UserServerAccess[]
|
|
|
|
@@index([organizationId])
|
|
@@map("servers")
|
|
}
|
|
|
|
enum SshAuthType {
|
|
PASSWORD
|
|
SSH_KEY
|
|
}
|
|
|
|
enum ServerStatus {
|
|
ONLINE
|
|
OFFLINE
|
|
WARNING
|
|
UNKNOWN
|
|
}
|
|
|
|
model ServerMetric {
|
|
id String @id @default(cuid())
|
|
serverId String
|
|
server Server @relation(fields: [serverId], references: [id], onDelete: Cascade)
|
|
cpuPct Float
|
|
ramPct Float
|
|
diskPct Float
|
|
ramUsed BigInt
|
|
ramTotal BigInt
|
|
diskUsed BigInt
|
|
diskTotal BigInt
|
|
networkRxBps BigInt?
|
|
networkTxBps BigInt?
|
|
uptimeSec BigInt
|
|
recordedAt DateTime @default(now())
|
|
|
|
@@index([serverId, recordedAt])
|
|
@@map("server_metrics")
|
|
}
|
|
|
|
// ========================
|
|
// Containers
|
|
// ========================
|
|
model Container {
|
|
id String @id @default(cuid())
|
|
dockerId String?
|
|
name String
|
|
image String
|
|
status ContainerStatus @default(STOPPED)
|
|
sourceType ContainerSourceType @default(MANUAL)
|
|
deployMode ContainerDeployMode?
|
|
serverId String
|
|
server Server @relation(fields: [serverId], references: [id], onDelete: Cascade)
|
|
environmentId String?
|
|
environment Environment? @relation(fields: [environmentId], references: [id], onDelete: SetNull)
|
|
domains Domain[]
|
|
deploymentSource ContainerDeploymentSource?
|
|
deployments Deployment[]
|
|
deploymentLock DeploymentLock?
|
|
ports Json @default("[]") // [{host: 80, container: 80, protocol: "tcp"}]
|
|
envVars Json @default("[]") // [{key: "NODE_ENV", value: "production"}]
|
|
volumes Json @default("[]")
|
|
labels Json @default("{}")
|
|
restartPolicy String @default("unless-stopped")
|
|
cpuUsage String?
|
|
ramUsage String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([environmentId])
|
|
@@index([serverId])
|
|
@@map("containers")
|
|
}
|
|
|
|
model ContainerDeploymentSource {
|
|
id String @id @default(cuid())
|
|
containerId String @unique
|
|
container Container @relation(fields: [containerId], references: [id], onDelete: Cascade)
|
|
projectName String?
|
|
gitProviderId String?
|
|
gitProvider UserGitProvider? @relation(fields: [gitProviderId], references: [id], onDelete: SetNull)
|
|
repoUrl String?
|
|
repoBranch String?
|
|
repoVisibility RepositoryVisibility?
|
|
buildType String?
|
|
buildPath String?
|
|
startCommand String?
|
|
portOverride String?
|
|
publishDirectory String?
|
|
imageTag String?
|
|
accessTokenEnc String?
|
|
composeEnvOverrides Json?
|
|
projectPath String?
|
|
composeFilePath String?
|
|
dockerfilePath String?
|
|
dockerContextPath String?
|
|
deploymentPath String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([gitProviderId])
|
|
@@map("container_deployment_sources")
|
|
}
|
|
|
|
model Deployment {
|
|
id String @id @default(cuid())
|
|
containerId String
|
|
organizationId String
|
|
serverId String
|
|
projectId String?
|
|
environmentId String?
|
|
userId String?
|
|
idempotencyKey String?
|
|
status DeploymentStatus
|
|
trigger DeploymentTrigger
|
|
version String?
|
|
commitSha String?
|
|
branch String?
|
|
image String?
|
|
imageDigest String?
|
|
sourceSnapshot Json?
|
|
configSnapshot Json
|
|
configRevision String?
|
|
rollbackSnapshotEnc String?
|
|
strategy String?
|
|
candidateRef String?
|
|
previousDeploymentId String?
|
|
failureReason String?
|
|
rollbackReason String?
|
|
logReference String?
|
|
error String?
|
|
startedAt DateTime?
|
|
completedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
container Container @relation(fields: [containerId], references: [id], onDelete: Cascade)
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
server Server @relation(fields: [serverId], references: [id], onDelete: Cascade)
|
|
project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull)
|
|
environment Environment? @relation(fields: [environmentId], references: [id], onDelete: SetNull)
|
|
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
|
previousDeployment Deployment? @relation("DeploymentPredecessor", fields: [previousDeploymentId], references: [id], onDelete: SetNull)
|
|
nextDeployments Deployment[] @relation("DeploymentPredecessor")
|
|
events DeploymentEvent[]
|
|
|
|
@@unique([containerId, idempotencyKey])
|
|
@@index([containerId, createdAt])
|
|
@@index([containerId, status, createdAt])
|
|
@@index([organizationId, createdAt])
|
|
@@index([serverId, createdAt])
|
|
@@index([projectId, createdAt])
|
|
@@index([environmentId, createdAt])
|
|
@@index([previousDeploymentId])
|
|
@@map("deployments")
|
|
}
|
|
|
|
model DeploymentEvent {
|
|
id String @id @default(cuid())
|
|
deploymentId String
|
|
status DeploymentStatus
|
|
level DeploymentEventLevel @default(INFO)
|
|
message String
|
|
metadata Json?
|
|
createdAt DateTime @default(now())
|
|
|
|
deployment Deployment @relation(fields: [deploymentId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([deploymentId, createdAt])
|
|
@@map("deployment_events")
|
|
}
|
|
|
|
model DeploymentLock {
|
|
containerId String @id
|
|
token String @unique
|
|
expiresAt DateTime
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
container Container @relation(fields: [containerId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([expiresAt])
|
|
@@map("deployment_locks")
|
|
}
|
|
|
|
enum DeploymentStatus {
|
|
QUEUED
|
|
BUILDING
|
|
RUNNING
|
|
VALIDATING
|
|
SWITCHING
|
|
ACTIVE
|
|
SUCCESS
|
|
FAILED
|
|
FAILED_ROLLED_BACK
|
|
CANCELLED
|
|
ROLLBACK_RUNNING
|
|
ROLLED_BACK
|
|
SUPERSEDED
|
|
}
|
|
|
|
enum DeploymentEventLevel {
|
|
INFO
|
|
WARNING
|
|
ERROR
|
|
}
|
|
|
|
enum DeploymentTrigger {
|
|
MANUAL
|
|
GIT_WEBHOOK
|
|
REBUILD
|
|
REDEPLOY
|
|
CONFIG_APPLY
|
|
ROLLBACK
|
|
APP_INSTALLER
|
|
}
|
|
|
|
model Network {
|
|
id String @id @default(cuid())
|
|
name String
|
|
driver String @default("bridge")
|
|
scope String @default("local")
|
|
subnet String?
|
|
gateway String?
|
|
containers Int @default(0)
|
|
serverId String
|
|
server Server @relation(fields: [serverId], references: [id], onDelete: Cascade)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([serverId, name])
|
|
@@index([serverId])
|
|
@@map("networks")
|
|
}
|
|
|
|
model FirewallRulePreset {
|
|
id String @id @default(cuid())
|
|
serverId String
|
|
server Server @relation(fields: [serverId], references: [id], onDelete: Cascade)
|
|
rule String
|
|
action String
|
|
direction String @default("IN")
|
|
source String @default("Anywhere")
|
|
description String @default("")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([serverId])
|
|
@@unique([serverId, rule, action, direction, source])
|
|
@@map("firewall_rule_presets")
|
|
}
|
|
|
|
enum ContainerStatus {
|
|
RUNNING
|
|
STOPPED
|
|
STARTING
|
|
STOPPING
|
|
ERROR
|
|
PAUSED
|
|
}
|
|
|
|
enum ContainerSourceType {
|
|
APP_INSTALLER
|
|
MANUAL
|
|
GIT_CLONE
|
|
GIT_PROVIDER
|
|
}
|
|
|
|
enum ContainerDeployMode {
|
|
IMAGE
|
|
DOCKERFILE
|
|
COMPOSE
|
|
}
|
|
|
|
enum RepositoryVisibility {
|
|
PUBLIC
|
|
PRIVATE
|
|
}
|
|
|
|
// ========================
|
|
// Domains & SSL
|
|
// ========================
|
|
model Domain {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
organizationId String
|
|
domainNameType DomainNameType @default(EXACT)
|
|
configMode DomainConfigMode @default(ISOLATED)
|
|
reviewStatus DomainReviewStatus @default(CONFIRMED)
|
|
isPrimary Boolean @default(false)
|
|
type DnsType @default(A)
|
|
value String // IP or CNAME target
|
|
serverId String?
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
server Server? @relation(fields: [serverId], references: [id])
|
|
targetContainerId String?
|
|
targetContainer Container? @relation(fields: [targetContainerId], references: [id], onDelete: SetNull)
|
|
targetPort Int?
|
|
proxy ProxyType @default(NONE)
|
|
discoverySource DomainDiscoverySource @default(MANUAL)
|
|
sslEnabled Boolean @default(false)
|
|
autoRenew Boolean @default(true)
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
sslCert SslCert?
|
|
|
|
@@index([organizationId])
|
|
@@index([targetContainerId])
|
|
@@map("domains")
|
|
}
|
|
|
|
enum DnsType {
|
|
A
|
|
AAAA
|
|
CNAME
|
|
MX
|
|
TXT
|
|
}
|
|
|
|
enum ProxyType {
|
|
TRAEFIK
|
|
NGINX
|
|
CADDY
|
|
NONE
|
|
}
|
|
|
|
enum DomainDiscoverySource {
|
|
MANUAL
|
|
NGINX
|
|
TRAEFIK
|
|
CADDY
|
|
CADDY_ADMIN
|
|
CERTBOT
|
|
}
|
|
|
|
enum DomainNameType {
|
|
EXACT
|
|
WILDCARD
|
|
}
|
|
|
|
enum DomainConfigMode {
|
|
SHARED
|
|
ISOLATED
|
|
}
|
|
|
|
enum DomainReviewStatus {
|
|
CONFIRMED
|
|
NEEDS_REVIEW
|
|
}
|
|
|
|
model SslCert {
|
|
id String @id @default(cuid())
|
|
domainId String @unique
|
|
domain Domain @relation(fields: [domainId], references: [id], onDelete: Cascade)
|
|
issuer String @default("Let's Encrypt")
|
|
certPem String? // certificate PEM
|
|
keyPem String? // private key PEM (encrypted)
|
|
issuedAt DateTime?
|
|
expiresAt DateTime?
|
|
status SslStatus @default(PENDING)
|
|
autoRenew Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("ssl_certs")
|
|
}
|
|
|
|
enum SslStatus {
|
|
VALID
|
|
EXPIRING
|
|
EXPIRED
|
|
PENDING
|
|
FAILED
|
|
}
|
|
|
|
// ========================
|
|
// Audit Log
|
|
// ========================
|
|
model AuditLog {
|
|
id String @id @default(cuid())
|
|
userId String?
|
|
organizationId String?
|
|
user User? @relation(fields: [userId], references: [id])
|
|
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: SetNull)
|
|
serverId String?
|
|
server Server? @relation(fields: [serverId], references: [id])
|
|
action String
|
|
category LogCategory
|
|
level LogLevel @default(INFO)
|
|
message String
|
|
meta Json?
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([createdAt])
|
|
@@index([organizationId])
|
|
@@index([serverId])
|
|
@@map("audit_logs")
|
|
}
|
|
|
|
enum LogCategory {
|
|
AUTH
|
|
SERVER
|
|
CONTAINER
|
|
DOMAIN
|
|
SSL
|
|
SECURITY
|
|
SYSTEM
|
|
TERMINAL
|
|
}
|
|
|
|
enum LogLevel {
|
|
DEBUG
|
|
INFO
|
|
WARNING
|
|
ERROR
|
|
SUCCESS
|
|
}
|
|
|
|
// ========================
|
|
// App Installer
|
|
// ========================
|
|
model AppInstall {
|
|
id String @id @default(cuid())
|
|
appId String // e.g. "wordpress", "nginx"
|
|
appName String
|
|
serverId String
|
|
server Server @relation(fields: [serverId], references: [id], onDelete: Cascade)
|
|
containerName String? // docker container name
|
|
port String? // host port used
|
|
status AppInstallStatus @default(PENDING)
|
|
error String?
|
|
installedAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("app_installs")
|
|
}
|
|
|
|
enum AppInstallStatus {
|
|
PENDING
|
|
INSTALLING
|
|
RUNNING
|
|
STARTING
|
|
STOPPING
|
|
STOPPED
|
|
PAUSED
|
|
UNKNOWN
|
|
FAILED
|
|
REMOVED
|
|
}
|
|
|
|
// ========================
|
|
// Backups
|
|
// ========================
|
|
model Backup {
|
|
id String @id @default(cuid())
|
|
name String
|
|
type BackupType
|
|
databaseEngine DatabaseEngine?
|
|
serverId String
|
|
server Server @relation(fields: [serverId], references: [id], onDelete: Cascade)
|
|
target String @default("Local")
|
|
sizeMb Float?
|
|
filePath String?
|
|
storageBucket String?
|
|
storageKey String?
|
|
storageEtag String?
|
|
storageDestinationId String?
|
|
status BackupStatus @default(PENDING)
|
|
error String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("backups")
|
|
}
|
|
|
|
enum BackupType {
|
|
DATABASE
|
|
VOLUME
|
|
FULL
|
|
}
|
|
|
|
enum DatabaseEngine {
|
|
POSTGRESQL
|
|
MYSQL
|
|
MARIADB
|
|
MONGODB
|
|
REDIS
|
|
}
|
|
|
|
enum BackupStatus {
|
|
PENDING
|
|
RUNNING
|
|
COMPLETED
|
|
FAILED
|
|
}
|