generator client { provider = "prisma-client-js" previewFeatures = ["postgresqlExtensions"] } datasource db { provider = "postgresql" url = env("DATABASE_URL") extensions = [pgcrypto, uuid_ossp(map: "uuid-ossp", schema: "public")] schemas = ["admin", "public"] } // ─── admin schema (shared with gscAdmin) ─────────────────────── model User { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid gscsid String @unique @db.VarChar(64) firstName String? @map("first_name") @db.VarChar(128) lastName String? @map("last_name") @db.VarChar(128) displayName String? @map("display_name") @db.VarChar(256) email String? @db.VarChar(256) phone String? @db.VarChar(32) mobile String? @db.VarChar(32) avatarUrl String? @map("avatar_url") @db.VarChar(512) timezone String? @default("UTC") @db.VarChar(64) locale String? @default("en") @db.VarChar(10) status String? @default("active") @db.VarChar(32) lastLoginAt DateTime? @map("last_login_at") @db.Timestamptz(6) lastActivityAt DateTime? @map("last_activity_at") @db.Timestamptz(6) metadata Json? @default("{}") createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) updatedAt DateTime? @default(now()) @updatedAt @map("updated_at") @db.Timestamptz(6) settings UserSetting[] @@index([gscsid], map: "idx_users_gscsid") @@map("users") @@schema("admin") } model SettingsDefinition { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid category String @db.VarChar(64) key String @db.VarChar(128) dataType String @map("data_type") @db.VarChar(32) defaultValue Json? @map("default_value") min_value Decimal? @db.Decimal max_value Decimal? @db.Decimal allowed_values Json? allow_customer_override Boolean? @default(true) allow_tenant_override Boolean? @default(true) allow_user_override Boolean? @default(true) description String? display_order Int? @default(0) customerSettings CustomerSetting[] tenantSettings TenantSetting[] userSettings UserSetting[] @@unique([category, key]) @@map("settings_definitions") @@schema("admin") } model CustomerSetting { customerId String @map("customer_id") @db.Uuid settingId String @map("setting_id") @db.Uuid value Json is_mandatory Boolean? @default(false) allow_tenant_override Boolean? @default(true) updated_by String? @db.Uuid updatedAt DateTime? @default(now()) @updatedAt @map("updated_at") @db.Timestamptz(6) setting SettingsDefinition @relation(fields: [settingId], references: [id], onDelete: Cascade, onUpdate: NoAction) @@id([customerId, settingId]) @@index([settingId, customerId], map: "idx_customer_settings_lookup") @@map("customer_settings") @@schema("admin") } model TenantSetting { tenantId String @map("tenant_id") @db.Uuid settingId String @map("setting_id") @db.Uuid value Json is_mandatory Boolean? @default(false) allow_user_override Boolean? @default(true) updated_by String? @db.Uuid updatedAt DateTime? @default(now()) @updatedAt @map("updated_at") @db.Timestamptz(6) setting SettingsDefinition @relation(fields: [settingId], references: [id], onDelete: Cascade, onUpdate: NoAction) @@id([tenantId, settingId]) @@index([settingId, tenantId], map: "idx_tenant_settings_lookup") @@map("tenant_settings") @@schema("admin") } model UserSetting { userId String @map("user_id") @db.Uuid settingId String @map("setting_id") @db.Uuid value Json updatedAt DateTime? @default(now()) @updatedAt @map("updated_at") @db.Timestamptz(6) setting SettingsDefinition @relation(fields: [settingId], references: [id], onDelete: Cascade, onUpdate: NoAction) user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: NoAction) @@id([userId, settingId]) @@map("user_settings") @@schema("admin") } // ─── public schema ───────────────────────────────────────────── model UserActivityLog { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid userId String @map("user_id") @db.Uuid tenantId String @map("tenant_id") @db.Uuid action String @db.VarChar(64) target String? @db.VarChar(256) metadata Json? @default("{}") ipAddress String? @map("ip_address") @db.VarChar(45) userAgent String? @map("user_agent") @db.VarChar(512) createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) @@index([userId, createdAt(sort: Desc)], map: "idx_user_activity_user") @@index([tenantId, createdAt(sort: Desc)], map: "idx_user_activity_tenant") @@map("user_activity_log") @@schema("public") } // ============================================================================ // Privileged Access Management (JIT elevation) — shared with gscAdmin. // Tables created by gscAdmin's `20260518_pam_init` migration; gscMy // only needs the model definitions to write/read them. // See gscAdmin/docs/pam-plan.md for the full design. // ============================================================================ model PrivilegePolicy { roleName String @id @map("role_name") @db.VarChar(128) maxDurationHours Int @default(4) @map("max_duration_hours") @db.SmallInt defaultDurationHours Int @default(1) @map("default_duration_hours") @db.SmallInt approvalMode String @default("audit") @map("approval_mode") @db.VarChar(16) approverEmail String? @map("approver_email") @db.VarChar(256) requiresMfa Boolean @default(false) @map("requires_mfa") eligibleGroup String @map("eligible_group") @db.VarChar(128) description String? createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamptz(6) grants PrivilegeGrant[] @@map("privilege_policies") @@schema("admin") } model PrivilegeGrant { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid gscsid String @db.VarChar(64) roleName String @map("role_name") @db.VarChar(128) status String @default("pending") @db.VarChar(16) approvalToken String? @unique @map("approval_token") @db.VarChar(64) requestedAt DateTime @default(now()) @map("requested_at") @db.Timestamptz(6) grantedAt DateTime? @map("granted_at") @db.Timestamptz(6) expiresAt DateTime @map("expires_at") @db.Timestamptz(6) grantedBy String? @map("granted_by") @db.VarChar(256) justification String mfaEvidence Json? @map("mfa_evidence") revokedAt DateTime? @map("revoked_at") @db.Timestamptz(6) revokedBy String? @map("revoked_by") @db.VarChar(64) revokeReason String? @map("revoke_reason") policy PrivilegePolicy @relation(fields: [roleName], references: [roleName], onUpdate: Cascade) @@index([gscsid, roleName], map: "idx_priv_grants_active") @@index([expiresAt], map: "idx_priv_grants_expires") @@map("privilege_grants") @@schema("admin") } model PrivilegeAudit { id BigInt @id @default(autoincrement()) ts DateTime @default(now()) @db.Timestamptz(6) event String @db.VarChar(32) gscsid String @db.VarChar(64) roleName String @map("role_name") @db.VarChar(128) grantId String? @map("grant_id") @db.Uuid actorGscsid String? @map("actor_gscsid") @db.VarChar(64) actorEmail String? @map("actor_email") @db.VarChar(256) detail Json? @@index([gscsid, ts(sort: Desc)], map: "idx_priv_audit_user_ts") @@map("privilege_audit") @@schema("admin") }