Files
metabuilder/prisma/schema.prisma
2025-12-30 21:26:54 +00:00

1652 lines
50 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])
}
// =============================================================================
// GITHUB INTEGRATION (github_tools package)
// =============================================================================
model GitHubRepository {
id String @id @default(cuid())
tenantId String
owner String
name String
fullName String // "owner/repo"
url String
cloneUrl String?
description String?
isPrivate Boolean @default(false)
defaultBranch String?
language String?
starCount Int @default(0)
forkCount Int @default(0)
openIssues Int @default(0)
license String?
topics String? // JSON: array of topics
lastSync BigInt?
syncError String?
enabled Boolean @default(true)
metadata String? // JSON: additional GitHub data
createdAt BigInt
updatedAt BigInt?
actions GitHubAction[]
workflows GitHubWorkflow[]
@@unique([tenantId, fullName])
@@index([tenantId])
@@index([owner])
}
model GitHubWorkflow {
id String @id @default(cuid())
repositoryId String
name String
path String
state String // active, deleted, disabled_fork, etc.
badge String? // Badge URL
createdAt BigInt
updatedAt BigInt?
repository GitHubRepository @relation(fields: [repositoryId], references: [id], onDelete: Cascade)
@@unique([repositoryId, path])
@@index([repositoryId])
}
model GitHubAction {
id String @id @default(cuid())
repositoryId String
workflowId String?
workflowName String
runId BigInt
runNumber Int
event String // push, pull_request, schedule, etc.
status String // queued, in_progress, completed
conclusion String? // success, failure, cancelled, skipped
branch String?
commitSha String?
commitMsg String?
actor String? // Who triggered it
url String
logsUrl String?
triggeredAt BigInt?
startedAt BigInt?
completedAt BigInt?
duration Int? // seconds
createdAt BigInt
repository GitHubRepository @relation(fields: [repositoryId], references: [id], onDelete: Cascade)
@@unique([repositoryId, runId])
@@index([repositoryId])
@@index([status])
@@index([conclusion])
@@index([completedAt])
}
model GitHubIssue {
id String @id @default(cuid())
repositoryId String
issueNumber Int
title String
body String?
state String // open, closed
author String
labels String? // JSON array
assignees String? // JSON array
milestone String?
comments Int @default(0)
locked Boolean @default(false)
url String
createdAt BigInt
updatedAt BigInt?
closedAt BigInt?
@@unique([repositoryId, issueNumber])
@@index([repositoryId])
@@index([state])
}
// =============================================================================
// GAMING & ARCADE (arcade_lobby package)
// =============================================================================
model Game {
id String @id @default(cuid())
tenantId String
name String
slug String
description String?
thumbnail String?
bannerImage String?
category String // platformer, puzzle, arcade, shooter, rpg, etc.
platform String // retroarch, web, native, etc.
core String? // RetroArch core name (snes9x, genesis_plus_gx, etc.)
romPath String?
romHash String? // SHA256 for integrity
saveDataPath String?
configPath String?
controls String? // JSON: button mappings
cheats String? // JSON: cheat codes
achievements String? // JSON: achievement definitions
metadata String? // JSON: developer, release year, genre tags, etc.
rating String? // E, T, M, etc.
players String @default("1") // "1", "1-2", "1-4", etc.
enabled Boolean @default(true)
featured Boolean @default(false)
playCount Int @default(0)
favoriteCount Int @default(0)
avgRating Float?
createdAt BigInt
updatedAt BigInt?
sessions GameSession[]
highScores GameHighScore[]
saves GameSave[]
reviews GameReview[]
@@unique([tenantId, slug])
@@index([tenantId])
@@index([category])
@@index([platform])
@@index([featured, playCount])
}
model GameSession {
id String @id @default(cuid())
gameId String
userId String
startedAt BigInt
endedAt BigInt?
duration Int? // seconds
saveStateId String? // Reference to GameSave
score BigInt?
level Int?
achievements String? // JSON: array of unlocked achievement IDs
stats String? // JSON: game-specific stats
metadata String? // JSON: controller used, settings, etc.
game Game @relation(fields: [gameId], references: [id], onDelete: Cascade)
@@index([gameId])
@@index([userId])
@@index([startedAt])
}
model GameHighScore {
id String @id @default(cuid())
gameId String
userId String
username String
score BigInt
rank Int?
level Int?
character String? // For games with character selection
mode String? // difficulty, speedrun, etc.
verified Boolean @default(false)
replay String? // Path to replay file
metadata String? // JSON: additional context
createdAt BigInt
game Game @relation(fields: [gameId], references: [id], onDelete: Cascade)
@@index([gameId, score])
@@index([gameId, rank])
@@index([userId])
}
model GameSave {
id String @id @default(cuid())
gameId String
userId String
name String // User-provided name
slot Int @default(0)
filePath String
screenshot String? // Thumbnail of save state
level Int?
progress Float? // Percentage completion
playTime Int? // seconds
isAuto Boolean @default(false)
metadata String? // JSON: location, items, etc.
createdAt BigInt
game Game @relation(fields: [gameId], references: [id], onDelete: Cascade)
@@unique([gameId, userId, slot])
@@index([gameId, userId])
@@index([createdAt])
}
model GameReview {
id String @id @default(cuid())
gameId String
userId String
username String
rating Int // 1-5 stars
title String?
review String?
helpful Int @default(0)
notHelpful Int @default(0)
verified Boolean @default(false) // Did they actually play it?
createdAt BigInt
updatedAt BigInt?
game Game @relation(fields: [gameId], references: [id], onDelete: Cascade)
@@unique([gameId, userId])
@@index([gameId])
@@index([rating])
}
// =============================================================================
// CSS DESIGNER & THEMING (css_designer package)
// =============================================================================
model CSSTheme {
id String @id @default(cuid())
tenantId String
name String
slug String
description String?
author String?
version String @default("1.0.0")
baseTheme String? // Parent theme to extend
variables String // JSON: CSS custom properties { "--color-primary": "#ff0000" }
typography String? // JSON: font families, sizes, weights
colors String? // JSON: color palette definitions
spacing String? // JSON: spacing scale
borders String? // JSON: border radius, widths
shadows String? // JSON: box shadow definitions
components String? // JSON: component-specific overrides
animations String? // JSON: transition/animation settings
breakpoints String? // JSON: responsive breakpoints
isDefault Boolean @default(false)
isPublic Boolean @default(false)
isDark Boolean @default(false)
tags String? // JSON: array of tags
preview String? // Preview image URL
downloads Int @default(0)
rating Float?
createdAt BigInt
updatedAt BigInt?
createdBy String?
@@unique([tenantId, slug])
@@index([tenantId])
@@index([isPublic, isDefault])
@@index([isDark])
}
model CSSVariable {
id String @id @default(cuid())
themeId String?
category String // color, spacing, typography, etc.
name String // --color-primary
value String // #1976d2
description String?
fallback String? // Default value if theme not loaded
scope String @default("global") // global, component-specific
createdAt BigInt
@@unique([themeId, name])
@@index([category])
@@index([scope])
}
// =============================================================================
// DASHBOARD & WIDGETS (dashboard package)
// =============================================================================
model Dashboard {
id String @id @default(cuid())
tenantId String
userId String?
name String
slug String
description String?
layout String // JSON: grid layout config
isDefault Boolean @default(false)
isShared Boolean @default(false)
isPublic Boolean @default(false)
permissions String? // JSON: who can view/edit
refreshRate Int? // seconds
createdAt BigInt
updatedAt BigInt?
widgets DashboardWidget[]
@@unique([tenantId, slug])
@@index([tenantId])
@@index([userId])
@@index([isPublic])
}
model DashboardWidget {
id String @id @default(cuid())
dashboardId String
type String // chart, stats, list, calendar, table, iframe, custom
title String
subtitle String?
dataSource String // JSON: query/API config
chartType String? // line, bar, pie, donut, area, etc.
config String // JSON: widget-specific configuration
position String // JSON: {x, y, w, h} grid position
minSize String? // JSON: {w, h} minimum dimensions
maxSize String? // JSON: {w, h} maximum dimensions
refreshRate Int? // seconds, null = no auto-refresh
permissions String? // JSON: role-based visibility
sortOrder Int @default(0)
enabled Boolean @default(true)
createdAt BigInt
updatedAt BigInt?
dashboard Dashboard @relation(fields: [dashboardId], references: [id], onDelete: Cascade)
@@index([dashboardId])
@@index([type])
}
model WidgetDataCache {
id String @id @default(cuid())
widgetId String
data String // JSON: cached data
expiresAt BigInt
cachedAt BigInt
cacheKey String
@@unique([widgetId, cacheKey])
@@index([expiresAt])
}
// =============================================================================
// GUIDES & DOCUMENTATION (quick_guide package)
// =============================================================================
model Guide {
id String @id @default(cuid())
tenantId String
title String
slug String
description String?
content String // Markdown content
category String? // getting-started, tutorials, reference, api
difficulty String? // beginner, intermediate, advanced
estimatedTime Int? // minutes
tags String? // JSON array
icon String?
author String?
isPublished Boolean @default(true)
isFeatured Boolean @default(false)
order Int @default(0)
version String @default("1.0.0")
views Int @default(0)
likes Int @default(0)
createdAt BigInt
updatedAt BigInt?
publishedAt BigInt?
createdBy String?
steps GuideStep[]
@@unique([tenantId, slug])
@@index([tenantId])
@@index([category])
@@index([isPublished, isFeatured])
}
model GuideStep {
id String @id @default(cuid())
guideId String
title String
content String // Markdown
order Int
actionType String? // click, input, navigate, wait, run, etc.
actionData String? // JSON: element selector, value, etc.
validation String? // JSON: success criteria
hints String? // JSON: array of hints
screenshot String? // Path to screenshot
videoUrl String?
createdAt BigInt
guide Guide @relation(fields: [guideId], references: [id], onDelete: Cascade)
@@index([guideId, order])
}
model GuideProgress {
id String @id @default(cuid())
guideId String
userId String
completedSteps String // JSON: array of step IDs
progress Float @default(0) // 0-100
startedAt BigInt
lastViewedAt BigInt
completedAt BigInt?
@@unique([guideId, userId])
@@index([userId])
@@index([guideId])
}
// =============================================================================
// ANALYTICS & METRICS (for all packages)
// =============================================================================
model Metric {
id String @id @default(cuid())
tenantId String
namespace String // package name or feature area
name String // metric name (page_views, api_calls, etc.)
value Float
unit String? // ms, bytes, count, etc.
dimensions String? // JSON: tags/dimensions
timestamp BigInt
@@index([tenantId, namespace, name])
@@index([timestamp])
}
model Event {
id String @id @default(cuid())
tenantId String
userId String?
category String // user_action, system, error, etc.
action String // click, view, create, delete, etc.
label String?
value Float?
properties String? // JSON: additional event data
sessionId String?
url String?
referrer String?
device String? // desktop, mobile, tablet
os String?
browser String?
timestamp BigInt
@@index([tenantId, category, action])
@@index([userId])
@@index([timestamp])
}
// =============================================================================
// IRC & CHAT (irc_webchat package)
// =============================================================================
model IRCChannel {
id String @id @default(cuid())
tenantId String
name String // #general, #help, etc.
topic String?
description String?
mode String @default("public") // public, private, secret
password String? // For private channels
maxUsers Int?
slowMode Int? // Seconds between messages
isDefault Boolean @default(false)
createdAt BigInt
createdBy String?
messages IRCMessage[]
memberships IRCMembership[]
@@unique([tenantId, name])
@@index([tenantId])
@@index([isDefault])
}
model IRCMessage {
id String @id @default(cuid())
tenantId String
channelId String
userId String
username String
type String @default("message") // message, action, notice, system
content String
isCommand Boolean @default(false)
metadata String? // JSON: mentions, links, etc.
createdAt BigInt
channel IRCChannel @relation(fields: [channelId], references: [id], onDelete: Cascade)
@@index([channelId])
@@index([userId])
@@index([createdAt])
}
model IRCMembership {
id String @id @default(cuid())
channelId String
userId String
username String
role String @default("user") // user, voice, halfop, op, admin, owner
joinedAt BigInt
lastActive BigInt?
isBanned Boolean @default(false)
isKicked Boolean @default(false)
kickReason String?
metadata String? // JSON: user preferences
channel IRCChannel @relation(fields: [channelId], references: [id], onDelete: Cascade)
@@unique([channelId, userId])
@@index([userId])
}
// =============================================================================
// STREAMING (stream_cast package)
// =============================================================================
model StreamChannel {
id String @id @default(cuid())
tenantId String
name String
slug String
description String?
thumbnail String?
category String? // gaming, music, talk, art, etc.
status String @default("offline") // offline, live, scheduled
viewerCount Int @default(0)
streamKey String? @unique
rtmpUrl String?
hlsUrl String?
chatEnabled Boolean @default(true)
isPublic Boolean @default(true)
isMature Boolean @default(false)
metadata String? // JSON: bitrate, resolution, etc.
createdAt BigInt
updatedAt BigInt?
createdBy String
schedules StreamSchedule[]
scenes StreamScene[]
@@unique([tenantId, slug])
@@index([tenantId])
@@index([status])
@@index([category])
}
model StreamSchedule {
id String @id @default(cuid())
channelId String
title String
description String?
startTime BigInt
endTime BigInt?
duration Int? // minutes
isRecurring Boolean @default(false)
recurrence String? // JSON: cron/rrule
notifyAt BigInt?
metadata String? // JSON: guests, topics, etc.
createdAt BigInt
channel StreamChannel @relation(fields: [channelId], references: [id], onDelete: Cascade)
@@index([channelId])
@@index([startTime])
}
model StreamScene {
id String @id @default(cuid())
channelId String
name String
layout String // JSON: scene composition
sources String // JSON: cameras, screens, overlays
transitions String? // JSON: scene transitions
isActive Boolean @default(false)
sortOrder Int @default(0)
createdAt BigInt
channel StreamChannel @relation(fields: [channelId], references: [id], onDelete: Cascade)
@@index([channelId])
@@index([isActive])
}
// =============================================================================
// CODEGEN STUDIO (codegen_studio package)
// =============================================================================
model CodegenProject {
id String @id @default(cuid())
tenantId String
name String
slug String
description String?
language String // typescript, lua, python, etc.
framework String? // react, qt, fastapi, etc.
config String // JSON: project configuration
output String? // Generated code output path
status String @default("draft") // draft, generating, complete, error
lastGenAt BigInt?
error String?
createdAt BigInt
updatedAt BigInt?
createdBy String
blueprints CodegenBlueprint[]
templates CodegenTemplate[]
@@unique([tenantId, slug])
@@index([tenantId])
@@index([status])
}
model CodegenBlueprint {
id String @id @default(cuid())
projectId String
name String
type String // model, api, component, service, etc.
schema String // JSON: blueprint definition
depends String? // JSON: dependencies on other blueprints
output String? // JSON: generated artifacts
validated Boolean @default(false)
createdAt BigInt
updatedAt BigInt?
project CodegenProject @relation(fields: [projectId], references: [id], onDelete: Cascade)
@@unique([projectId, name])
@@index([projectId])
@@index([type])
}
model CodegenTemplate {
id String @id @default(cuid())
projectId String? // null for global templates
tenantId String?
name String
language String
type String // model, api, component, test, etc.
template String // Template content with placeholders
variables String? // JSON: variable definitions
isBuiltin Boolean @default(false)
createdAt BigInt
updatedAt BigInt?
project CodegenProject? @relation(fields: [projectId], references: [id], onDelete: Cascade)
@@unique([projectId, name])
@@index([tenantId])
@@index([language, type])
}
// =============================================================================
// API & INTEGRATIONS
// =============================================================================
model APIKey {
id String @id @default(cuid())
tenantId String
name String
description String?
key String @unique
secret String?
permissions String // JSON: array of scopes
rateLimit Int? // requests per minute
ipWhitelist String? // JSON: array of allowed IPs
enabled Boolean @default(true)
lastUsedAt BigInt?
expiresAt BigInt?
createdAt BigInt
createdBy String?
@@index([tenantId])
@@index([key])
@@index([enabled])
}
model OAuthToken {
id String @id @default(cuid())
userId String
provider String // github, google, etc.
accessToken String
refreshToken String?
tokenType String @default("Bearer")
scope String?
expiresAt BigInt?
metadata String? // JSON: provider-specific data
createdAt BigInt
updatedAt BigInt?
@@unique([userId, provider])
@@index([provider])
@@index([expiresAt])
}
// =============================================================================
// SEARCH & INDEXING
// =============================================================================
model SearchIndex {
id String @id @default(cuid())
tenantId String
entityType String
entityId String
title String
content String // Searchable text content
metadata String? // JSON: additional indexed fields
boost Float @default(1.0)
updatedAt BigInt
@@unique([entityType, entityId])
@@index([tenantId])
@@index([entityType])
}
// =============================================================================
// FEATURE FLAGS (Enhanced)
// =============================================================================
model FeatureFlagOverride {
id String @id @default(cuid())
flagId String
targetType String // user, role, tenant
targetId String
enabled Boolean
createdAt BigInt
@@unique([flagId, targetType, targetId])
@@index([flagId])
}
// =============================================================================
// PACKAGE ENHANCEMENTS
// =============================================================================
model PackagePermission {
id String @id @default(cuid())
packageId String
tenantId String?
userId String?
role String?
permission String // read, write, execute, admin
resource String? // Specific resource within package
granted Boolean @default(true)
createdAt BigInt
@@unique([packageId, tenantId, userId, permission, resource])
@@index([packageId])
@@index([tenantId])
}