feat(#37-41): Add domains, ideas, relationships, agents, widgets schema

Schema additions for issues #37-41:

New models:
- Domain (#37): Life domains (work, marriage, homelab, etc.)
- Idea (#38): Brain dumps with pgvector embeddings
- Relationship (#39): Generic entity linking (blocks, depends_on)
- Agent (#40): ClawdBot agent tracking with metrics
- AgentSession (#40): Conversation session tracking
- WidgetDefinition (#41): HUD widget registry
- UserLayout (#41): Per-user dashboard configuration

Updated models:
- Task, Event, Project: Added domainId foreign key
- User, Workspace: Added new relations

New enums:
- IdeaStatus: CAPTURED, PROCESSING, ACTIONABLE, ARCHIVED, DISCARDED
- RelationshipType: BLOCKS, BLOCKED_BY, DEPENDS_ON, etc.
- AgentStatus: IDLE, WORKING, WAITING, ERROR, TERMINATED
- EntityType: Added IDEA, DOMAIN

Migration: 20260129182803_add_domains_ideas_agents_widgets
This commit is contained in:
Jason Woltje
2026-01-29 12:29:21 -06:00
parent a220c2dc0a
commit 973502f26e
308 changed files with 18374 additions and 113 deletions

View File

@@ -52,6 +52,10 @@ enum ActivityAction {
COMPLETED
ASSIGNED
COMMENTED
LOGIN
LOGOUT
PASSWORD_RESET
EMAIL_VERIFIED
}
enum EntityType {
@@ -60,6 +64,36 @@ enum EntityType {
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
}
// ============================================
@@ -78,15 +112,19 @@ model User {
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
// Relations
ownedWorkspaces Workspace[] @relation("WorkspaceOwner")
ownedWorkspaces Workspace[] @relation("WorkspaceOwner")
workspaceMemberships WorkspaceMember[]
assignedTasks Task[] @relation("TaskAssignee")
createdTasks Task[] @relation("TaskCreator")
createdEvents Event[] @relation("EventCreator")
createdProjects Project[] @relation("ProjectCreator")
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[]
@@map("users")
}
@@ -107,6 +145,12 @@ model Workspace {
projects Project[]
activityLogs ActivityLog[]
memoryEmbeddings MemoryEmbedding[]
domains Domain[]
ideas Idea[]
relationships Relationship[]
agents Agent[]
agentSessions AgentSession[]
userLayouts UserLayout[]
@@index([ownerId])
@@map("workspaces")
@@ -139,6 +183,7 @@ model Task {
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
@@ -152,6 +197,7 @@ model Task {
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)
@@index([workspaceId])
@@index([workspaceId, status])
@@ -159,6 +205,7 @@ model Task {
@@index([assigneeId])
@@index([projectId])
@@index([parentId])
@@index([domainId])
@@map("tasks")
}
@@ -174,6 +221,7 @@ model Event {
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
@@ -182,11 +230,13 @@ model Event {
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)
@@index([workspaceId])
@@index([workspaceId, startTime])
@@index([creatorId])
@@index([projectId])
@@index([domainId])
@@map("events")
}
@@ -199,6 +249,7 @@ model Project {
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
@@ -209,10 +260,13 @@ model Project {
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[]
@@index([workspaceId])
@@index([workspaceId, status])
@@index([creatorId])
@@index([domainId])
@@map("projects")
}
@@ -224,6 +278,8 @@ model ActivityLog {
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
@@ -234,6 +290,7 @@ model ActivityLog {
@@index([workspaceId, createdAt])
@@index([entityType, entityId])
@@index([userId])
@@index([action])
@@map("activity_logs")
}
@@ -256,6 +313,239 @@ model MemoryEmbedding {
@@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([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)
@@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("[]")
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([workspaceId, userId, name])
@@index([userId])
@@map("user_layouts")
}
// ============================================
// AUTHENTICATION MODELS (BetterAuth)
// ============================================