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]) }