Files
HexaHost-GameCloud/packages/database/prisma/schema.prisma
smueller c4077d4673
Some checks failed
CI / Node — lint, typecheck, test, build (push) Failing after 10s
CI / Go — node-agent tests (push) Failing after 8s
CI / Go — edge-gateway build (push) Successful in 13s
Phase2
2026-06-26 12:01:25 +02:00

388 lines
10 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum UserStatus {
ACTIVE
SUSPENDED
DELETED
}
enum ServerEdition {
JAVA
BEDROCK
}
enum SoftwareFamily {
VANILLA
PAPER
PURPUR
FABRIC
FORGE
NEOFORGE
QUILT
BEDROCK_DEDICATED
}
enum GameServerStatus {
DRAFT
PROVISIONING
INSTALLING
STOPPED
STARTING
RUNNING
STOPPING
ERROR
DELETING
DELETED
}
enum GameNodeStatus {
ONLINE
OFFLINE
MAINTENANCE
DRAINING
UNREACHABLE
}
enum AllocationStatus {
ACTIVE
RELEASED
}
enum JobStatus {
PENDING
RUNNING
COMPLETED
FAILED
CANCELLED
}
model User {
id String @id @default(uuid())
email String @unique
username String @unique
displayName String?
status UserStatus @default(ACTIVE)
emailVerifiedAt DateTime? @db.Timestamptz(3)
failedLoginAttempts Int @default(0)
lockedUntil DateTime? @db.Timestamptz(3)
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
credentials UserCredential[]
sessions UserSession[]
platformRoles UserPlatformRole[]
gameServers GameServer[]
auditEvents AuditEvent[]
emailVerificationTokens EmailVerificationToken[]
passwordResetTokens PasswordResetToken[]
totpCredential TotpCredential?
@@map("users")
}
model UserCredential {
id String @id @default(uuid())
userId String
passwordHash String
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@map("user_credentials")
}
model UserSession {
id String @id @default(uuid())
userId String
tokenHash String @unique
expiresAt DateTime @db.Timestamptz(3)
revokedAt DateTime? @db.Timestamptz(3)
ipAddress String?
userAgent String?
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@index([expiresAt])
@@map("user_sessions")
}
model EmailVerificationToken {
id String @id @default(uuid())
userId String
tokenHash String @unique
expiresAt DateTime @db.Timestamptz(3)
usedAt DateTime? @db.Timestamptz(3)
createdAt DateTime @default(now()) @db.Timestamptz(3)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@index([expiresAt])
@@map("email_verification_tokens")
}
model PasswordResetToken {
id String @id @default(uuid())
userId String
tokenHash String @unique
expiresAt DateTime @db.Timestamptz(3)
usedAt DateTime? @db.Timestamptz(3)
createdAt DateTime @default(now()) @db.Timestamptz(3)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@index([expiresAt])
@@map("password_reset_tokens")
}
model TotpCredential {
id String @id @default(uuid())
userId String @unique
secret String
enabledAt DateTime? @db.Timestamptz(3)
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
recoveryCodes RecoveryCode[]
@@map("totp_credentials")
}
model RecoveryCode {
id String @id @default(uuid())
totpCredentialId String
codeHash String
usedAt DateTime? @db.Timestamptz(3)
createdAt DateTime @default(now()) @db.Timestamptz(3)
totpCredential TotpCredential @relation(fields: [totpCredentialId], references: [id], onDelete: Cascade)
@@index([totpCredentialId])
@@map("recovery_codes")
}
model PlatformRole {
id String @id @default(uuid())
name String @unique
description String?
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
userRoles UserPlatformRole[]
@@map("platform_roles")
}
model UserPlatformRole {
id String @id @default(uuid())
userId String
roleId String
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
role PlatformRole @relation(fields: [roleId], references: [id], onDelete: Cascade)
@@unique([userId, roleId])
@@index([userId])
@@index([roleId])
@@map("user_platform_roles")
}
model GameServer {
id String @id @default(uuid())
userId String
planId String?
nodeId String?
name String
status GameServerStatus @default(DRAFT)
version Int @default(1)
edition ServerEdition @default(JAVA)
softwareFamily SoftwareFamily @default(VANILLA)
minecraftVersion String @default("1.21.1")
eulaAccepted Boolean @default(false)
hostPort Int?
containerId String?
dataPath String?
ramMb Int @default(1024)
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
user User @relation(fields: [userId], references: [id])
plan Plan? @relation(fields: [planId], references: [id])
node GameNode? @relation(fields: [nodeId], references: [id])
stateTransitions GameServerStateTransition[]
allocation GameServerAllocation?
@@index([userId])
@@index([nodeId])
@@index([status])
@@map("game_servers")
}
model GameServerAllocation {
id String @id @default(uuid())
serverId String @unique
nodeId String
hostPort Int
ramMbReserved Int
status AllocationStatus @default(ACTIVE)
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
server GameServer @relation(fields: [serverId], references: [id], onDelete: Cascade)
node GameNode @relation(fields: [nodeId], references: [id])
@@unique([nodeId, hostPort])
@@index([nodeId])
@@map("game_server_allocations")
}
model GameServerStateTransition {
id String @id @default(uuid())
gameServerId String
fromStatus GameServerStatus?
toStatus GameServerStatus
reason String?
correlationId String?
actorId String?
errorCode String?
errorMessage String?
metadata Json?
createdAt DateTime @default(now()) @db.Timestamptz(3)
gameServer GameServer @relation(fields: [gameServerId], references: [id], onDelete: Cascade)
@@index([gameServerId])
@@index([createdAt])
@@map("game_server_state_transitions")
}
model GameNode {
id String @id @default(uuid())
name String @unique
hostname String
status GameNodeStatus @default(OFFLINE)
maxServers Int @default(10)
activeServers Int @default(0)
lastHeartbeatAt DateTime? @db.Timestamptz(3)
agentVersion String?
enrollmentTokenHash String?
enrolledAt DateTime? @db.Timestamptz(3)
metadata Json?
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
gameServers GameServer[]
heartbeats GameNodeHeartbeat[]
allocations GameServerAllocation[]
@@map("game_nodes")
}
model GameNodeHeartbeat {
id String @id @default(uuid())
nodeId String
payload Json?
createdAt DateTime @default(now()) @db.Timestamptz(3)
node GameNode @relation(fields: [nodeId], references: [id], onDelete: Cascade)
@@index([nodeId])
@@index([createdAt])
@@map("game_node_heartbeats")
}
model Plan {
id String @id @default(uuid())
name String @unique
slug String @unique
description String?
isFree Boolean @default(false)
isActive Boolean @default(true)
maxRamMb Int
maxCpuCores Float
maxStorageMb Int
metadata Json?
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
gameServers GameServer[]
@@map("plans")
}
model FeatureFlag {
id String @id @default(uuid())
key String @unique
description String?
enabled Boolean @default(false)
metadata Json?
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
@@map("feature_flags")
}
model SystemSetting {
id String @id @default(uuid())
key String @unique
value Json
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
@@map("system_settings")
}
model AuditEvent {
id String @id @default(uuid())
userId String?
action String
entityType String?
entityId String?
metadata Json?
ipAddress String?
createdAt DateTime @default(now()) @db.Timestamptz(3)
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
@@index([userId])
@@index([action])
@@index([entityType, entityId])
@@index([createdAt])
@@map("audit_events")
}
model JobRecord {
id String @id @default(uuid())
queue String
jobName String
status JobStatus @default(PENDING)
payload Json?
result Json?
error String?
attempts Int @default(0)
startedAt DateTime? @db.Timestamptz(3)
completedAt DateTime? @db.Timestamptz(3)
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
@@index([queue, status])
@@index([createdAt])
@@map("job_records")
}