Some checks failed
ci/woodpecker/push/api Pipeline failed
- Add matrix_room_id column to workspace table (migration) - Create MatrixRoomService for room provisioning and mapping - Auto-create Matrix room on workspace provisioning (when configured) - Support manual room linking for existing workspaces - Unit tests for all mapping operations Refs #380
1510 lines
47 KiB
Plaintext
1510 lines
47 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
|
|
CREDENTIAL_CREATED
|
|
CREDENTIAL_ACCESSED
|
|
CREDENTIAL_ROTATED
|
|
CREDENTIAL_REVOKED
|
|
}
|
|
|
|
enum EntityType {
|
|
TASK
|
|
EVENT
|
|
PROJECT
|
|
WORKSPACE
|
|
USER
|
|
IDEA
|
|
DOMAIN
|
|
CREDENTIAL
|
|
}
|
|
|
|
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 AgentTaskStatus {
|
|
PENDING
|
|
RUNNING
|
|
COMPLETED
|
|
FAILED
|
|
}
|
|
|
|
enum AgentTaskPriority {
|
|
LOW
|
|
MEDIUM
|
|
HIGH
|
|
}
|
|
|
|
enum EntryStatus {
|
|
DRAFT
|
|
PUBLISHED
|
|
ARCHIVED
|
|
}
|
|
|
|
enum Visibility {
|
|
PRIVATE
|
|
WORKSPACE
|
|
PUBLIC
|
|
}
|
|
|
|
enum FormalityLevel {
|
|
VERY_CASUAL
|
|
CASUAL
|
|
NEUTRAL
|
|
FORMAL
|
|
VERY_FORMAL
|
|
}
|
|
|
|
enum RunnerJobStatus {
|
|
PENDING
|
|
QUEUED
|
|
RUNNING
|
|
COMPLETED
|
|
FAILED
|
|
CANCELLED
|
|
}
|
|
|
|
enum JobStepPhase {
|
|
SETUP
|
|
EXECUTION
|
|
VALIDATION
|
|
CLEANUP
|
|
}
|
|
|
|
enum JobStepType {
|
|
COMMAND
|
|
AI_ACTION
|
|
GATE
|
|
ARTIFACT
|
|
}
|
|
|
|
enum JobStepStatus {
|
|
PENDING
|
|
RUNNING
|
|
COMPLETED
|
|
FAILED
|
|
SKIPPED
|
|
}
|
|
|
|
enum FederationConnectionStatus {
|
|
PENDING
|
|
ACTIVE
|
|
SUSPENDED
|
|
DISCONNECTED
|
|
}
|
|
|
|
enum FederationMessageType {
|
|
QUERY
|
|
COMMAND
|
|
EVENT
|
|
}
|
|
|
|
enum FederationMessageStatus {
|
|
PENDING
|
|
DELIVERED
|
|
FAILED
|
|
TIMEOUT
|
|
}
|
|
|
|
enum CredentialType {
|
|
API_KEY
|
|
OAUTH_TOKEN
|
|
ACCESS_TOKEN
|
|
SECRET
|
|
PASSWORD
|
|
CUSTOM
|
|
}
|
|
|
|
enum CredentialScope {
|
|
USER
|
|
WORKSPACE
|
|
SYSTEM
|
|
}
|
|
|
|
// ============================================
|
|
// 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[]
|
|
agentTasks AgentTask[] @relation("AgentTaskCreator")
|
|
userLayouts UserLayout[]
|
|
userPreference UserPreference?
|
|
knowledgeEntryVersions KnowledgeEntryVersion[] @relation("EntryVersionAuthor")
|
|
llmProviders LlmProviderInstance[] @relation("UserLlmProviders")
|
|
federatedIdentities FederatedIdentity[]
|
|
llmUsageLogs LlmUsageLog[] @relation("UserLlmUsageLogs")
|
|
userCredentials UserCredential[] @relation("UserCredentials")
|
|
|
|
@@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("{}")
|
|
matrixRoomId String? @map("matrix_room_id")
|
|
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[]
|
|
agentTasks AgentTask[]
|
|
userLayouts UserLayout[]
|
|
knowledgeEntries KnowledgeEntry[]
|
|
knowledgeTags KnowledgeTag[]
|
|
cronSchedules CronSchedule[]
|
|
personalities Personality[]
|
|
llmSettings WorkspaceLlmSettings?
|
|
qualityGates QualityGate[]
|
|
runnerJobs RunnerJob[]
|
|
federationConnections FederationConnection[]
|
|
federationMessages FederationMessage[]
|
|
federationEventSubscriptions FederationEventSubscription[]
|
|
llmUsageLogs LlmUsageLog[]
|
|
userCredentials UserCredential[]
|
|
|
|
@@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 AgentTask {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
|
|
// Task details
|
|
title String
|
|
description String? @db.Text
|
|
status AgentTaskStatus @default(PENDING)
|
|
priority AgentTaskPriority @default(MEDIUM)
|
|
|
|
// Agent configuration
|
|
agentType String @map("agent_type")
|
|
agentConfig Json @default("{}") @map("agent_config")
|
|
|
|
// Results
|
|
result Json?
|
|
error String? @db.Text
|
|
|
|
// Timing
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
startedAt DateTime? @map("started_at") @db.Timestamptz
|
|
completedAt DateTime? @map("completed_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
createdBy User @relation("AgentTaskCreator", fields: [createdById], references: [id], onDelete: Cascade)
|
|
createdById String @map("created_by_id") @db.Uuid
|
|
runnerJobs RunnerJob[]
|
|
|
|
@@unique([id, workspaceId])
|
|
@@index([workspaceId])
|
|
@@index([workspaceId, status])
|
|
@@index([createdById])
|
|
@@index([agentType])
|
|
@@map("agent_tasks")
|
|
}
|
|
|
|
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?
|
|
encryptionVersion String? @map("encryption_version") @db.VarChar(20)
|
|
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])
|
|
@@index([encryptionVersion])
|
|
@@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")
|
|
}
|
|
|
|
// ============================================
|
|
// USER CREDENTIALS MODULE
|
|
// ============================================
|
|
|
|
model UserCredential {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
workspaceId String? @map("workspace_id") @db.Uuid
|
|
|
|
// Identity
|
|
name String
|
|
provider String // "github", "openai", "custom"
|
|
type CredentialType
|
|
scope CredentialScope @default(USER)
|
|
|
|
// Encrypted storage
|
|
encryptedValue String @map("encrypted_value") @db.Text
|
|
maskedValue String? @map("masked_value") @db.VarChar(20)
|
|
|
|
// Metadata
|
|
description String? @db.Text
|
|
expiresAt DateTime? @map("expires_at") @db.Timestamptz
|
|
lastUsedAt DateTime? @map("last_used_at") @db.Timestamptz
|
|
metadata Json @default("{}")
|
|
|
|
// Status
|
|
isActive Boolean @default(true) @map("is_active")
|
|
rotatedAt DateTime? @map("rotated_at") @db.Timestamptz
|
|
|
|
// Audit
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
user User @relation("UserCredentials", fields: [userId], references: [id], onDelete: Cascade)
|
|
workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, workspaceId, provider, name])
|
|
@@index([userId])
|
|
@@index([workspaceId])
|
|
@@index([userId, scope])
|
|
@@index([workspaceId, scope])
|
|
@@index([scope, isActive])
|
|
@@map("user_credentials")
|
|
}
|
|
|
|
// ============================================
|
|
// 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?
|
|
|
|
// Full-text search vector (automatically maintained by trigger)
|
|
searchVector Unsupported("tsvector")? @map("search_vector")
|
|
|
|
// 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])
|
|
// Note: GIN index on searchVector created via migration (not supported in Prisma schema)
|
|
@@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")
|
|
displayText String @map("display_text")
|
|
context String?
|
|
|
|
// Position in source content
|
|
positionStart Int @map("position_start")
|
|
positionEnd Int @map("position_end")
|
|
|
|
// Resolution status
|
|
resolved Boolean @default(true)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
|
|
@@unique([sourceId, targetId])
|
|
@@index([sourceId])
|
|
@@index([targetId])
|
|
@@index([resolved])
|
|
@@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")
|
|
}
|
|
|
|
// ============================================
|
|
// PERSONALITY MODULE
|
|
// ============================================
|
|
|
|
model Personality {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
|
|
// Identity
|
|
name String // unique identifier slug
|
|
displayName String @map("display_name")
|
|
description String? @db.Text
|
|
|
|
// System prompt
|
|
systemPrompt String @map("system_prompt") @db.Text
|
|
|
|
// LLM configuration
|
|
temperature Float? // null = use provider default
|
|
maxTokens Int? @map("max_tokens") // null = use provider default
|
|
llmProviderInstanceId String? @map("llm_provider_instance_id") @db.Uuid
|
|
|
|
// Status
|
|
isDefault Boolean @default(false) @map("is_default")
|
|
isEnabled Boolean @default(true) @map("is_enabled")
|
|
|
|
// Audit
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
llmProviderInstance LlmProviderInstance? @relation("PersonalityLlmProvider", fields: [llmProviderInstanceId], references: [id], onDelete: SetNull)
|
|
workspaceLlmSettings WorkspaceLlmSettings[] @relation("WorkspacePersonality")
|
|
|
|
@@unique([id, workspaceId])
|
|
@@unique([workspaceId, name])
|
|
@@index([workspaceId])
|
|
@@index([workspaceId, isDefault])
|
|
@@index([workspaceId, isEnabled])
|
|
@@index([llmProviderInstanceId])
|
|
@@map("personalities")
|
|
}
|
|
|
|
// ============================================
|
|
// LLM PROVIDER MODULE
|
|
// ============================================
|
|
|
|
model LlmProviderInstance {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
providerType String @map("provider_type") // "ollama" | "claude" | "openai"
|
|
displayName String @map("display_name")
|
|
userId String? @map("user_id") @db.Uuid // NULL = system-level, UUID = user-level
|
|
config Json // Provider-specific configuration
|
|
isDefault Boolean @default(false) @map("is_default")
|
|
isEnabled Boolean @default(true) @map("is_enabled")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
user User? @relation("UserLlmProviders", fields: [userId], references: [id], onDelete: Cascade)
|
|
personalities Personality[] @relation("PersonalityLlmProvider")
|
|
workspaceLlmSettings WorkspaceLlmSettings[] @relation("WorkspaceLlmProvider")
|
|
llmUsageLogs LlmUsageLog[] @relation("LlmUsageLogs")
|
|
|
|
@@index([userId])
|
|
@@index([providerType])
|
|
@@index([isDefault])
|
|
@@index([isEnabled])
|
|
@@map("llm_provider_instances")
|
|
}
|
|
|
|
// ============================================
|
|
// WORKSPACE LLM SETTINGS
|
|
// ============================================
|
|
|
|
model WorkspaceLlmSettings {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @unique @map("workspace_id") @db.Uuid
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
defaultLlmProviderId String? @map("default_llm_provider_id") @db.Uuid
|
|
defaultLlmProvider LlmProviderInstance? @relation("WorkspaceLlmProvider", fields: [defaultLlmProviderId], references: [id], onDelete: SetNull)
|
|
defaultPersonalityId String? @map("default_personality_id") @db.Uuid
|
|
defaultPersonality Personality? @relation("WorkspacePersonality", fields: [defaultPersonalityId], references: [id], onDelete: SetNull)
|
|
settings Json? @default("{}")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
@@index([workspaceId])
|
|
@@index([defaultLlmProviderId])
|
|
@@index([defaultPersonalityId])
|
|
@@map("workspace_llm_settings")
|
|
}
|
|
|
|
// ============================================
|
|
// QUALITY GATE MODULE
|
|
// ============================================
|
|
|
|
model QualityGate {
|
|
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
|
|
description String?
|
|
type String // 'build' | 'lint' | 'test' | 'coverage' | 'custom'
|
|
command String?
|
|
expectedOutput String? @map("expected_output")
|
|
isRegex Boolean @default(false) @map("is_regex")
|
|
required Boolean @default(true)
|
|
order Int @default(0)
|
|
isEnabled Boolean @default(true) @map("is_enabled")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
@@unique([workspaceId, name])
|
|
@@index([workspaceId])
|
|
@@index([workspaceId, isEnabled])
|
|
@@map("quality_gates")
|
|
}
|
|
|
|
model TaskRejection {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
taskId String @map("task_id")
|
|
workspaceId String @map("workspace_id")
|
|
agentId String @map("agent_id")
|
|
attemptCount Int @map("attempt_count")
|
|
failures Json // FailureSummary[]
|
|
originalTask String @map("original_task")
|
|
startedAt DateTime @map("started_at") @db.Timestamptz
|
|
rejectedAt DateTime @map("rejected_at") @db.Timestamptz
|
|
escalated Boolean @default(false)
|
|
manualReview Boolean @default(false) @map("manual_review")
|
|
resolvedAt DateTime? @map("resolved_at") @db.Timestamptz
|
|
resolution String?
|
|
|
|
@@index([taskId])
|
|
@@index([workspaceId])
|
|
@@index([agentId])
|
|
@@index([escalated])
|
|
@@index([manualReview])
|
|
@@map("task_rejections")
|
|
}
|
|
|
|
model TokenBudget {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
taskId String @unique @map("task_id") @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
agentId String @map("agent_id")
|
|
|
|
// Budget allocation
|
|
allocatedTokens Int @map("allocated_tokens")
|
|
estimatedComplexity String @map("estimated_complexity") // "low", "medium", "high", "critical"
|
|
|
|
// Usage tracking
|
|
inputTokensUsed Int @default(0) @map("input_tokens_used")
|
|
outputTokensUsed Int @default(0) @map("output_tokens_used")
|
|
totalTokensUsed Int @default(0) @map("total_tokens_used")
|
|
|
|
// Cost tracking
|
|
estimatedCost Decimal? @map("estimated_cost") @db.Decimal(10, 6)
|
|
|
|
// State
|
|
startedAt DateTime @default(now()) @map("started_at") @db.Timestamptz
|
|
lastUpdatedAt DateTime @updatedAt @map("last_updated_at") @db.Timestamptz
|
|
completedAt DateTime? @map("completed_at") @db.Timestamptz
|
|
|
|
// Analysis
|
|
budgetUtilization Float? @map("budget_utilization") // 0.0 - 1.0
|
|
suspiciousPattern Boolean @default(false) @map("suspicious_pattern")
|
|
suspiciousReason String? @map("suspicious_reason")
|
|
|
|
@@index([taskId])
|
|
@@index([workspaceId])
|
|
@@index([suspiciousPattern])
|
|
@@map("token_budgets")
|
|
}
|
|
|
|
// ============================================
|
|
// RUNNER JOB TRACKING MODULE
|
|
// ============================================
|
|
|
|
model RunnerJob {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
agentTaskId String? @map("agent_task_id") @db.Uuid
|
|
|
|
// Job details
|
|
type String // 'git-status', 'code-task', 'priority-calc'
|
|
status RunnerJobStatus @default(PENDING)
|
|
priority Int
|
|
progressPercent Int @default(0) @map("progress_percent")
|
|
version Int @default(1) // Optimistic locking version
|
|
|
|
// Results
|
|
result Json?
|
|
error String? @db.Text
|
|
|
|
// Timing
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
startedAt DateTime? @map("started_at") @db.Timestamptz
|
|
completedAt DateTime? @map("completed_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
agentTask AgentTask? @relation(fields: [agentTaskId], references: [id], onDelete: SetNull)
|
|
steps JobStep[]
|
|
events JobEvent[]
|
|
|
|
@@unique([id, workspaceId])
|
|
@@index([workspaceId])
|
|
@@index([workspaceId, status])
|
|
@@index([agentTaskId])
|
|
@@index([priority])
|
|
@@map("runner_jobs")
|
|
}
|
|
|
|
model JobStep {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
jobId String @map("job_id") @db.Uuid
|
|
|
|
// Step details
|
|
ordinal Int
|
|
phase JobStepPhase
|
|
name String
|
|
type JobStepType
|
|
status JobStepStatus @default(PENDING)
|
|
|
|
// Output and metrics
|
|
output String? @db.Text
|
|
tokensInput Int? @map("tokens_input")
|
|
tokensOutput Int? @map("tokens_output")
|
|
|
|
// Timing
|
|
startedAt DateTime? @map("started_at") @db.Timestamptz
|
|
completedAt DateTime? @map("completed_at") @db.Timestamptz
|
|
durationMs Int? @map("duration_ms")
|
|
|
|
// Relations
|
|
job RunnerJob @relation(fields: [jobId], references: [id], onDelete: Cascade)
|
|
events JobEvent[]
|
|
|
|
@@index([jobId])
|
|
@@index([jobId, ordinal])
|
|
@@index([status])
|
|
@@map("job_steps")
|
|
}
|
|
|
|
model JobEvent {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
jobId String @map("job_id") @db.Uuid
|
|
stepId String? @map("step_id") @db.Uuid
|
|
|
|
// Event details
|
|
type String
|
|
timestamp DateTime @db.Timestamptz
|
|
actor String
|
|
payload Json
|
|
|
|
// Relations
|
|
job RunnerJob @relation(fields: [jobId], references: [id], onDelete: Cascade)
|
|
step JobStep? @relation(fields: [stepId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([jobId])
|
|
@@index([stepId])
|
|
@@index([timestamp])
|
|
@@index([type])
|
|
@@index([jobId, timestamp])
|
|
@@map("job_events")
|
|
}
|
|
|
|
// ============================================
|
|
// FEDERATION MODULE
|
|
// ============================================
|
|
|
|
model Instance {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
instanceId String @unique @map("instance_id") // Unique identifier for federation
|
|
name String
|
|
url String
|
|
publicKey String @map("public_key") @db.Text
|
|
privateKey String @map("private_key") @db.Text // AES-256-GCM encrypted with ENCRYPTION_KEY
|
|
|
|
// Capabilities and metadata
|
|
capabilities Json @default("{}")
|
|
metadata Json @default("{}")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
@@map("instances")
|
|
}
|
|
|
|
model FederationConnection {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
|
|
// Remote instance details
|
|
remoteInstanceId String @map("remote_instance_id")
|
|
remoteUrl String @map("remote_url")
|
|
remotePublicKey String @map("remote_public_key") @db.Text
|
|
remoteCapabilities Json @default("{}") @map("remote_capabilities")
|
|
|
|
// Connection status
|
|
status FederationConnectionStatus @default(PENDING)
|
|
|
|
// Metadata
|
|
metadata Json @default("{}")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
connectedAt DateTime? @map("connected_at") @db.Timestamptz
|
|
disconnectedAt DateTime? @map("disconnected_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
messages FederationMessage[]
|
|
eventSubscriptions FederationEventSubscription[]
|
|
|
|
@@unique([workspaceId, remoteInstanceId])
|
|
@@index([workspaceId])
|
|
@@index([workspaceId, status])
|
|
@@index([remoteInstanceId])
|
|
@@map("federation_connections")
|
|
}
|
|
|
|
model FederatedIdentity {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
localUserId String @map("local_user_id") @db.Uuid
|
|
remoteUserId String @map("remote_user_id")
|
|
remoteInstanceId String @map("remote_instance_id")
|
|
oidcSubject String @map("oidc_subject")
|
|
email String
|
|
metadata Json @default("{}")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
user User @relation(fields: [localUserId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([localUserId, remoteInstanceId])
|
|
@@index([localUserId])
|
|
@@index([remoteInstanceId])
|
|
@@index([oidcSubject])
|
|
@@map("federated_identities")
|
|
}
|
|
|
|
model FederationMessage {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
connectionId String @map("connection_id") @db.Uuid
|
|
|
|
// Message metadata
|
|
messageType FederationMessageType @map("message_type")
|
|
messageId String @unique @map("message_id") // UUID for deduplication
|
|
correlationId String? @map("correlation_id") // For request/response tracking
|
|
|
|
// Message content
|
|
query String? @db.Text
|
|
commandType String? @map("command_type") @db.Text
|
|
eventType String? @map("event_type") @db.Text // For EVENT messages
|
|
payload Json? @default("{}")
|
|
response Json? @default("{}")
|
|
|
|
// Status tracking
|
|
status FederationMessageStatus @default(PENDING)
|
|
error String? @db.Text
|
|
|
|
// Security
|
|
signature String @db.Text
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
deliveredAt DateTime? @map("delivered_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
connection FederationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([workspaceId])
|
|
@@index([connectionId])
|
|
@@index([messageId])
|
|
@@index([correlationId])
|
|
@@index([eventType])
|
|
@@map("federation_messages")
|
|
}
|
|
|
|
model FederationEventSubscription {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
connectionId String @map("connection_id") @db.Uuid
|
|
|
|
// Event subscription details
|
|
eventType String @map("event_type")
|
|
metadata Json @default("{}")
|
|
isActive Boolean @default(true) @map("is_active")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
connection FederationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([workspaceId, connectionId, eventType])
|
|
@@index([workspaceId])
|
|
@@index([connectionId])
|
|
@@index([eventType])
|
|
@@index([workspaceId, isActive])
|
|
@@map("federation_event_subscriptions")
|
|
}
|
|
|
|
// ============================================
|
|
// LLM USAGE TRACKING MODULE
|
|
// ============================================
|
|
|
|
model LlmUsageLog {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
workspaceId String @map("workspace_id") @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
|
|
// LLM provider and model info
|
|
provider String @db.VarChar(50)
|
|
model String @db.VarChar(100)
|
|
providerInstanceId String? @map("provider_instance_id") @db.Uuid
|
|
|
|
// Token usage
|
|
promptTokens Int @default(0) @map("prompt_tokens")
|
|
completionTokens Int @default(0) @map("completion_tokens")
|
|
totalTokens Int @default(0) @map("total_tokens")
|
|
|
|
// Optional cost (in cents for precision)
|
|
costCents Float? @map("cost_cents")
|
|
|
|
// Task type for routing analytics
|
|
taskType String? @map("task_type") @db.VarChar(50)
|
|
|
|
// Optional reference to conversation/session
|
|
conversationId String? @map("conversation_id") @db.Uuid
|
|
|
|
// Duration in milliseconds
|
|
durationMs Int? @map("duration_ms")
|
|
|
|
// Timestamp
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
|
|
// Relations
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
user User @relation("UserLlmUsageLogs", fields: [userId], references: [id], onDelete: Cascade)
|
|
llmProviderInstance LlmProviderInstance? @relation("LlmUsageLogs", fields: [providerInstanceId], references: [id], onDelete: SetNull)
|
|
|
|
@@index([workspaceId])
|
|
@@index([workspaceId, createdAt])
|
|
@@index([userId])
|
|
@@index([provider])
|
|
@@index([model])
|
|
@@index([providerInstanceId])
|
|
@@index([taskType])
|
|
@@index([conversationId])
|
|
@@map("llm_usage_logs")
|
|
}
|