- Added EntryVersion model with author relation - Implemented automatic versioning on entry create/update - Added API endpoints for version history: - GET /api/knowledge/entries/:slug/versions - list versions - GET /api/knowledge/entries/:slug/versions/:version - get specific - POST /api/knowledge/entries/:slug/restore/:version - restore version - Created VersionHistory.tsx component with timeline view - Added History tab to entry detail page - Supports version viewing and restoring - Includes comprehensive tests for version operations - All TypeScript types are explicit and type-safe
842 lines
26 KiB
Plaintext
842 lines
26 KiB
Plaintext
// Mosaic Stack Database Schema
|
|
// PostgreSQL 17 with pgvector extension
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
previewFeatures = ["postgresqlExtensions"]
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
extensions = [pgvector(map: "vector"), uuid_ossp(map: "uuid-ossp")]
|
|
}
|
|
|
|
// ============================================
|
|
// ENUMS
|
|
// ============================================
|
|
|
|
enum TaskStatus {
|
|
NOT_STARTED
|
|
IN_PROGRESS
|
|
PAUSED
|
|
COMPLETED
|
|
ARCHIVED
|
|
}
|
|
|
|
enum TaskPriority {
|
|
LOW
|
|
MEDIUM
|
|
HIGH
|
|
}
|
|
|
|
enum ProjectStatus {
|
|
PLANNING
|
|
ACTIVE
|
|
PAUSED
|
|
COMPLETED
|
|
ARCHIVED
|
|
}
|
|
|
|
enum WorkspaceMemberRole {
|
|
OWNER
|
|
ADMIN
|
|
MEMBER
|
|
GUEST
|
|
}
|
|
|
|
enum TeamMemberRole {
|
|
OWNER
|
|
ADMIN
|
|
MEMBER
|
|
}
|
|
|
|
enum ActivityAction {
|
|
CREATED
|
|
UPDATED
|
|
DELETED
|
|
COMPLETED
|
|
ASSIGNED
|
|
COMMENTED
|
|
LOGIN
|
|
LOGOUT
|
|
PASSWORD_RESET
|
|
EMAIL_VERIFIED
|
|
}
|
|
|
|
enum EntityType {
|
|
TASK
|
|
EVENT
|
|
PROJECT
|
|
WORKSPACE
|
|
USER
|
|
IDEA
|
|
DOMAIN
|
|
}
|
|
|
|
enum IdeaStatus {
|
|
CAPTURED
|
|
PROCESSING
|
|
ACTIONABLE
|
|
ARCHIVED
|
|
DISCARDED
|
|
}
|
|
|
|
enum RelationshipType {
|
|
BLOCKS
|
|
BLOCKED_BY
|
|
DEPENDS_ON
|
|
PARENT_OF
|
|
CHILD_OF
|
|
RELATED_TO
|
|
DUPLICATE_OF
|
|
SUPERSEDES
|
|
PART_OF
|
|
}
|
|
|
|
enum AgentStatus {
|
|
IDLE
|
|
WORKING
|
|
WAITING
|
|
ERROR
|
|
TERMINATED
|
|
}
|
|
|
|
enum EntryStatus {
|
|
DRAFT
|
|
PUBLISHED
|
|
ARCHIVED
|
|
}
|
|
|
|
enum Visibility {
|
|
PRIVATE
|
|
WORKSPACE
|
|
PUBLIC
|
|
}
|
|
|
|
// ============================================
|
|
// MODELS
|
|
// ============================================
|
|
|
|
model User {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
email String @unique
|
|
name String
|
|
emailVerified Boolean @default(false) @map("email_verified")
|
|
image String?
|
|
authProviderId String? @unique @map("auth_provider_id")
|
|
preferences Json @default("{}")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
ownedWorkspaces Workspace[] @relation("WorkspaceOwner")
|
|
workspaceMemberships WorkspaceMember[]
|
|
teamMemberships TeamMember[]
|
|
assignedTasks Task[] @relation("TaskAssignee")
|
|
createdTasks Task[] @relation("TaskCreator")
|
|
createdEvents Event[] @relation("EventCreator")
|
|
createdProjects Project[] @relation("ProjectCreator")
|
|
activityLogs ActivityLog[]
|
|
sessions Session[]
|
|
accounts Account[]
|
|
ideas Idea[] @relation("IdeaCreator")
|
|
relationships Relationship[] @relation("RelationshipCreator")
|
|
agentSessions AgentSession[]
|
|
userLayouts UserLayout[]
|
|
userPreference UserPreference?
|
|
knowledgeEntryVersions KnowledgeEntryVersion[] @relation("EntryVersionAuthor")
|
|
|
|
@@map("users")
|
|
}
|
|
|
|
model UserPreference {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
userId String @unique @map("user_id") @db.Uuid
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
theme String @default("system")
|
|
locale String @default("en")
|
|
timezone String?
|
|
settings Json @default("{}")
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
@@map("user_preferences")
|
|
}
|
|
|
|
model Workspace {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
name String
|
|
ownerId String @map("owner_id") @db.Uuid
|
|
settings Json @default("{}")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
owner User @relation("WorkspaceOwner", fields: [ownerId], references: [id], onDelete: Cascade)
|
|
members WorkspaceMember[]
|
|
teams Team[]
|
|
tasks Task[]
|
|
events Event[]
|
|
projects Project[]
|
|
activityLogs ActivityLog[]
|
|
memoryEmbeddings MemoryEmbedding[]
|
|
domains Domain[]
|
|
ideas Idea[]
|
|
relationships Relationship[]
|
|
agents Agent[]
|
|
agentSessions AgentSession[]
|
|
userLayouts UserLayout[]
|
|
knowledgeEntries KnowledgeEntry[]
|
|
knowledgeTags KnowledgeTag[]
|
|
cronSchedules CronSchedule[]
|
|
|
|
@@index([ownerId])
|
|
@@map("workspaces")
|
|
}
|
|
|
|
model WorkspaceMember {
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
role WorkspaceMemberRole @default(MEMBER)
|
|
joinedAt DateTime @default(now()) @map("joined_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([workspaceId, userId])
|
|
@@index([userId])
|
|
@@map("workspace_members")
|
|
}
|
|
|
|
model Team {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
name String
|
|
description String? @db.Text
|
|
metadata Json @default("{}")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
members TeamMember[]
|
|
|
|
@@index([workspaceId])
|
|
@@map("teams")
|
|
}
|
|
|
|
model TeamMember {
|
|
teamId String @map("team_id") @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
role TeamMemberRole @default(MEMBER)
|
|
joinedAt DateTime @default(now()) @map("joined_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
team Team @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([teamId, userId])
|
|
@@index([userId])
|
|
@@map("team_members")
|
|
}
|
|
|
|
model Task {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
title String
|
|
description String? @db.Text
|
|
status TaskStatus @default(NOT_STARTED)
|
|
priority TaskPriority @default(MEDIUM)
|
|
dueDate DateTime? @map("due_date") @db.Timestamptz
|
|
assigneeId String? @map("assignee_id") @db.Uuid
|
|
creatorId String @map("creator_id") @db.Uuid
|
|
projectId String? @map("project_id") @db.Uuid
|
|
parentId String? @map("parent_id") @db.Uuid
|
|
domainId String? @map("domain_id") @db.Uuid
|
|
sortOrder Int @default(0) @map("sort_order")
|
|
metadata Json @default("{}")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
completedAt DateTime? @map("completed_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
assignee User? @relation("TaskAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
|
|
creator User @relation("TaskCreator", fields: [creatorId], references: [id], onDelete: Cascade)
|
|
project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull)
|
|
parent Task? @relation("TaskSubtasks", fields: [parentId], references: [id], onDelete: Cascade)
|
|
subtasks Task[] @relation("TaskSubtasks")
|
|
domain Domain? @relation(fields: [domainId], references: [id], onDelete: SetNull)
|
|
|
|
@@unique([id, workspaceId])
|
|
@@index([workspaceId])
|
|
@@index([workspaceId, status])
|
|
@@index([workspaceId, dueDate])
|
|
@@index([assigneeId])
|
|
@@index([projectId])
|
|
@@index([parentId])
|
|
@@index([domainId])
|
|
@@map("tasks")
|
|
}
|
|
|
|
model Event {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
title String
|
|
description String? @db.Text
|
|
startTime DateTime @map("start_time") @db.Timestamptz
|
|
endTime DateTime? @map("end_time") @db.Timestamptz
|
|
allDay Boolean @default(false) @map("all_day")
|
|
location String?
|
|
recurrence Json?
|
|
creatorId String @map("creator_id") @db.Uuid
|
|
projectId String? @map("project_id") @db.Uuid
|
|
domainId String? @map("domain_id") @db.Uuid
|
|
metadata Json @default("{}")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
creator User @relation("EventCreator", fields: [creatorId], references: [id], onDelete: Cascade)
|
|
project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull)
|
|
domain Domain? @relation(fields: [domainId], references: [id], onDelete: SetNull)
|
|
|
|
@@unique([id, workspaceId])
|
|
@@index([workspaceId])
|
|
@@index([workspaceId, startTime])
|
|
@@index([creatorId])
|
|
@@index([projectId])
|
|
@@index([domainId])
|
|
@@map("events")
|
|
}
|
|
|
|
model Project {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
name String
|
|
description String? @db.Text
|
|
status ProjectStatus @default(PLANNING)
|
|
startDate DateTime? @map("start_date") @db.Date
|
|
endDate DateTime? @map("end_date") @db.Date
|
|
creatorId String @map("creator_id") @db.Uuid
|
|
domainId String? @map("domain_id") @db.Uuid
|
|
color String?
|
|
metadata Json @default("{}")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
creator User @relation("ProjectCreator", fields: [creatorId], references: [id], onDelete: Cascade)
|
|
tasks Task[]
|
|
events Event[]
|
|
domain Domain? @relation(fields: [domainId], references: [id], onDelete: SetNull)
|
|
ideas Idea[]
|
|
|
|
@@unique([id, workspaceId])
|
|
@@index([workspaceId])
|
|
@@index([workspaceId, status])
|
|
@@index([creatorId])
|
|
@@index([domainId])
|
|
@@map("projects")
|
|
}
|
|
|
|
model ActivityLog {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
action ActivityAction
|
|
entityType EntityType @map("entity_type")
|
|
entityId String @map("entity_id") @db.Uuid
|
|
details Json @default("{}")
|
|
ipAddress String? @map("ip_address")
|
|
userAgent String? @map("user_agent")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([id, workspaceId])
|
|
@@index([workspaceId])
|
|
@@index([workspaceId, createdAt])
|
|
@@index([entityType, entityId])
|
|
@@index([userId])
|
|
@@index([action])
|
|
@@map("activity_logs")
|
|
}
|
|
|
|
model MemoryEmbedding {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
content String @db.Text
|
|
// Note: vector dimension (1536) must match EMBEDDING_DIMENSION constant in @mosaic/shared
|
|
embedding Unsupported("vector(1536)")?
|
|
entityType EntityType? @map("entity_type")
|
|
entityId String? @map("entity_id") @db.Uuid
|
|
metadata Json @default("{}")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([workspaceId])
|
|
@@map("memory_embeddings")
|
|
}
|
|
|
|
// ============================================
|
|
// NEW MODELS
|
|
// ============================================
|
|
|
|
model Domain {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
|
|
name String
|
|
slug String
|
|
description String? @db.Text
|
|
color String?
|
|
icon String?
|
|
sortOrder Int @default(0) @map("sort_order")
|
|
|
|
metadata Json @default("{}")
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
tasks Task[]
|
|
events Event[]
|
|
projects Project[]
|
|
ideas Idea[]
|
|
|
|
@@unique([id, workspaceId])
|
|
@@unique([workspaceId, slug])
|
|
@@index([workspaceId])
|
|
@@map("domains")
|
|
}
|
|
|
|
model Idea {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
domainId String? @map("domain_id") @db.Uuid
|
|
projectId String? @map("project_id") @db.Uuid
|
|
|
|
// Core fields
|
|
title String?
|
|
content String @db.Text
|
|
|
|
// Status
|
|
status IdeaStatus @default(CAPTURED)
|
|
priority TaskPriority @default(MEDIUM)
|
|
|
|
// Categorization
|
|
category String?
|
|
tags String[]
|
|
|
|
metadata Json @default("{}")
|
|
|
|
// Embedding for semantic search (pgvector)
|
|
embedding Unsupported("vector(1536)")?
|
|
|
|
// Audit
|
|
creatorId String @map("creator_id") @db.Uuid
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
domain Domain? @relation(fields: [domainId], references: [id], onDelete: SetNull)
|
|
project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull)
|
|
creator User @relation("IdeaCreator", fields: [creatorId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([id, workspaceId])
|
|
@@index([workspaceId])
|
|
@@index([workspaceId, status])
|
|
@@index([domainId])
|
|
@@index([projectId])
|
|
@@index([creatorId])
|
|
@@map("ideas")
|
|
}
|
|
|
|
model Relationship {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
|
|
// Source entity
|
|
sourceType EntityType @map("source_type")
|
|
sourceId String @map("source_id") @db.Uuid
|
|
|
|
// Target entity
|
|
targetType EntityType @map("target_type")
|
|
targetId String @map("target_id") @db.Uuid
|
|
|
|
// Relationship type
|
|
relationship RelationshipType
|
|
|
|
metadata Json @default("{}")
|
|
notes String? @db.Text
|
|
|
|
// Audit
|
|
creatorId String @map("creator_id") @db.Uuid
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
creator User @relation("RelationshipCreator", fields: [creatorId], references: [id], onDelete: Cascade)
|
|
|
|
// Prevent duplicate relationships
|
|
@@unique([workspaceId, sourceType, sourceId, targetType, targetId, relationship])
|
|
@@index([sourceType, sourceId])
|
|
@@index([targetType, targetId])
|
|
@@index([relationship])
|
|
@@map("relationships")
|
|
}
|
|
|
|
model Agent {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
|
|
// Identity
|
|
agentId String @map("agent_id")
|
|
name String?
|
|
model String?
|
|
role String?
|
|
|
|
// Status
|
|
status AgentStatus @default(IDLE)
|
|
currentTask String? @map("current_task") @db.Text
|
|
|
|
// Performance metrics
|
|
metrics Json @default("{\"totalTasks\": 0, \"successfulTasks\": 0, \"failedTasks\": 0, \"avgResponseTimeMs\": 0}")
|
|
|
|
// Health
|
|
lastHeartbeat DateTime? @map("last_heartbeat") @db.Timestamptz
|
|
errorCount Int @default(0) @map("error_count")
|
|
lastError String? @map("last_error") @db.Text
|
|
|
|
// Firing history
|
|
firedCount Int @default(0) @map("fired_count")
|
|
fireHistory Json @default("[]") @map("fire_history")
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
terminatedAt DateTime? @map("terminated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
sessions AgentSession[]
|
|
|
|
@@unique([workspaceId, agentId])
|
|
@@index([workspaceId])
|
|
@@index([status])
|
|
@@map("agents")
|
|
}
|
|
|
|
model AgentSession {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
agentId String? @map("agent_id") @db.Uuid
|
|
|
|
// Identity
|
|
sessionKey String @map("session_key")
|
|
label String?
|
|
channel String?
|
|
|
|
// Context
|
|
contextSummary String? @map("context_summary") @db.Text
|
|
messageCount Int @default(0) @map("message_count")
|
|
|
|
// Status
|
|
isActive Boolean @default(true) @map("is_active")
|
|
|
|
startedAt DateTime @default(now()) @map("started_at") @db.Timestamptz
|
|
lastMessageAt DateTime? @map("last_message_at") @db.Timestamptz
|
|
endedAt DateTime? @map("ended_at") @db.Timestamptz
|
|
|
|
metadata Json @default("{}")
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
agent Agent? @relation(fields: [agentId], references: [id], onDelete: SetNull)
|
|
|
|
@@unique([workspaceId, sessionKey])
|
|
@@index([workspaceId])
|
|
@@index([userId])
|
|
@@index([agentId])
|
|
@@index([isActive])
|
|
@@map("agent_sessions")
|
|
}
|
|
|
|
model WidgetDefinition {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
|
|
name String @unique
|
|
displayName String @map("display_name")
|
|
description String? @db.Text
|
|
component String
|
|
|
|
// Default size (grid units)
|
|
defaultWidth Int @default(1) @map("default_width")
|
|
defaultHeight Int @default(1) @map("default_height")
|
|
minWidth Int @default(1) @map("min_width")
|
|
minHeight Int @default(1) @map("min_height")
|
|
maxWidth Int? @map("max_width")
|
|
maxHeight Int? @map("max_height")
|
|
|
|
// Configuration schema (JSON Schema for widget config)
|
|
configSchema Json @default("{}") @map("config_schema")
|
|
|
|
isActive Boolean @default(true) @map("is_active")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
|
|
@@map("widget_definitions")
|
|
}
|
|
|
|
model UserLayout {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
|
|
name String
|
|
isDefault Boolean @default(false) @map("is_default")
|
|
|
|
// Layout configuration (array of widget placements)
|
|
layout Json @default("[]")
|
|
|
|
// Additional metadata for the layout
|
|
metadata Json @default("{}")
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([id, workspaceId])
|
|
@@unique([workspaceId, userId, name])
|
|
@@index([userId])
|
|
@@map("user_layouts")
|
|
}
|
|
|
|
// ============================================
|
|
// AUTHENTICATION MODELS (BetterAuth)
|
|
// ============================================
|
|
|
|
model Session {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
token String @unique
|
|
expiresAt DateTime @map("expires_at") @db.Timestamptz
|
|
ipAddress String? @map("ip_address")
|
|
userAgent String? @map("user_agent")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@index([token])
|
|
@@map("sessions")
|
|
}
|
|
|
|
model Account {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
accountId String @map("account_id")
|
|
providerId String @map("provider_id")
|
|
accessToken String? @map("access_token")
|
|
refreshToken String? @map("refresh_token")
|
|
idToken String? @map("id_token")
|
|
accessTokenExpiresAt DateTime? @map("access_token_expires_at") @db.Timestamptz
|
|
refreshTokenExpiresAt DateTime? @map("refresh_token_expires_at") @db.Timestamptz
|
|
scope String?
|
|
password String?
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([providerId, accountId])
|
|
@@index([userId])
|
|
@@map("accounts")
|
|
}
|
|
|
|
model Verification {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
identifier String
|
|
value String
|
|
expiresAt DateTime @map("expires_at") @db.Timestamptz
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
@@index([identifier])
|
|
@@map("verifications")
|
|
}
|
|
|
|
// ============================================
|
|
// KNOWLEDGE MODULE
|
|
// ============================================
|
|
|
|
model KnowledgeEntry {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
|
|
// Identity
|
|
slug String
|
|
title String
|
|
|
|
// Content
|
|
content String @db.Text
|
|
contentHtml String? @map("content_html") @db.Text
|
|
summary String?
|
|
|
|
// Status
|
|
status EntryStatus @default(DRAFT)
|
|
visibility Visibility @default(PRIVATE)
|
|
|
|
// Audit
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
createdBy String @map("created_by") @db.Uuid
|
|
updatedBy String @map("updated_by") @db.Uuid
|
|
|
|
// Relations
|
|
tags KnowledgeEntryTag[]
|
|
outgoingLinks KnowledgeLink[] @relation("SourceEntry")
|
|
incomingLinks KnowledgeLink[] @relation("TargetEntry")
|
|
versions KnowledgeEntryVersion[]
|
|
embedding KnowledgeEmbedding?
|
|
|
|
@@unique([workspaceId, slug])
|
|
@@index([workspaceId, status])
|
|
@@index([workspaceId, updatedAt])
|
|
@@index([createdBy])
|
|
@@index([updatedBy])
|
|
@@map("knowledge_entries")
|
|
}
|
|
|
|
model KnowledgeEntryVersion {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
entryId String @map("entry_id") @db.Uuid
|
|
entry KnowledgeEntry @relation(fields: [entryId], references: [id], onDelete: Cascade)
|
|
|
|
version Int
|
|
title String
|
|
content String @db.Text
|
|
summary String?
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
createdBy String @map("created_by") @db.Uuid
|
|
author User @relation("EntryVersionAuthor", fields: [createdBy], references: [id])
|
|
changeNote String? @map("change_note")
|
|
|
|
@@unique([entryId, version])
|
|
@@index([entryId, version])
|
|
@@map("knowledge_entry_versions")
|
|
}
|
|
|
|
model KnowledgeLink {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
|
|
sourceId String @map("source_id") @db.Uuid
|
|
source KnowledgeEntry @relation("SourceEntry", fields: [sourceId], references: [id], onDelete: Cascade)
|
|
|
|
targetId String @map("target_id") @db.Uuid
|
|
target KnowledgeEntry @relation("TargetEntry", fields: [targetId], references: [id], onDelete: Cascade)
|
|
|
|
// Link metadata
|
|
linkText String @map("link_text")
|
|
context String?
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
|
|
@@unique([sourceId, targetId])
|
|
@@index([sourceId])
|
|
@@index([targetId])
|
|
@@map("knowledge_links")
|
|
}
|
|
|
|
model KnowledgeTag {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
|
|
name String
|
|
slug String
|
|
color String?
|
|
description String?
|
|
|
|
entries KnowledgeEntryTag[]
|
|
|
|
@@unique([workspaceId, slug])
|
|
@@index([workspaceId])
|
|
@@map("knowledge_tags")
|
|
}
|
|
|
|
model KnowledgeEntryTag {
|
|
entryId String @map("entry_id") @db.Uuid
|
|
entry KnowledgeEntry @relation(fields: [entryId], references: [id], onDelete: Cascade)
|
|
|
|
tagId String @map("tag_id") @db.Uuid
|
|
tag KnowledgeTag @relation(fields: [tagId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([entryId, tagId])
|
|
@@index([entryId])
|
|
@@index([tagId])
|
|
@@map("knowledge_entry_tags")
|
|
}
|
|
|
|
model KnowledgeEmbedding {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
entryId String @unique @map("entry_id") @db.Uuid
|
|
entry KnowledgeEntry @relation(fields: [entryId], references: [id], onDelete: Cascade)
|
|
|
|
embedding Unsupported("vector(1536)")
|
|
model String
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
@@index([entryId])
|
|
@@map("knowledge_embeddings")
|
|
}
|
|
|
|
// ============================================
|
|
// CRON JOBS
|
|
// ============================================
|
|
|
|
model CronSchedule {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
|
|
// Cron configuration
|
|
expression String // Standard cron: "0 9 * * *" = 9am daily
|
|
command String // MoltBot command to trigger
|
|
|
|
// State
|
|
enabled Boolean @default(true)
|
|
lastRun DateTime? @map("last_run") @db.Timestamptz
|
|
nextRun DateTime? @map("next_run") @db.Timestamptz
|
|
|
|
// Audit
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
@@index([workspaceId])
|
|
@@index([workspaceId, enabled])
|
|
@@index([nextRun])
|
|
@@map("cron_schedules")
|
|
}
|