117 lines
3.9 KiB
Plaintext
117 lines
3.9 KiB
Plaintext
// VR-P28a / M038-M039: platform operator identity and authorization.
|
|
//
|
|
// These models are deliberately tenant-less. Authentik is the only productive
|
|
// login authority; HiveGrid stores the resulting operator identity, session,
|
|
// role grants and MFA assurance. The local development fallback may provision
|
|
// an AdminUser without an Authentik subject only behind the fail-closed guards
|
|
// documented in AGENTS.md.
|
|
|
|
enum AdminUserStatus {
|
|
active
|
|
disabled
|
|
locked
|
|
}
|
|
|
|
model AdminUser {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
email String @unique
|
|
firstName String
|
|
lastName String
|
|
avatar String?
|
|
locale String?
|
|
status AdminUserStatus @default(active)
|
|
authentikSubject String? @unique
|
|
authentikGroups String[] @default([])
|
|
lastSsoLoginAt DateTime?
|
|
lastLoginIpHash String?
|
|
disabledAt DateTime?
|
|
disabledReason String?
|
|
|
|
sessions AdminSession[]
|
|
roles AdminUserRole[]
|
|
dataConnections AdminDataConnection[]
|
|
connectionCredentials AdminConnectionCredential[]
|
|
mailboxes AdminMailbox[]
|
|
phoneConnections AdminPhoneConnection[]
|
|
calendarConnections AdminCalendarConnection[]
|
|
notificationDeliveries NotificationDelivery[]
|
|
supportTicketMessages SupportTicketMessage[] @relation("supportTicketMessageAuthor")
|
|
adminTenantNotesAuthored AdminTenantNote[] @relation("adminTenantNoteAuthor")
|
|
|
|
@@index([status, email], name: "admin_user_status_email_idx")
|
|
@@index([lastSsoLoginAt(sort: Desc)], name: "admin_user_last_sso_login_idx")
|
|
}
|
|
|
|
model AdminSession {
|
|
id String @id @default(cuid())
|
|
adminUserId String
|
|
tokenHash String @unique
|
|
createdAt DateTime @default(now())
|
|
lastSeenAt DateTime @default(now())
|
|
expiresAt DateTime
|
|
revokedAt DateTime?
|
|
ipHash String?
|
|
userAgent String?
|
|
approxLocation String?
|
|
authenticationMethods String[] @default([])
|
|
mfaAssuredAt DateTime?
|
|
|
|
adminUser AdminUser @relation(fields: [adminUserId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([adminUserId, revokedAt], name: "admin_session_user_revoked_idx")
|
|
@@index([expiresAt], name: "admin_session_expiry_idx")
|
|
}
|
|
|
|
model AdminRole {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
name String @unique
|
|
description String
|
|
systemKey String? @unique
|
|
isSystem Boolean @default(false)
|
|
active Boolean @default(true)
|
|
|
|
permissions AdminRolePermission[]
|
|
users AdminUserRole[]
|
|
|
|
@@index([active, name], name: "admin_role_active_name_idx")
|
|
}
|
|
|
|
model AdminPermission {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
name String @unique
|
|
description String
|
|
|
|
roles AdminRolePermission[]
|
|
}
|
|
|
|
model AdminRolePermission {
|
|
adminRoleId String
|
|
adminPermissionId String
|
|
createdAt DateTime @default(now())
|
|
|
|
role AdminRole @relation(fields: [adminRoleId], references: [id], onDelete: Cascade)
|
|
permission AdminPermission @relation(fields: [adminPermissionId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([adminRoleId, adminPermissionId])
|
|
@@index([adminPermissionId], name: "admin_role_permission_permission_idx")
|
|
}
|
|
|
|
model AdminUserRole {
|
|
adminUserId String
|
|
adminRoleId String
|
|
createdAt DateTime @default(now())
|
|
grantedByAdminUserId String?
|
|
|
|
user AdminUser @relation(fields: [adminUserId], references: [id], onDelete: Cascade)
|
|
role AdminRole @relation(fields: [adminRoleId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([adminUserId, adminRoleId])
|
|
@@index([adminRoleId], name: "admin_user_role_role_idx")
|
|
}
|