290 lines
9.8 KiB
Plaintext
290 lines
9.8 KiB
Plaintext
model AppConfiguration {
|
|
id String @id @default(cuid())
|
|
updatedAt DateTime @updatedAt
|
|
name String
|
|
url String
|
|
theme String?
|
|
authRequireEmailVerification Boolean @default(false)
|
|
authRequireOrganization Boolean @default(true)
|
|
authRequireName Boolean @default(true)
|
|
analyticsEnabled Boolean @default(true)
|
|
analyticsSimpleAnalytics Boolean @default(false)
|
|
analyticsPlausibleAnalytics Boolean @default(false)
|
|
subscriptionRequired Boolean @default(true)
|
|
subscriptionAllowSubscribeBeforeSignUp Boolean @default(true)
|
|
subscriptionAllowSignUpBeforeSubscribe Boolean @default(true)
|
|
cookiesEnabled Boolean @default(false)
|
|
metricsEnabled Boolean @default(false)
|
|
metricsLogToConsole Boolean @default(false)
|
|
metricsSaveToDatabase Boolean @default(false)
|
|
metricsIgnoreUrls String?
|
|
brandingLogo String?
|
|
brandingLogoDarkMode String?
|
|
brandingIcon String?
|
|
brandingIconDarkMode String?
|
|
brandingFavicon String?
|
|
headScripts String?
|
|
bodyScripts String?
|
|
emailProvider String?
|
|
emailFromEmail String?
|
|
emailFromName String?
|
|
emailSupportEmail String?
|
|
}
|
|
|
|
model Log {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
tenantId String?
|
|
userId String?
|
|
apiKeyId String?
|
|
rowId String?
|
|
url String
|
|
action String
|
|
details String?
|
|
commentId String?
|
|
apiKey ApiKey? @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)
|
|
comment RowComment? @relation(fields: [commentId], references: [id])
|
|
row Row? @relation(fields: [rowId], references: [id])
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
webhookLogs EntityWebhookLog[]
|
|
}
|
|
|
|
model AuditEvent {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
tenantId String?
|
|
actorId String?
|
|
actorType String
|
|
actorEmail String?
|
|
actorIp String?
|
|
actorUserAgent String?
|
|
action String
|
|
targetType String?
|
|
targetId String?
|
|
requestId String?
|
|
sourceModule String?
|
|
outcome String @default("success")
|
|
dataSensitivity String @default("internal")
|
|
regulatoryScope String[] @default([])
|
|
metadata Json?
|
|
previousHash String?
|
|
eventHash String?
|
|
|
|
@@index([tenantId, createdAt], name: "audit_event_tenant_created_at_idx")
|
|
@@index([actorId, createdAt], name: "audit_event_actor_created_at_idx")
|
|
@@index([action, createdAt], name: "audit_event_action_created_at_idx")
|
|
@@index([requestId], name: "audit_event_request_id_idx")
|
|
@@index([tenantId, action, createdAt], name: "audit_event_tenant_action_created_at_idx")
|
|
@@index([tenantId, outcome, createdAt], name: "audit_event_tenant_outcome_created_at_idx")
|
|
}
|
|
|
|
model IdempotencyKey {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
expiresAt DateTime?
|
|
scope String
|
|
key String
|
|
requestHash String
|
|
responseStatus Int
|
|
responseBody Json?
|
|
responseHeaders Json?
|
|
|
|
@@unique([scope, key], name: "idempotency_key_scope_key")
|
|
@@index([expiresAt], name: "idempotency_key_expires_at_idx")
|
|
}
|
|
|
|
model ApiKey {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
createdByUserId String
|
|
tenantId String
|
|
key String @default(uuid())
|
|
keyHash String?
|
|
keyPrefix String?
|
|
keyLastFour String?
|
|
hashedAt DateTime?
|
|
keyVersion Int @default(1)
|
|
alias String
|
|
expires DateTime?
|
|
active Boolean
|
|
createdByUser User @relation(fields: [createdByUserId], references: [id], onDelete: Cascade)
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
entities ApiKeyEntity[]
|
|
apiKeyLogs ApiKeyLog[]
|
|
logs Log[]
|
|
createdRows Row[]
|
|
tenantIpAddresses TenantIpAddress[]
|
|
|
|
@@unique([tenantId, alias])
|
|
@@unique([tenantId, key])
|
|
@@unique([keyHash], name: "api_key_hash_key")
|
|
@@index([key])
|
|
}
|
|
|
|
model ApiKeyLog {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
apiKeyId String?
|
|
apiKey ApiKey? @relation(fields: [apiKeyId], references: [id])
|
|
tenantId String?
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
ip String
|
|
endpoint String
|
|
method String
|
|
params String
|
|
status Int?
|
|
duration Int?
|
|
error String?
|
|
type String?
|
|
alias String?
|
|
tenantName String?
|
|
|
|
@@index([tenantId], name: "api_key_log_tenant")
|
|
@@index([tenantId, createdAt], name: "api_key_log_tenant_created_at")
|
|
@@index([tenantId, type], name: "api_key_log_tenant_type")
|
|
@@index([apiKeyId, tenantId, createdAt(sort: Desc)], name: "api_key_log_key_tenant_created_at")
|
|
}
|
|
|
|
model Event {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
tenantId String?
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
|
userId String?
|
|
user User? @relation(fields: [userId], references: [id])
|
|
name String
|
|
data String
|
|
resource String?
|
|
description String?
|
|
attempts EventWebhookAttempt[]
|
|
}
|
|
|
|
model EventWebhookAttempt {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
startedAt DateTime?
|
|
finishedAt DateTime?
|
|
eventId String
|
|
event Event @relation(fields: [eventId], references: [id], onDelete: Cascade)
|
|
endpoint String
|
|
success Boolean?
|
|
status Int?
|
|
message String?
|
|
body String?
|
|
}
|
|
|
|
model MetricLog {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
env String
|
|
type String // loader, action
|
|
route String
|
|
url String
|
|
function String
|
|
duration Int
|
|
userId String?
|
|
tenantId String?
|
|
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
}
|
|
|
|
model FileUploadProgress {
|
|
id String @id @default(cuid())
|
|
fileName String
|
|
progressServer Int
|
|
progressStorage Int
|
|
url String?
|
|
error String?
|
|
chunks FileChunk[]
|
|
}
|
|
|
|
model FileChunk {
|
|
id Int @id @default(autoincrement())
|
|
fileUploadId String
|
|
fileUpload FileUploadProgress @relation(fields: [fileUploadId], references: [id], onDelete: Cascade)
|
|
index Int
|
|
data Bytes
|
|
}
|
|
|
|
model FileObject {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
provider String
|
|
bucket String
|
|
key String
|
|
contentType String
|
|
byteSize Int
|
|
checksumSha256 String?
|
|
publicUrl String?
|
|
uploadedAt DateTime?
|
|
lastSignedUploadAt DateTime?
|
|
lastSignedDownloadAt DateTime?
|
|
metadata Json?
|
|
|
|
@@unique([provider, bucket, key], name: "file_object_provider_bucket_key")
|
|
@@index([provider, bucket], name: "file_object_provider_bucket_idx")
|
|
@@index([uploadedAt], name: "file_object_uploaded_at_idx")
|
|
}
|
|
|
|
/// Privacy (AD-22): `ip` speichert einen HMAC-SHA256-Pseudonym-Hash der Client-IP, KEINE Klartext-IP.
|
|
/// Persistiert wird nur das Land (countryCode/countryName); regionCode/city/zipCode/latitude/longitude
|
|
/// bleiben bewusst leer. Auflösung lokal (DB-IP Lite), kein externer Transfer.
|
|
model IpAddress {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
ip String @unique
|
|
provider String
|
|
type String
|
|
countryCode String
|
|
countryName String
|
|
regionCode String
|
|
regionName String
|
|
city String
|
|
zipCode String
|
|
latitude Decimal?
|
|
longitude Decimal?
|
|
metadata String
|
|
logs IpAddressLog[]
|
|
}
|
|
|
|
/// Privacy (AD-22): `ip` ist der HMAC-Pseudonym-Hash der Client-IP, kein Klartext.
|
|
model IpAddressLog {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
ip String
|
|
url String
|
|
action String
|
|
description String
|
|
success Boolean
|
|
error String?
|
|
metadata String?
|
|
ipAddressId String?
|
|
ipAddress IpAddress? @relation(fields: [ipAddressId], references: [id])
|
|
}
|
|
|
|
model Widget {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
tenantId String?
|
|
name String
|
|
appearance String
|
|
metadata String
|
|
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([tenantId, name])
|
|
}
|
|
|
|
model Credential {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
name String @unique
|
|
value Json
|
|
}
|