mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-05-05 19:19:35 +00:00
904 lines
26 KiB
Plaintext
904 lines
26 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "sqlite"
|
|
}
|
|
|
|
// =============================================================================
|
|
// CORE IDENTITY & AUTH
|
|
// =============================================================================
|
|
|
|
model User {
|
|
id String @id
|
|
username String @unique
|
|
email String @unique
|
|
role String // public|user|moderator|admin|god|supergod
|
|
profilePicture String?
|
|
bio String?
|
|
createdAt BigInt
|
|
tenantId String?
|
|
isInstanceOwner Boolean @default(false)
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
|
ownedTenants Tenant[] @relation("TenantOwner")
|
|
comments Comment[]
|
|
powerTransfersFrom PowerTransferRequest[] @relation("PowerTransferFrom")
|
|
powerTransfersTo PowerTransferRequest[] @relation("PowerTransferTo")
|
|
passwordChangeTimestamp BigInt?
|
|
firstLogin Boolean @default(false)
|
|
sessions Session[]
|
|
notifications Notification[]
|
|
auditLogs AuditLog[]
|
|
mediaAssets MediaAsset[]
|
|
forumPosts ForumPost[]
|
|
forumThreads ForumThread[]
|
|
|
|
@@index([tenantId])
|
|
@@index([role])
|
|
}
|
|
|
|
model Credential {
|
|
username String @id
|
|
passwordHash String
|
|
}
|
|
|
|
model Session {
|
|
id String @id
|
|
userId String
|
|
token String @unique
|
|
expiresAt BigInt
|
|
createdAt BigInt
|
|
lastActivity BigInt
|
|
ipAddress String?
|
|
userAgent String?
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@index([expiresAt])
|
|
@@index([token])
|
|
}
|
|
|
|
// =============================================================================
|
|
// MULTI-TENANCY
|
|
// =============================================================================
|
|
|
|
model Tenant {
|
|
id String @id
|
|
name String
|
|
slug String @unique
|
|
ownerId String
|
|
createdAt BigInt
|
|
homepageConfig String?
|
|
settings String? // JSON: theme, features, limits
|
|
owner User @relation("TenantOwner", fields: [ownerId], references: [id], onDelete: Cascade)
|
|
users User[]
|
|
workflows Workflow[]
|
|
luaScripts LuaScript[]
|
|
pages PageConfig[]
|
|
schemas ModelSchema[]
|
|
notifications Notification[]
|
|
auditLogs AuditLog[]
|
|
mediaAssets MediaAsset[]
|
|
forumCategories ForumCategory[]
|
|
|
|
@@index([slug])
|
|
@@index([ownerId])
|
|
}
|
|
|
|
// =============================================================================
|
|
// ROUTING & PAGES
|
|
// =============================================================================
|
|
|
|
model PageConfig {
|
|
id String @id
|
|
tenantId String?
|
|
packageId String? // Which package defined this route
|
|
path String // Route pattern: /media/jobs, /forum/:id
|
|
title String
|
|
description String? // SEO meta description
|
|
icon String? // Icon for navigation menus
|
|
component String? // Named component reference
|
|
componentTree String // JSON: full component tree
|
|
level Int // Required permission level 1-6
|
|
requiresAuth Boolean
|
|
requiredRole String?
|
|
parentPath String? // Parent route for hierarchy
|
|
sortOrder Int @default(0)
|
|
isPublished Boolean @default(true)
|
|
params String? // JSON: route parameter definitions
|
|
meta String? // JSON: additional metadata (og tags, etc.)
|
|
createdAt BigInt?
|
|
updatedAt BigInt?
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([tenantId, path])
|
|
@@index([tenantId])
|
|
@@index([packageId])
|
|
@@index([level])
|
|
@@index([parentPath])
|
|
}
|
|
|
|
// =============================================================================
|
|
// WORKFLOWS & SCRIPTING
|
|
// =============================================================================
|
|
|
|
model Workflow {
|
|
id String @id
|
|
tenantId String?
|
|
name String
|
|
description String?
|
|
nodes String // JSON: WorkflowNode[]
|
|
edges String // JSON: WorkflowEdge[]
|
|
enabled Boolean
|
|
version Int @default(1)
|
|
createdAt BigInt?
|
|
updatedAt BigInt?
|
|
createdBy String?
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([tenantId])
|
|
@@index([enabled])
|
|
}
|
|
|
|
model LuaScript {
|
|
id String @id
|
|
tenantId String?
|
|
name String
|
|
description String?
|
|
code String
|
|
parameters String // JSON: Array<{name, type}>
|
|
returnType String?
|
|
isSandboxed Boolean @default(true)
|
|
allowedGlobals String @default("[]")
|
|
timeoutMs Int @default(5000)
|
|
version Int @default(1)
|
|
createdAt BigInt?
|
|
updatedAt BigInt?
|
|
createdBy String?
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([tenantId])
|
|
@@index([name])
|
|
}
|
|
|
|
// =============================================================================
|
|
// DATA SCHEMAS
|
|
// =============================================================================
|
|
|
|
model ModelSchema {
|
|
id String @id @default(cuid())
|
|
tenantId String?
|
|
name String
|
|
label String?
|
|
labelPlural String?
|
|
icon String?
|
|
fields String // JSON: field definitions
|
|
listDisplay String? // JSON: columns to show in list
|
|
listFilter String? // JSON: filterable fields
|
|
searchFields String? // JSON: searchable fields
|
|
ordering String? // JSON: default sort order
|
|
validations String? // JSON: validation rules
|
|
hooks String? // JSON: lifecycle hooks (Lua script refs)
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([tenantId, name])
|
|
@@index([tenantId])
|
|
}
|
|
|
|
model DynamicData {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
schemaId String // Reference to ModelSchema
|
|
data String // JSON: actual record data
|
|
createdAt BigInt
|
|
updatedAt BigInt?
|
|
createdBy String?
|
|
updatedBy String?
|
|
|
|
@@index([tenantId, schemaId])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
// =============================================================================
|
|
// APP CONFIGURATION
|
|
// =============================================================================
|
|
|
|
model AppConfiguration {
|
|
id String @id
|
|
name String
|
|
schemas String // JSON
|
|
workflows String // JSON
|
|
luaScripts String // JSON
|
|
pages String // JSON
|
|
theme String // JSON
|
|
}
|
|
|
|
model SystemConfig {
|
|
key String @id
|
|
value String
|
|
}
|
|
|
|
model SMTPConfig {
|
|
id String @id @default("default")
|
|
host String
|
|
port Int
|
|
secure Boolean
|
|
username String
|
|
password String
|
|
fromEmail String
|
|
fromName String
|
|
}
|
|
|
|
// =============================================================================
|
|
// GENERIC KEY-VALUE STORAGE
|
|
// =============================================================================
|
|
|
|
model KeyValue {
|
|
id String @id @default(cuid())
|
|
tenantId String?
|
|
namespace String // Logical grouping: 'settings', 'cache', 'state', 'user_prefs', etc.
|
|
key String
|
|
value String // JSON or plain text
|
|
type String @default("string") // string, json, number, boolean
|
|
expiresAt BigInt? // Optional TTL for cache-like usage
|
|
createdAt BigInt
|
|
updatedAt BigInt?
|
|
|
|
@@unique([tenantId, namespace, key])
|
|
@@index([tenantId])
|
|
@@index([namespace])
|
|
@@index([expiresAt])
|
|
}
|
|
|
|
model UserPreference {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
tenantId String?
|
|
key String // theme, language, notifications_enabled, sidebar_collapsed, etc.
|
|
value String // JSON or plain value
|
|
createdAt BigInt
|
|
updatedAt BigInt?
|
|
|
|
@@unique([userId, tenantId, key])
|
|
@@index([userId])
|
|
@@index([tenantId])
|
|
}
|
|
|
|
model FeatureFlag {
|
|
id String @id @default(cuid())
|
|
tenantId String?
|
|
name String // dark_mode, beta_features, new_editor, etc.
|
|
enabled Boolean @default(false)
|
|
description String?
|
|
rules String? // JSON: targeting rules (user roles, percentages, etc.)
|
|
createdAt BigInt
|
|
updatedAt BigInt?
|
|
|
|
@@unique([tenantId, name])
|
|
@@index([tenantId])
|
|
@@index([enabled])
|
|
}
|
|
|
|
// =============================================================================
|
|
// COMPONENTS & UI
|
|
// =============================================================================
|
|
|
|
model ComponentNode {
|
|
id String @id
|
|
type String
|
|
parentId String?
|
|
childIds String // JSON: string[]
|
|
order Int
|
|
pageId String
|
|
|
|
@@index([pageId])
|
|
@@index([parentId])
|
|
}
|
|
|
|
model ComponentConfig {
|
|
id String @id
|
|
componentId String
|
|
props String // JSON
|
|
styles String // JSON
|
|
events String // JSON
|
|
conditionalRendering String? // JSON
|
|
|
|
@@index([componentId])
|
|
}
|
|
|
|
model CssCategory {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
classes String // JSON: string[]
|
|
}
|
|
|
|
model DropdownConfig {
|
|
id String @id
|
|
name String @unique
|
|
label String
|
|
options String // JSON: Array<{value, label}>
|
|
}
|
|
|
|
// =============================================================================
|
|
// PACKAGES
|
|
// =============================================================================
|
|
|
|
model InstalledPackage {
|
|
packageId String @id
|
|
tenantId String?
|
|
installedAt BigInt
|
|
version String
|
|
enabled Boolean
|
|
config String? // JSON: package-specific configuration
|
|
|
|
@@index([tenantId])
|
|
}
|
|
|
|
model PackageData {
|
|
packageId String @id
|
|
data String // JSON
|
|
}
|
|
|
|
// =============================================================================
|
|
// CONTENT: COMMENTS
|
|
// =============================================================================
|
|
|
|
model Comment {
|
|
id String @id
|
|
tenantId String?
|
|
userId String
|
|
content String
|
|
createdAt BigInt
|
|
updatedAt BigInt?
|
|
parentId String?
|
|
entityType String? // What this comment is on: 'post', 'thread', 'media', etc.
|
|
entityId String? // ID of the entity being commented on
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([tenantId])
|
|
@@index([userId])
|
|
@@index([parentId])
|
|
@@index([entityType, entityId])
|
|
}
|
|
|
|
// =============================================================================
|
|
// CONTENT: FORUM
|
|
// =============================================================================
|
|
|
|
model ForumCategory {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
name String
|
|
description String?
|
|
icon String?
|
|
slug String
|
|
sortOrder Int @default(0)
|
|
parentId String? // For nested categories
|
|
createdAt BigInt
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
threads ForumThread[]
|
|
|
|
@@unique([tenantId, slug])
|
|
@@index([tenantId])
|
|
@@index([parentId])
|
|
}
|
|
|
|
model ForumThread {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
categoryId String
|
|
authorId String
|
|
title String
|
|
content String
|
|
slug String
|
|
isPinned Boolean @default(false)
|
|
isLocked Boolean @default(false)
|
|
viewCount Int @default(0)
|
|
replyCount Int @default(0)
|
|
lastReplyAt BigInt?
|
|
lastReplyBy String?
|
|
createdAt BigInt
|
|
updatedAt BigInt?
|
|
category ForumCategory @relation(fields: [categoryId], references: [id], onDelete: Cascade)
|
|
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
|
|
posts ForumPost[]
|
|
|
|
@@unique([tenantId, slug])
|
|
@@index([tenantId])
|
|
@@index([categoryId])
|
|
@@index([authorId])
|
|
@@index([isPinned, lastReplyAt])
|
|
}
|
|
|
|
model ForumPost {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
threadId String
|
|
authorId String
|
|
content String
|
|
likes Int @default(0)
|
|
isEdited Boolean @default(false)
|
|
createdAt BigInt
|
|
updatedAt BigInt?
|
|
thread ForumThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
|
|
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([tenantId])
|
|
@@index([threadId])
|
|
@@index([authorId])
|
|
}
|
|
|
|
// =============================================================================
|
|
// MEDIA
|
|
// =============================================================================
|
|
|
|
model MediaAsset {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
userId String
|
|
filename String
|
|
originalName String
|
|
mimeType String
|
|
size BigInt
|
|
path String
|
|
thumbnailPath String?
|
|
width Int?
|
|
height Int?
|
|
duration Int? // For video/audio in seconds
|
|
metadata String? // JSON: EXIF, tags, etc.
|
|
createdAt BigInt
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([tenantId])
|
|
@@index([userId])
|
|
@@index([mimeType])
|
|
}
|
|
|
|
model MediaJob {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
userId String
|
|
type String // transcode, thumbnail, convert, etc.
|
|
status String // pending, processing, completed, failed
|
|
priority Int @default(0)
|
|
inputPath String
|
|
outputPath String?
|
|
params String // JSON: job-specific parameters
|
|
progress Int @default(0)
|
|
error String?
|
|
startedAt BigInt?
|
|
completedAt BigInt?
|
|
createdAt BigInt
|
|
|
|
@@index([tenantId])
|
|
@@index([status, priority])
|
|
@@index([userId])
|
|
}
|
|
|
|
// =============================================================================
|
|
// NOTIFICATIONS
|
|
// =============================================================================
|
|
|
|
model Notification {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
userId String
|
|
type String // info, warning, success, error, mention, reply, etc.
|
|
title String
|
|
message String
|
|
icon String?
|
|
read Boolean @default(false)
|
|
data String? // JSON: action URLs, entity references, etc.
|
|
createdAt BigInt
|
|
expiresAt BigInt?
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([tenantId])
|
|
@@index([userId, read])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
// =============================================================================
|
|
// AUDIT & LOGGING
|
|
// =============================================================================
|
|
|
|
model AuditLog {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
userId String?
|
|
username String?
|
|
action String // create, update, delete, login, logout, etc.
|
|
entity String // User, Workflow, Page, etc.
|
|
entityId String?
|
|
oldValue String? // JSON: previous state
|
|
newValue String? // JSON: new state
|
|
ipAddress String?
|
|
userAgent String?
|
|
details String? // JSON: additional context
|
|
timestamp BigInt
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
|
|
|
@@index([tenantId])
|
|
@@index([userId])
|
|
@@index([entity, entityId])
|
|
@@index([action])
|
|
@@index([timestamp])
|
|
}
|
|
|
|
model ErrorLog {
|
|
id String @id @default(cuid())
|
|
timestamp BigInt
|
|
level String // error, warning, info
|
|
message String
|
|
stack String?
|
|
context String? // JSON: additional context
|
|
userId String?
|
|
username String?
|
|
tenantId String?
|
|
source String? // Component/file where error occurred
|
|
resolved Boolean @default(false)
|
|
resolvedAt BigInt?
|
|
resolvedBy String?
|
|
|
|
@@index([tenantId])
|
|
@@index([level])
|
|
@@index([timestamp])
|
|
@@index([resolved])
|
|
}
|
|
|
|
// =============================================================================
|
|
// AUTH TOKENS & SECURITY
|
|
// =============================================================================
|
|
|
|
model PasswordResetToken {
|
|
username String @id
|
|
token String
|
|
expiresAt BigInt?
|
|
createdAt BigInt?
|
|
}
|
|
|
|
model PowerTransferRequest {
|
|
id String @id
|
|
fromUserId String
|
|
toUserId String
|
|
status String // pending, accepted, rejected
|
|
createdAt BigInt
|
|
expiresAt BigInt
|
|
fromUser User @relation("PowerTransferFrom", fields: [fromUserId], references: [id], onDelete: Cascade)
|
|
toUser User @relation("PowerTransferTo", fields: [toUserId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([status])
|
|
@@index([expiresAt])
|
|
}
|
|
|
|
// =============================================================================
|
|
// GENERIC ENTITIES FOR PACKAGES
|
|
// =============================================================================
|
|
|
|
// Tags - Attach labels to any entity (posts, media, threads, etc.)
|
|
model Tag {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
name String
|
|
slug String
|
|
color String? // Hex color for UI
|
|
icon String?
|
|
category String? // Group tags: 'topic', 'status', 'priority', etc.
|
|
createdAt BigInt
|
|
|
|
@@unique([tenantId, slug])
|
|
@@index([tenantId])
|
|
@@index([category])
|
|
}
|
|
|
|
// Tagging - Many-to-many junction for tags on any entity
|
|
model Tagging {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
tagId String
|
|
entityType String // 'post', 'media', 'thread', 'user', etc.
|
|
entityId String
|
|
createdAt BigInt
|
|
createdBy String?
|
|
|
|
@@unique([tagId, entityType, entityId])
|
|
@@index([tenantId])
|
|
@@index([tagId])
|
|
@@index([entityType, entityId])
|
|
}
|
|
|
|
// Relationships - Generic many-to-many between any entities
|
|
model EntityRelation {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
sourceType String // 'user', 'post', 'product', etc.
|
|
sourceId String
|
|
targetType String
|
|
targetId String
|
|
relationType String // 'follows', 'blocks', 'related_to', 'parent_of', etc.
|
|
metadata String? // JSON: additional relation data
|
|
createdAt BigInt
|
|
createdBy String?
|
|
|
|
@@unique([sourceType, sourceId, targetType, targetId, relationType])
|
|
@@index([tenantId])
|
|
@@index([sourceType, sourceId])
|
|
@@index([targetType, targetId])
|
|
@@index([relationType])
|
|
}
|
|
|
|
// Generic Task Queue - Background jobs for any package
|
|
model Task {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
queue String // 'email', 'export', 'import', 'cleanup', etc.
|
|
type String // Specific task type within queue
|
|
status String @default("pending") // pending, running, completed, failed, cancelled
|
|
priority Int @default(0)
|
|
payload String // JSON: task input data
|
|
result String? // JSON: task output/result
|
|
error String?
|
|
attempts Int @default(0)
|
|
maxAttempts Int @default(3)
|
|
runAt BigInt? // Scheduled execution time
|
|
startedAt BigInt?
|
|
completedAt BigInt?
|
|
createdAt BigInt
|
|
createdBy String?
|
|
|
|
@@index([tenantId])
|
|
@@index([queue, status])
|
|
@@index([status, priority])
|
|
@@index([runAt])
|
|
}
|
|
|
|
// Webhooks - Outbound event notifications
|
|
model Webhook {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
name String
|
|
url String
|
|
secret String? // For HMAC signing
|
|
events String // JSON: array of event types to trigger on
|
|
headers String? // JSON: custom headers to include
|
|
enabled Boolean @default(true)
|
|
lastTriggered BigInt?
|
|
failCount Int @default(0)
|
|
createdAt BigInt
|
|
updatedAt BigInt?
|
|
|
|
@@index([tenantId])
|
|
@@index([enabled])
|
|
}
|
|
|
|
// Webhook Deliveries - Log of webhook attempts
|
|
model WebhookDelivery {
|
|
id String @id @default(cuid())
|
|
webhookId String
|
|
event String
|
|
payload String // JSON: what was sent
|
|
response String? // JSON: response received
|
|
statusCode Int?
|
|
success Boolean
|
|
duration Int? // ms
|
|
error String?
|
|
createdAt BigInt
|
|
|
|
@@index([webhookId])
|
|
@@index([createdAt])
|
|
@@index([success])
|
|
}
|
|
|
|
// Attachments - Generic file attachments to any entity
|
|
model Attachment {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
entityType String // 'comment', 'post', 'message', etc.
|
|
entityId String
|
|
filename String
|
|
originalName String
|
|
mimeType String
|
|
size BigInt
|
|
path String
|
|
metadata String? // JSON: dimensions, duration, etc.
|
|
sortOrder Int @default(0)
|
|
createdAt BigInt
|
|
createdBy String?
|
|
|
|
@@index([tenantId])
|
|
@@index([entityType, entityId])
|
|
}
|
|
|
|
// Reactions - Likes, emoji reactions on any entity
|
|
model Reaction {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
userId String
|
|
entityType String // 'post', 'comment', 'media', etc.
|
|
entityId String
|
|
type String // 'like', 'love', 'laugh', 'wow', 'sad', 'angry', '+1', etc.
|
|
createdAt BigInt
|
|
|
|
@@unique([userId, entityType, entityId, type])
|
|
@@index([tenantId])
|
|
@@index([entityType, entityId])
|
|
@@index([userId])
|
|
}
|
|
|
|
// Bookmarks/Favorites - Users saving any entity
|
|
model Bookmark {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
userId String
|
|
entityType String // 'post', 'thread', 'media', 'product', etc.
|
|
entityId String
|
|
folder String? // Optional folder/collection
|
|
note String? // User's note about the bookmark
|
|
createdAt BigInt
|
|
|
|
@@unique([userId, entityType, entityId])
|
|
@@index([tenantId])
|
|
@@index([userId])
|
|
@@index([entityType, entityId])
|
|
@@index([folder])
|
|
}
|
|
|
|
// Activity Feed - Timeline events
|
|
model Activity {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
userId String?
|
|
action String // 'created', 'updated', 'deleted', 'shared', 'mentioned', etc.
|
|
entityType String
|
|
entityId String
|
|
targetType String? // Secondary entity (e.g., 'user' mentioned in 'post')
|
|
targetId String?
|
|
metadata String? // JSON: extra context
|
|
isPublic Boolean @default(true)
|
|
createdAt BigInt
|
|
|
|
@@index([tenantId])
|
|
@@index([userId])
|
|
@@index([entityType, entityId])
|
|
@@index([createdAt])
|
|
@@index([isPublic, createdAt])
|
|
}
|
|
|
|
// Counters - Denormalized counts for any entity
|
|
model Counter {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
entityType String
|
|
entityId String
|
|
name String // 'views', 'likes', 'shares', 'downloads', etc.
|
|
value BigInt @default(0)
|
|
updatedAt BigInt
|
|
|
|
@@unique([entityType, entityId, name])
|
|
@@index([tenantId])
|
|
@@index([entityType, entityId])
|
|
}
|
|
|
|
// Versions - Version history for any entity
|
|
model Version {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
entityType String
|
|
entityId String
|
|
version Int
|
|
data String // JSON: snapshot of entity state
|
|
changes String? // JSON: diff from previous version
|
|
message String? // Commit message
|
|
createdAt BigInt
|
|
createdBy String?
|
|
|
|
@@unique([entityType, entityId, version])
|
|
@@index([tenantId])
|
|
@@index([entityType, entityId])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
// Templates - Reusable content templates
|
|
model Template {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
name String
|
|
description String?
|
|
category String // 'email', 'page', 'component', 'workflow', etc.
|
|
content String // JSON or template string
|
|
variables String? // JSON: list of variable placeholders
|
|
isPublic Boolean @default(false)
|
|
createdAt BigInt
|
|
updatedAt BigInt?
|
|
createdBy String?
|
|
|
|
@@unique([tenantId, category, name])
|
|
@@index([tenantId])
|
|
@@index([category])
|
|
@@index([isPublic])
|
|
}
|
|
|
|
// Scheduled Jobs - Cron-like recurring tasks
|
|
model ScheduledJob {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
name String
|
|
description String?
|
|
schedule String // Cron expression: "0 0 * * *"
|
|
taskType String // What to run
|
|
taskPayload String // JSON: parameters
|
|
enabled Boolean @default(true)
|
|
lastRunAt BigInt?
|
|
nextRunAt BigInt?
|
|
lastStatus String? // success, failed
|
|
lastError String?
|
|
runCount Int @default(0)
|
|
createdAt BigInt
|
|
updatedAt BigInt?
|
|
|
|
@@index([tenantId])
|
|
@@index([enabled, nextRunAt])
|
|
}
|
|
|
|
// Locks - Distributed locking for concurrency control
|
|
model Lock {
|
|
id String @id @default(cuid())
|
|
tenantId String?
|
|
resource String // What's being locked
|
|
owner String // Who holds the lock (session ID, worker ID, etc.)
|
|
expiresAt BigInt
|
|
acquiredAt BigInt
|
|
metadata String? // JSON: additional context
|
|
|
|
@@unique([tenantId, resource])
|
|
@@index([expiresAt])
|
|
}
|
|
|
|
// Messages - Generic messaging/inbox system
|
|
model Message {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
senderId String?
|
|
recipientId String
|
|
threadId String? // For threaded conversations
|
|
subject String?
|
|
body String
|
|
isRead Boolean @default(false)
|
|
isArchived Boolean @default(false)
|
|
isDeleted Boolean @default(false)
|
|
metadata String? // JSON: attachments, flags, etc.
|
|
createdAt BigInt
|
|
readAt BigInt?
|
|
|
|
@@index([tenantId])
|
|
@@index([recipientId, isRead])
|
|
@@index([senderId])
|
|
@@index([threadId])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
// Invitations - Generic invite system
|
|
model Invitation {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
type String // 'team', 'project', 'event', etc.
|
|
targetId String? // What they're being invited to
|
|
email String
|
|
token String @unique
|
|
role String? // Role to assign on acceptance
|
|
invitedBy String
|
|
status String @default("pending") // pending, accepted, declined, expired
|
|
expiresAt BigInt
|
|
acceptedAt BigInt?
|
|
createdAt BigInt
|
|
|
|
@@index([tenantId])
|
|
@@index([email])
|
|
@@index([token])
|
|
@@index([status])
|
|
}
|