// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" } datasource db { provider = "mysql" url = env("DATABASE_URL") } // Multi-tenancy model Tenant { id String @id @default(uuid()) name String slug String @unique isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt users User[] objectDefinitions ObjectDefinition[] accounts Account[] apps App[] roles Role[] permissions Permission[] @@map("tenants") } // User & Auth model User { id String @id @default(uuid()) tenantId String email String password String firstName String? lastName String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade) userRoles UserRole[] accounts Account[] @@unique([tenantId, email]) @@index([tenantId]) @@map("users") } // RBAC - Spatie-like model Role { id String @id @default(uuid()) tenantId String name String guardName String @default("api") description String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade) userRoles UserRole[] rolePermissions RolePermission[] @@unique([tenantId, name, guardName]) @@index([tenantId]) @@map("roles") } model Permission { id String @id @default(uuid()) tenantId String name String guardName String @default("api") description String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade) rolePermissions RolePermission[] @@unique([tenantId, name, guardName]) @@index([tenantId]) @@map("permissions") } model UserRole { id String @id @default(uuid()) userId String roleId String createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id], onDelete: Cascade) role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) @@unique([userId, roleId]) @@index([userId]) @@index([roleId]) @@map("user_roles") } model RolePermission { id String @id @default(uuid()) roleId String permissionId String createdAt DateTime @default(now()) role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade) @@unique([roleId, permissionId]) @@index([roleId]) @@index([permissionId]) @@map("role_permissions") } // Object Definition (Metadata) model ObjectDefinition { id String @id @default(uuid()) tenantId String apiName String label String pluralLabel String? description String? @db.Text isSystem Boolean @default(false) tableName String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade) fields FieldDefinition[] pages AppPage[] @@unique([tenantId, apiName]) @@index([tenantId]) @@map("object_definitions") } model FieldDefinition { id String @id @default(uuid()) objectId String apiName String label String type String // text, number, boolean, date, datetime, lookup, picklist, etc. description String? @db.Text isRequired Boolean @default(false) isUnique Boolean @default(false) isReadonly Boolean @default(false) isLookup Boolean @default(false) referenceTo String? // objectApiName for lookup fields defaultValue String? options Json? // for picklist fields validationRules Json? // custom validation rules isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt object ObjectDefinition @relation(fields: [objectId], references: [id], onDelete: Cascade) @@unique([objectId, apiName]) @@index([objectId]) @@map("field_definitions") } // Example static object: Account model Account { id String @id @default(uuid()) tenantId String name String status String @default("active") ownerId String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade) owner User @relation(fields: [ownerId], references: [id]) @@index([tenantId]) @@index([ownerId]) @@map("accounts") } // Application Builder model App { id String @id @default(uuid()) tenantId String slug String label String description String? @db.Text icon String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade) pages AppPage[] @@unique([tenantId, slug]) @@index([tenantId]) @@map("apps") } model AppPage { id String @id @default(uuid()) appId String slug String label String type String // list, board, dashboard, form, detail objectApiName String? objectId String? config Json? // page-specific configuration sortOrder Int @default(0) isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt app App @relation(fields: [appId], references: [id], onDelete: Cascade) object ObjectDefinition? @relation(fields: [objectId], references: [id]) @@unique([appId, slug]) @@index([appId]) @@index([objectId]) @@map("app_pages") }