Files
HiveGrid-Wireframes/hivegrid-cloud/prisma/schema/accounts.prisma
T

335 lines
13 KiB
Plaintext

model User {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
email String @unique
passwordHash String?
firstName String
lastName String
avatar String?
phone String?
defaultTenantId String?
verifyToken String?
verifyTokenCreatedAt DateTime?
locale String?
lightOrDarkMode String?
totpSecretEncrypted String?
totpPendingSecretEncrypted String?
totpEnabledAt DateTime?
totpPendingCreatedAt DateTime?
mfaRecoveryCodeHashes Json?
mfaRecoveryCodesGeneratedAt DateTime?
mfaRecoveryCodeLastUsedAt DateTime?
active Boolean @default(false)
// Phase 10 Task #68 — DSGVO bulk-ops self-service flags.
// `pendingDeletion` is set the moment the user confirms a delete request via
// the email-verification token; `scheduledDeletionAt` carries the 30-day
// grace deadline. `pseudonymized` is flipped permanently once the cascade
// job has rewritten PII to deterministic pseudonyms (Art. 17 alternative
// path for retention-bound rows such as AuditEvents). `deletionRequestId`
// is the idempotency token shared with the worker job + audit trail.
pendingDeletion Boolean @default(false)
scheduledDeletionAt DateTime?
deletionRequestedAt DateTime?
pseudonymized Boolean @default(false)
pseudonymizedAt DateTime?
deletionRequestId String? @unique
admin AdminUser? // Has access to the admin panel
createdApiKeys ApiKey[]
createdGroups Group[]
groups GroupUser[]
logs Log[]
createdRows Row[]
createdRowComments RowComment[]
createdRowCommentReactions RowCommentReaction[]
createdEntityViews EntityView[] @relation("createdByUser")
rowPermissions RowPermission[]
assignedTasks RowTask[] @relation("assignedToUser")
completedTasks RowTask[] @relation("completedByUser")
createdRowTasks RowTask[] @relation("createdByUser")
tenants TenantUser[]
invitation TenantUserInvitation? @relation("createdUser")
sentInvitations TenantUserInvitation[] @relation("fromUser")
acceptedInvitations TenantUserInvitation[] @relation("acceptedByUser")
revokedInvitations TenantUserInvitation[] @relation("revokedByUser")
roles UserRole[]
readEmails EmailRead[]
entityViews EntityView[]
onboardingSessions OnboardingSession[]
tenantIpAddresses TenantIpAddress[]
analyticsUniqueSessions AnalyticsUniqueVisitor[]
metricLogs MetricLog[]
formulaLogs FormulaLog[]
knowledgeBaseArticles KnowledgeBaseArticle[]
events Event[]
workflowsCreated Workflow[] @relation("createdByUser")
workflowsExecuted WorkflowExecution[] @relation("executedByUser")
workflowVariablesCreated WorkflowVariable[]
workflowCredentialsCreated WorkflowCredential[]
feedback Feedback[]
supportTickets SupportTicket[]
credits Credit[]
portals Portal[]
impersonationAuditsActor ImpersonationAudit[] @relation("ImpersonationAuditActor")
impersonationAuditsTarget ImpersonationAudit[] @relation("ImpersonationAuditTarget")
notificationDeliveries NotificationDelivery[]
userSessions UserSession[]
trustedDevices TrustedDevice[]
notificationPreferences UserNotificationPreference[]
deviceTokens DeviceToken[]
magicLinkTokens MagicLinkToken[]
appsInstalled App[] @relation("appInstalledByUser")
appSyncRuns AppSyncRun[] @relation("appSyncRunCreatedByUser")
sitesCreated Site[] @relation("sitesCreatedByUser")
// Phase 10 Task #68 — grace-period cron query scans pendingDeletion users
// whose deadline has elapsed. Index keeps the cron O(log n).
@@index([pendingDeletion, scheduledDeletionAt], name: "user_pending_deletion_due_idx")
}
model MagicLinkToken {
id String @id @default(cuid())
createdAt DateTime @default(now())
userId String
tokenHash String @unique
expiresAt DateTime
consumedAt DateTime?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, expiresAt])
@@index([expiresAt, consumedAt])
}
// Has access to the admin panel
model AdminUser {
userId String @id @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
// Phase 09 #82 — OIDC SSO link to external IdP (Authentik).
// ssoProvider / ssoSubjectId together identify the federated identity
// (typically `authentik` + the IdP-stable `sub` claim). Both nullable so
// legacy bootstrap admins predating SSO continue to function.
ssoProvider String?
ssoSubjectId String?
ssoGroups String[] @default([])
lastSsoLoginAt DateTime?
@@unique([ssoProvider, ssoSubjectId])
@@index([ssoSubjectId])
}
model Tenant {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
slug String @unique
name String
icon String?
logo String?
subscriptionId String?
active Boolean @default(false)
deactivatedReason String?
apiKeys ApiKey[]
apiKeyLogs ApiKeyLog[]
groups Group[]
logs Log[]
rows Row[]
rowPermissions RowPermission[]
subscription TenantSubscription?
productConfiguration TenantProductConfiguration?
featureOverrides TenantFeatureOverride[]
users TenantUser[]
roles Role[]
invitations TenantUserInvitation[]
userRoles UserRole[]
inboundAddresses TenantInboundAddress[]
events Event[]
fromRegistration Registration?
entityViews EntityView[]
emailSenders EmailSender[]
campaigns Campaign[]
outboundEmails OutboundEmail[]
onboardingSessions OnboardingSession[]
ipAddresses TenantIpAddress[]
tenantSettingsRow TenantSettingsRow?
metricLogs MetricLog[]
formulaLogs FormulaLog[]
knowledgeBases KnowledgeBase[]
types TenantType[]
entityProperties Property[]
entityGroupConfigurations EntityGroupConfiguration[]
entityTemplates EntityTemplate[]
workflows Workflow[]
workflowExecutions WorkflowExecution[]
workflowVariables WorkflowVariable[]
workflowCredentials WorkflowCredential[]
feedback Feedback[]
supportTickets SupportTicket[]
credits Credit[]
portals Portal[]
portalsUsers PortalUser[]
widgets Widget[]
impersonationAudits ImpersonationAudit[]
notificationDeliveries NotificationDelivery[]
notificationPreferences UserNotificationPreference[]
deviceTokens DeviceToken[]
authProviders WorkspaceAuthProvider[]
theme String?
themeConfig String?
apps App[]
dataConnections DataConnection[]
appSyncRuns AppSyncRun[]
sites Site[]
forms Form[]
@@index([slug])
}
model WorkspaceAuthProvider {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenantId String
kind String
name String
slug String
enabled Boolean @default(false)
issuer String?
authorizationUrl String?
tokenUrl String?
jwksUrl String?
clientId String?
entityId String?
ssoUrl String?
certificateFingerprint String?
metadataUpdatedAt DateTime?
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
@@unique([tenantId, slug])
@@index([tenantId, kind, enabled])
@@index([tenantId, updatedAt])
}
model ImpersonationAudit {
id String @id @default(cuid())
createdAt DateTime @default(now())
actorUserId String?
targetUserId String?
tenantId String?
action String
reason String?
requestPath String
metadata String?
actor User? @relation("ImpersonationAuditActor", fields: [actorUserId], references: [id], onDelete: SetNull)
target User? @relation("ImpersonationAuditTarget", fields: [targetUserId], references: [id], onDelete: SetNull)
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)
@@index([actorUserId])
@@index([targetUserId])
@@index([tenantId])
@@index([createdAt])
}
model TenantUser {
id String @id @default(cuid())
createdAt DateTime @default(now())
tenantId String
userId String
type Int
joined Int
status Int
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model TenantUserInvitation {
id String @id @default(cuid())
tenantId String
email String
firstName String
lastName String
type Int
pending Boolean
status String @default("pending")
tokenHash String?
tokenPrefix String?
expiresAt DateTime?
acceptedAt DateTime?
revokedAt DateTime?
createdUserId String? @unique
fromUserId String?
acceptedByUserId String?
revokedByUserId String?
fromUser User? @relation(name: "fromUser", fields: [fromUserId], references: [id])
user User? @relation(name: "createdUser", fields: [createdUserId], references: [id])
acceptedByUser User? @relation(name: "acceptedByUser", fields: [acceptedByUserId], references: [id])
revokedByUser User? @relation(name: "revokedByUser", fields: [revokedByUserId], references: [id])
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
@@index([tenantId, status, expiresAt])
@@index([tenantId, email, status])
@@index([tenantId, tokenPrefix])
@@index([acceptedByUserId])
@@index([revokedByUserId])
}
model Registration {
id String @id @default(cuid())
createdAt DateTime @default(now())
email String @unique
firstName String
lastName String
slug String?
token String @unique
ipAddress String?
company String?
selectedSubscriptionPriceId String?
leadConversionLeadId String?
leadConversionToken String?
leadConversionPlanId String?
createdTenantId String? @unique
createdTenant Tenant? @relation(fields: [createdTenantId], references: [id], onDelete: Cascade)
}
model Blacklist {
id String @id @default(cuid())
createdAt DateTime @default(now())
type String // email, domain, ip
value String
active Boolean @default(true)
registerAttempts Int @default(0)
}
model TenantIpAddress {
id String @id @default(cuid())
tenantId String
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
userId String?
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
apiKeyId String?
apiKey ApiKey? @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)
ip String
fromUrl String
createdAt DateTime @default(now())
@@unique([tenantId, ip, userId, apiKeyId])
}
model TenantType {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String @unique
titlePlural String
description String?
isDefault Boolean @default(false)
tenants Tenant[]
subscriptionProducts SubscriptionProduct[]
}