- Add Prisma models for conversations, messages, participants, tool runs, and user settings - Create API endpoints for conversation CRUD and SSE message streaming - Build landing page with sample prompts at /omega - Build chat interface with real-time streaming at /omega/[conversationId] - Integrate @tpmjs/registry-search and @tpmjs/registry-execute packages - Use OpenAI GPT-4.1 Mini as the default model
1617 lines
54 KiB
Text
1617 lines
54 KiB
Text
// This is your Prisma schema file,
|
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
directUrl = env("DIRECT_URL") // Direct connection for migrations (bypasses pooler)
|
|
}
|
|
|
|
/// Package table - stores NPM package metadata (package-level)
|
|
model Package {
|
|
id String @id @default(cuid())
|
|
|
|
// NPM Metadata
|
|
npmPackageName String @unique @map("npm_package_name") @db.VarChar(214)
|
|
npmVersion String @map("npm_version") @db.VarChar(50)
|
|
npmPublishedAt DateTime @map("npm_published_at")
|
|
npmDescription String? @map("npm_description") @db.Text
|
|
npmRepository Json? @map("npm_repository") @db.JsonB
|
|
npmHomepage String? @map("npm_homepage") @db.Text
|
|
npmLicense String? @map("npm_license") @db.VarChar(50)
|
|
npmKeywords String[] @default([]) @map("npm_keywords") @db.Text
|
|
npmReadme String? @map("npm_readme") @db.Text
|
|
npmAuthor Json? @map("npm_author") @db.JsonB
|
|
npmMaintainers Json? @map("npm_maintainers") @db.JsonB
|
|
|
|
// TPMJS Package-Level Metadata
|
|
category String @db.VarChar(50)
|
|
env Json? @db.JsonB // Environment variables (shared across tools)
|
|
frameworks String[] @default([]) @db.Text
|
|
tier String @db.VarChar(20) // 'minimal' | 'rich'
|
|
discoveryMethod String @map("discovery_method") @db.VarChar(20) // 'keyword' | 'changes-feed'
|
|
isOfficial Boolean @default(false) @map("is_official")
|
|
|
|
// Package Metrics
|
|
npmDownloadsLastMonth Int? @default(0) @map("npm_downloads_last_month")
|
|
githubStars Int? @default(0) @map("github_stars")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relations
|
|
tools Tool[]
|
|
|
|
@@index([category])
|
|
@@index([isOfficial])
|
|
@@index([npmDownloadsLastMonth])
|
|
@@index([createdAt])
|
|
@@map("packages")
|
|
}
|
|
|
|
/// Tool table - stores individual tools within packages
|
|
model Tool {
|
|
id String @id @default(cuid())
|
|
|
|
// Package Relation
|
|
packageId String @map("package_id")
|
|
package Package @relation(fields: [packageId], references: [id], onDelete: Cascade)
|
|
|
|
// Tool Identity
|
|
name String @db.VarChar(100) // e.g., "helloWorldTool", "default"
|
|
|
|
// Tool Metadata
|
|
description String @db.Text
|
|
parameters Json? @db.JsonB // Legacy/fallback - author-provided parameters array
|
|
returns Json? @db.JsonB // @deprecated - will be auto-extracted in future
|
|
aiAgent Json? @map("ai_agent") @db.JsonB // @deprecated - will be auto-extracted in future
|
|
|
|
// Schema Extraction Fields
|
|
inputSchema Json? @map("input_schema") @db.JsonB // Full JSON Schema from executor
|
|
schemaSource String? @map("schema_source") @db.VarChar(20) // 'extracted' | 'author' | null
|
|
schemaExtractedAt DateTime? @map("schema_extracted_at") // Only updated on successful extraction
|
|
schemaExtractionAttemptAt DateTime? @map("schema_extraction_attempt_at") // Updated on every attempt (for rate limiting)
|
|
schemaExtractionError String? @map("schema_extraction_error") @db.Text // Error message from last failed attempt
|
|
|
|
// Tool Discovery Fields
|
|
toolDiscoverySource String? @map("tool_discovery_source") @db.VarChar(20) // 'auto' | 'manual' | null
|
|
|
|
// Tool Metrics
|
|
qualityScore Decimal? @map("quality_score") @db.Decimal(3, 2) // 0.00 to 1.00
|
|
likeCount Int @default(0) @map("like_count")
|
|
|
|
// Health Status Fields
|
|
importHealth HealthStatus? @default(UNKNOWN) @map("import_health")
|
|
executionHealth HealthStatus? @default(UNKNOWN) @map("execution_health")
|
|
lastHealthCheck DateTime? @map("last_health_check")
|
|
healthCheckError String? @map("health_check_error") @db.Text
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Rating aggregates
|
|
averageRating Decimal? @map("average_rating") @db.Decimal(2, 1) // 1.0 to 5.0
|
|
ratingCount Int @default(0) @map("rating_count")
|
|
reviewCount Int @default(0) @map("review_count")
|
|
|
|
// Relations
|
|
simulations Simulation[]
|
|
healthChecks HealthCheck[]
|
|
collections CollectionTool[]
|
|
agents AgentTool[]
|
|
likes ToolLike[]
|
|
ratings ToolRating[]
|
|
reviews ToolReview[]
|
|
skillsCache ToolSkillsCache?
|
|
|
|
@@unique([packageId, name])
|
|
@@index([qualityScore])
|
|
@@index([likeCount])
|
|
@@index([averageRating])
|
|
@@index([ratingCount])
|
|
@@index([reviewCount])
|
|
@@index([importHealth])
|
|
@@index([executionHealth])
|
|
@@index([lastHealthCheck])
|
|
@@map("tools")
|
|
}
|
|
|
|
/// Sync checkpoints - tracks progress of sync workers
|
|
model SyncCheckpoint {
|
|
id String @id @default(cuid())
|
|
|
|
source String @unique @db.VarChar(50) // 'changes-feed' | 'keyword-search' | 'metrics'
|
|
checkpoint Json @db.JsonB // Stores last sequence, timestamp, etc.
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@map("sync_checkpoints")
|
|
}
|
|
|
|
/// Sync logs - audit trail of sync operations
|
|
model SyncLog {
|
|
id String @id @default(cuid())
|
|
|
|
source String @db.VarChar(50) // 'changes-feed' | 'keyword-search' | 'metrics'
|
|
status String @db.VarChar(20) // 'success' | 'error' | 'partial'
|
|
processed Int @default(0) // Number of packages processed
|
|
skipped Int @default(0) // Number of packages skipped
|
|
errors Int @default(0) // Number of errors encountered
|
|
message String? @db.Text // Error message or summary
|
|
metadata Json? @db.JsonB // Additional context
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@index([source])
|
|
@@index([status])
|
|
@@index([createdAt])
|
|
@@map("sync_logs")
|
|
}
|
|
|
|
/// Simulations - tracks tool playground executions
|
|
model Simulation {
|
|
id String @id @default(cuid())
|
|
|
|
// Relations
|
|
toolId String @map("tool_id")
|
|
tool Tool @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
|
|
|
// Request data
|
|
userPrompt String @map("user_prompt") @db.Text
|
|
parameters Json? @db.JsonB
|
|
ipAddress String? @map("ip_address") @db.VarChar(45)
|
|
userAgent String? @map("user_agent") @db.Text
|
|
|
|
// Results
|
|
status String @db.VarChar(20) // pending|running|success|error|timeout
|
|
executionTimeMs Int? @map("execution_time_ms")
|
|
output Json? @db.JsonB
|
|
error String? @db.Text
|
|
|
|
// AI metadata
|
|
agentSteps Int @default(0) @map("agent_steps")
|
|
model String? @db.VarChar(50)
|
|
|
|
// Relations
|
|
tokenUsage TokenUsage?
|
|
logs ExecutionLog[]
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
completedAt DateTime? @map("completed_at")
|
|
|
|
@@index([toolId])
|
|
@@index([status])
|
|
@@index([ipAddress, createdAt]) // For rate limiting
|
|
@@map("simulations")
|
|
}
|
|
|
|
/// Token usage - tracks token consumption per simulation
|
|
model TokenUsage {
|
|
id String @id @default(cuid())
|
|
|
|
simulationId String @unique @map("simulation_id")
|
|
simulation Simulation @relation(fields: [simulationId], references: [id], onDelete: Cascade)
|
|
|
|
inputTokens Int @default(0) @map("input_tokens")
|
|
toolDescTokens Int @default(0) @map("tool_desc_tokens")
|
|
schemaTokens Int @default(0) @map("schema_tokens")
|
|
outputTokens Int @default(0) @map("output_tokens")
|
|
totalTokens Int @default(0) @map("total_tokens")
|
|
estimatedCost Decimal? @map("estimated_cost") @db.Decimal(10, 6)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
@@map("token_usage")
|
|
}
|
|
|
|
/// Execution logs - detailed logs for each simulation
|
|
model ExecutionLog {
|
|
id String @id @default(cuid())
|
|
|
|
simulationId String @map("simulation_id")
|
|
simulation Simulation @relation(fields: [simulationId], references: [id], onDelete: Cascade)
|
|
|
|
timestamp DateTime @default(now())
|
|
level String @db.VarChar(20) // info|warning|error|debug
|
|
event String @db.VarChar(50)
|
|
message String @db.Text
|
|
metadata Json? @db.JsonB
|
|
|
|
@@index([simulationId])
|
|
@@map("execution_logs")
|
|
}
|
|
|
|
/// HealthCheck table - tracks full audit history of health checks
|
|
model HealthCheck {
|
|
id String @id @default(cuid())
|
|
|
|
// Relations
|
|
toolId String @map("tool_id")
|
|
tool Tool @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
|
|
|
// Check metadata
|
|
checkType HealthCheckType @map("check_type")
|
|
triggerSource String @map("trigger_source") @db.VarChar(50) // 'sync' | 'manual' | 'daily-cron'
|
|
|
|
// Import check results
|
|
importStatus HealthStatus @map("import_status")
|
|
importError String? @map("import_error") @db.Text
|
|
importTimeMs Int? @map("import_time_ms")
|
|
|
|
// Execution check results
|
|
executionStatus HealthStatus @map("execution_status")
|
|
executionError String? @map("execution_error") @db.Text
|
|
executionTimeMs Int? @map("execution_time_ms")
|
|
testParameters Json? @map("test_parameters") @db.JsonB
|
|
|
|
// Overall status
|
|
overallStatus HealthStatus @map("overall_status")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@index([toolId])
|
|
@@index([checkType])
|
|
@@index([overallStatus])
|
|
@@index([createdAt])
|
|
@@map("health_checks")
|
|
}
|
|
|
|
/// Health status enum - tracks health check results
|
|
enum HealthStatus {
|
|
UNKNOWN // Not yet checked
|
|
HEALTHY // Passed health check
|
|
BROKEN // Failed health check
|
|
}
|
|
|
|
/// Health check type enum - types of health checks performed
|
|
enum HealthCheckType {
|
|
IMPORT // Only import check
|
|
EXECUTION // Only execution check
|
|
FULL // Both import and execution
|
|
}
|
|
|
|
/// StatsSnapshot - daily snapshot of registry statistics for historical tracking
|
|
model StatsSnapshot {
|
|
id String @id @default(cuid())
|
|
|
|
// Snapshot date (one per day)
|
|
date DateTime @unique @db.Date
|
|
|
|
// Registry Overview
|
|
totalTools Int @default(0) @map("total_tools")
|
|
totalPackages Int @default(0) @map("total_packages")
|
|
officialTools Int @default(0) @map("official_tools")
|
|
officialPackages Int @default(0) @map("official_packages")
|
|
toolsWithSchema Int @default(0) @map("tools_with_schema")
|
|
|
|
// Downloads & Stars
|
|
totalNpmDownloads Int @default(0) @map("total_npm_downloads")
|
|
totalGithubStars Int @default(0) @map("total_github_stars")
|
|
|
|
// Health Status Counts
|
|
importHealthy Int @default(0) @map("import_healthy")
|
|
importBroken Int @default(0) @map("import_broken")
|
|
importUnknown Int @default(0) @map("import_unknown")
|
|
executionHealthy Int @default(0) @map("execution_healthy")
|
|
executionBroken Int @default(0) @map("execution_broken")
|
|
executionUnknown Int @default(0) @map("execution_unknown")
|
|
|
|
// Quality Distribution (stored as JSON for flexibility)
|
|
qualityDistribution Json? @map("quality_distribution") @db.JsonB
|
|
|
|
// Package Tiers
|
|
tiersMinimal Int @default(0) @map("tiers_minimal")
|
|
tiersRich Int @default(0) @map("tiers_rich")
|
|
|
|
// Execution Stats (daily)
|
|
executionsTotal Int @default(0) @map("executions_total")
|
|
executionsSuccessful Int @default(0) @map("executions_successful")
|
|
executionsFailed Int @default(0) @map("executions_failed")
|
|
executionsAvgTimeMs Int? @map("executions_avg_time_ms")
|
|
|
|
// Token Usage (daily)
|
|
tokensInput BigInt @default(0) @map("tokens_input")
|
|
tokensOutput BigInt @default(0) @map("tokens_output")
|
|
tokensTotal BigInt @default(0) @map("tokens_total")
|
|
tokensCostUsd Decimal? @map("tokens_cost_usd") @db.Decimal(10, 4)
|
|
|
|
// Health Checks (daily)
|
|
healthChecksRun Int @default(0) @map("health_checks_run")
|
|
|
|
// Category Breakdown (stored as JSON)
|
|
categories Json? @db.JsonB
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@index([date])
|
|
@@map("stats_snapshots")
|
|
}
|
|
|
|
// ============================================================================
|
|
// Better Auth Models
|
|
// ============================================================================
|
|
|
|
/// User table - stores authenticated users
|
|
model User {
|
|
id String @id @default(cuid())
|
|
name String
|
|
email String @unique
|
|
emailVerified Boolean @default(false) @map("email_verified")
|
|
image String?
|
|
username String? @unique @db.VarChar(30) // URL-friendly username (nullable for migration)
|
|
|
|
// Tier for rate limiting and feature access
|
|
tier UserTier @default(FREE)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
sessions Session[]
|
|
accounts Account[]
|
|
collections Collection[]
|
|
agents Agent[]
|
|
apiKeys UserApiKey[]
|
|
toolLikes ToolLike[]
|
|
toolRatings ToolRating[]
|
|
toolReviews ToolReview[]
|
|
collectionLikes CollectionLike[]
|
|
agentLikes AgentLike[]
|
|
activities UserActivity[]
|
|
bridgeConnection BridgeConnection?
|
|
tpmjsApiKeys TpmjsApiKey[] @relation("UserTpmjsApiKeys")
|
|
usageSummaries ApiUsageSummary[] @relation("UserUsageSummaries")
|
|
|
|
@@index([username])
|
|
@@map("users")
|
|
}
|
|
|
|
/// Session table - stores user sessions
|
|
model Session {
|
|
id String @id @default(cuid())
|
|
userId String @map("user_id")
|
|
token String @unique
|
|
expiresAt DateTime @map("expires_at")
|
|
ipAddress String? @map("ip_address")
|
|
userAgent String? @map("user_agent")
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@map("sessions")
|
|
}
|
|
|
|
/// Account table - stores auth provider accounts (including email/password)
|
|
model Account {
|
|
id String @id @default(cuid())
|
|
userId String @map("user_id")
|
|
accountId String @map("account_id")
|
|
providerId String @map("provider_id")
|
|
accessToken String? @map("access_token") @db.Text
|
|
refreshToken String? @map("refresh_token") @db.Text
|
|
idToken String? @map("id_token") @db.Text
|
|
expiresAt DateTime? @map("expires_at")
|
|
password String?
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@map("accounts")
|
|
}
|
|
|
|
/// Verification table - stores email verification tokens
|
|
model Verification {
|
|
id String @id @default(cuid())
|
|
identifier String
|
|
value String
|
|
expiresAt DateTime @map("expires_at")
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@map("verifications")
|
|
}
|
|
|
|
// ============================================================================
|
|
// Collection Models
|
|
// ============================================================================
|
|
|
|
/// Collection - user-created groups of tools
|
|
model Collection {
|
|
id String @id @default(cuid())
|
|
|
|
// Owner relationship
|
|
userId String @map("user_id")
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
// Collection metadata
|
|
name String @db.VarChar(100)
|
|
slug String? @db.VarChar(50) // URL-friendly identifier (nullable for migration)
|
|
description String? @db.VarChar(500)
|
|
isPublic Boolean @default(false) @map("is_public")
|
|
likeCount Int @default(0) @map("like_count")
|
|
|
|
// Executor configuration (optional - uses system default if not set)
|
|
executorType String? @map("executor_type") @db.VarChar(50)
|
|
executorConfig Json? @map("executor_config") @db.JsonB
|
|
|
|
// Tool environment variables (encrypted JSON: { "KEY": "value" })
|
|
// These are passed to tools when executed
|
|
envVars Json? @map("env_vars") @db.JsonB
|
|
|
|
// Fork tracking - for "fork to use" model
|
|
forkedFromId String? @map("forked_from_id")
|
|
forkedFrom Collection? @relation("CollectionForks", fields: [forkedFromId], references: [id], onDelete: SetNull)
|
|
forks Collection[] @relation("CollectionForks")
|
|
forkCount Int @default(0) @map("fork_count")
|
|
|
|
// AI-generated use cases
|
|
useCases Json? @map("use_cases") @db.JsonB
|
|
useCasesGeneratedAt DateTime? @map("use_cases_generated_at")
|
|
|
|
// AI-generated skills documentation
|
|
skillsMarkdown String? @map("skills_markdown") @db.Text
|
|
skillsGeneratedAt DateTime? @map("skills_generated_at")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relations
|
|
tools CollectionTool[]
|
|
agents AgentCollection[]
|
|
likes CollectionLike[]
|
|
bridgeTools CollectionBridgeTool[]
|
|
scenarios Scenario[]
|
|
skillsGenerationJobs SkillsGenerationJob[]
|
|
|
|
// Unique constraint: user can't have duplicate collection slugs
|
|
@@unique([userId, slug])
|
|
@@index([userId])
|
|
@@index([slug])
|
|
@@index([isPublic])
|
|
@@index([likeCount])
|
|
@@index([createdAt])
|
|
@@index([forkedFromId])
|
|
@@index([forkCount])
|
|
@@map("collections")
|
|
}
|
|
|
|
/// CollectionTool - junction table for many-to-many relationship between collections and tools
|
|
model CollectionTool {
|
|
id String @id @default(cuid())
|
|
|
|
// Relationships
|
|
collectionId String @map("collection_id")
|
|
collection Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)
|
|
toolId String @map("tool_id")
|
|
tool Tool @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
|
|
|
// Ordering - allows users to reorder tools within a collection
|
|
position Int @default(0)
|
|
|
|
// Optional user notes about why this tool is in the collection
|
|
note String? @db.VarChar(500)
|
|
|
|
// Timestamps
|
|
addedAt DateTime @default(now()) @map("added_at")
|
|
|
|
// Unique constraint: tool can only be in a collection once
|
|
@@unique([collectionId, toolId])
|
|
@@index([collectionId])
|
|
@@index([toolId])
|
|
@@map("collection_tools")
|
|
}
|
|
|
|
// ============================================================================
|
|
// Agent Models
|
|
// ============================================================================
|
|
|
|
/// AI Provider enum - supported LLM providers
|
|
enum AIProvider {
|
|
OPENAI
|
|
ANTHROPIC
|
|
GOOGLE
|
|
GROQ
|
|
MISTRAL
|
|
}
|
|
|
|
/// Message role enum - conversation message types
|
|
enum MessageRole {
|
|
USER
|
|
ASSISTANT
|
|
TOOL
|
|
SYSTEM
|
|
}
|
|
|
|
/// Agent - user-owned AI agent configurations
|
|
model Agent {
|
|
id String @id @default(cuid())
|
|
|
|
// Owner relationship
|
|
userId String @map("user_id")
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
// Agent identity
|
|
uid String @unique @db.VarChar(50) // URL-friendly identifier
|
|
name String @db.VarChar(100)
|
|
description String? @db.VarChar(500)
|
|
|
|
// Model configuration
|
|
provider AIProvider
|
|
modelId String @map("model_id") @db.VarChar(100)
|
|
systemPrompt String? @map("system_prompt") @db.Text
|
|
temperature Float @default(0.7)
|
|
maxToolCallsPerTurn Int @default(20) @map("max_tool_calls_per_turn")
|
|
maxMessagesInContext Int @default(10) @map("max_messages_in_context")
|
|
|
|
// Visibility
|
|
isPublic Boolean @default(true) @map("is_public")
|
|
likeCount Int @default(0) @map("like_count")
|
|
|
|
// Executor configuration (optional - uses system default if not set)
|
|
// Agent executor overrides collection executor overrides system default
|
|
executorType String? @map("executor_type") @db.VarChar(50)
|
|
executorConfig Json? @map("executor_config") @db.JsonB
|
|
|
|
// Tool environment variables (encrypted JSON: { "KEY": "value" })
|
|
// Agent env vars override collection env vars, otherwise merged
|
|
envVars Json? @map("env_vars") @db.JsonB
|
|
|
|
// Fork tracking - for "fork to use" model
|
|
forkedFromId String? @map("forked_from_id")
|
|
forkedFrom Agent? @relation("AgentForks", fields: [forkedFromId], references: [id], onDelete: SetNull)
|
|
forks Agent[] @relation("AgentForks")
|
|
forkCount Int @default(0) @map("fork_count")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relations
|
|
collections AgentCollection[]
|
|
tools AgentTool[]
|
|
conversations Conversation[]
|
|
likes AgentLike[]
|
|
|
|
@@unique([userId, name])
|
|
@@index([userId])
|
|
@@index([uid])
|
|
@@index([isPublic])
|
|
@@index([likeCount])
|
|
@@index([createdAt])
|
|
@@index([forkedFromId])
|
|
@@index([forkCount])
|
|
@@map("agents")
|
|
}
|
|
|
|
/// AgentCollection - junction table for Agent -> Collection (many-to-many)
|
|
model AgentCollection {
|
|
id String @id @default(cuid())
|
|
|
|
// Relationships
|
|
agentId String @map("agent_id")
|
|
agent Agent @relation(fields: [agentId], references: [id], onDelete: Cascade)
|
|
collectionId String @map("collection_id")
|
|
collection Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)
|
|
|
|
// Ordering
|
|
position Int @default(0)
|
|
|
|
// Timestamps
|
|
addedAt DateTime @default(now()) @map("added_at")
|
|
|
|
@@unique([agentId, collectionId])
|
|
@@index([agentId])
|
|
@@index([collectionId])
|
|
@@map("agent_collections")
|
|
}
|
|
|
|
/// AgentTool - junction table for Agent -> Tool (many-to-many)
|
|
model AgentTool {
|
|
id String @id @default(cuid())
|
|
|
|
// Relationships
|
|
agentId String @map("agent_id")
|
|
agent Agent @relation(fields: [agentId], references: [id], onDelete: Cascade)
|
|
toolId String @map("tool_id")
|
|
tool Tool @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
|
|
|
// Ordering
|
|
position Int @default(0)
|
|
|
|
// Timestamps
|
|
addedAt DateTime @default(now()) @map("added_at")
|
|
|
|
@@unique([agentId, toolId])
|
|
@@index([agentId])
|
|
@@index([toolId])
|
|
@@map("agent_tools")
|
|
}
|
|
|
|
/// UserApiKey - encrypted API keys/env vars per user
|
|
model UserApiKey {
|
|
id String @id @default(cuid())
|
|
|
|
// Owner relationship
|
|
userId String @map("user_id")
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
// Key identification (e.g. OPENAI_API_KEY, MY_SECRET, etc.)
|
|
keyName String @map("key_name") @db.VarChar(100)
|
|
|
|
// Encrypted key storage
|
|
encryptedKey String @map("encrypted_key") @db.Text
|
|
keyIv String @map("key_iv") @db.VarChar(32)
|
|
keyHint String? @map("key_hint") @db.VarChar(10) // Last 4 chars
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@unique([userId, keyName])
|
|
@@index([userId])
|
|
@@map("user_api_keys")
|
|
}
|
|
|
|
/// Conversation - chat session with an agent
|
|
model Conversation {
|
|
id String @id @default(cuid())
|
|
|
|
// Agent relationship
|
|
agentId String @map("agent_id")
|
|
agent Agent @relation(fields: [agentId], references: [id], onDelete: Cascade)
|
|
|
|
// Conversation identity
|
|
slug String @db.VarChar(100) // User-chosen unique ID
|
|
|
|
// Metadata
|
|
title String? @db.VarChar(200)
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relations
|
|
messages Message[]
|
|
|
|
@@unique([agentId, slug])
|
|
@@index([agentId])
|
|
@@index([createdAt])
|
|
@@map("conversations")
|
|
}
|
|
|
|
/// Message - individual message in a conversation
|
|
model Message {
|
|
id String @id @default(cuid())
|
|
|
|
// Conversation relationship
|
|
conversationId String @map("conversation_id")
|
|
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
|
|
|
|
// Message content
|
|
role MessageRole
|
|
content String @db.Text
|
|
|
|
// Tool call metadata (for role=ASSISTANT with tool calls)
|
|
toolCalls Json? @map("tool_calls") @db.JsonB
|
|
|
|
// Tool result metadata (for role=TOOL)
|
|
toolCallId String? @map("tool_call_id") @db.VarChar(100)
|
|
toolName String? @map("tool_name") @db.VarChar(200)
|
|
toolResult Json? @map("tool_result") @db.JsonB
|
|
|
|
// Token tracking
|
|
inputTokens Int? @map("input_tokens")
|
|
outputTokens Int? @map("output_tokens")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@index([conversationId])
|
|
@@index([createdAt])
|
|
@@map("messages")
|
|
}
|
|
|
|
// ============================================================================
|
|
// Like Models
|
|
// ============================================================================
|
|
|
|
/// ToolLike - tracks users who liked a tool
|
|
model ToolLike {
|
|
id String @id @default(cuid())
|
|
|
|
// Relationships
|
|
userId String @map("user_id")
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
toolId String @map("tool_id")
|
|
tool Tool @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@unique([userId, toolId])
|
|
@@index([toolId])
|
|
@@index([userId])
|
|
@@map("tool_likes")
|
|
}
|
|
|
|
/// CollectionLike - tracks users who liked a collection
|
|
model CollectionLike {
|
|
id String @id @default(cuid())
|
|
|
|
// Relationships
|
|
userId String @map("user_id")
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
collectionId String @map("collection_id")
|
|
collection Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@unique([userId, collectionId])
|
|
@@index([collectionId])
|
|
@@index([userId])
|
|
@@map("collection_likes")
|
|
}
|
|
|
|
/// AgentLike - tracks users who liked an agent
|
|
model AgentLike {
|
|
id String @id @default(cuid())
|
|
|
|
// Relationships
|
|
userId String @map("user_id")
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
agentId String @map("agent_id")
|
|
agent Agent @relation(fields: [agentId], references: [id], onDelete: Cascade)
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@unique([userId, agentId])
|
|
@@index([agentId])
|
|
@@index([userId])
|
|
@@map("agent_likes")
|
|
}
|
|
|
|
/// ToolRating - user ratings for tools (1-5 stars)
|
|
model ToolRating {
|
|
id String @id @default(cuid())
|
|
|
|
// Relationships
|
|
userId String @map("user_id")
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
toolId String @map("tool_id")
|
|
tool Tool @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
|
|
|
// Rating value (1-5)
|
|
rating Int @db.SmallInt
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@unique([userId, toolId])
|
|
@@index([toolId])
|
|
@@index([userId])
|
|
@@index([rating])
|
|
@@map("tool_ratings")
|
|
}
|
|
|
|
/// ToolReview - user reviews for tools
|
|
model ToolReview {
|
|
id String @id @default(cuid())
|
|
|
|
// Relationships
|
|
userId String @map("user_id")
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
toolId String @map("tool_id")
|
|
tool Tool @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
|
|
|
// Review content
|
|
title String? @db.VarChar(200)
|
|
content String @db.Text
|
|
rating Int @db.SmallInt // 1-5, denormalized for convenience
|
|
|
|
// Moderation
|
|
isApproved Boolean @default(true) @map("is_approved")
|
|
isHidden Boolean @default(false) @map("is_hidden")
|
|
|
|
// Helpful votes
|
|
helpfulCount Int @default(0) @map("helpful_count")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@unique([userId, toolId])
|
|
@@index([toolId])
|
|
@@index([userId])
|
|
@@index([rating])
|
|
@@index([isApproved, isHidden])
|
|
@@index([createdAt])
|
|
@@map("tool_reviews")
|
|
}
|
|
|
|
// ============================================================================
|
|
// Activity Stream Models
|
|
// ============================================================================
|
|
|
|
/// Activity type enum - types of user activities tracked
|
|
enum ActivityType {
|
|
AGENT_CREATED
|
|
AGENT_UPDATED
|
|
AGENT_DELETED
|
|
AGENT_CLONED
|
|
AGENT_FORKED
|
|
AGENT_TOOL_ADDED
|
|
AGENT_TOOL_REMOVED
|
|
AGENT_COLLECTION_ADDED
|
|
AGENT_COLLECTION_REMOVED
|
|
COLLECTION_CREATED
|
|
COLLECTION_UPDATED
|
|
COLLECTION_DELETED
|
|
COLLECTION_CLONED
|
|
COLLECTION_FORKED
|
|
COLLECTION_TOOL_ADDED
|
|
COLLECTION_TOOL_REMOVED
|
|
TOOL_LIKED
|
|
TOOL_UNLIKED
|
|
COLLECTION_LIKED
|
|
COLLECTION_UNLIKED
|
|
AGENT_LIKED
|
|
AGENT_UNLIKED
|
|
}
|
|
|
|
/// UserActivity - tracks user actions for activity stream
|
|
model UserActivity {
|
|
id String @id @default(cuid())
|
|
|
|
// Owner relationship
|
|
userId String @map("user_id")
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
// Activity type
|
|
type ActivityType
|
|
|
|
// Optional entity references (for linking to entities if they still exist)
|
|
agentId String? @map("agent_id")
|
|
collectionId String? @map("collection_id")
|
|
toolId String? @map("tool_id")
|
|
|
|
// Denormalized fields (stored at creation time for display even after entity deletion)
|
|
targetName String @map("target_name") @db.VarChar(200)
|
|
targetType String @map("target_type") @db.VarChar(50) // 'agent' | 'collection' | 'tool'
|
|
|
|
// Additional context (e.g., toolName when adding to collection)
|
|
metadata Json? @db.JsonB
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@index([userId])
|
|
@@index([userId, createdAt])
|
|
@@index([type])
|
|
@@index([createdAt])
|
|
@@map("user_activities")
|
|
}
|
|
|
|
// ============================================================================
|
|
// Endpoint Health Monitoring Models
|
|
// ============================================================================
|
|
|
|
/// EndpointHealthReport - stores health check results from GitHub Actions or other monitoring
|
|
model EndpointHealthReport {
|
|
id String @id @default(cuid())
|
|
|
|
// Report metadata
|
|
timestamp DateTime
|
|
source String @db.VarChar(50) // 'github-actions' | 'manual' | 'uptime-robot' etc.
|
|
runId String? @map("run_id") @db.VarChar(100) // GitHub Actions run ID
|
|
|
|
// Check results
|
|
checks Json @db.JsonB // { check_name: 'pass' | 'fail' }
|
|
passCount Int @map("pass_count")
|
|
failCount Int @map("fail_count")
|
|
totalChecks Int @map("total_checks")
|
|
overallStatus String @map("overall_status") @db.VarChar(20) // 'healthy' | 'degraded' | 'down'
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@index([timestamp])
|
|
@@index([overallStatus])
|
|
@@index([source])
|
|
@@map("endpoint_health_reports")
|
|
}
|
|
|
|
// ============================================================================
|
|
// MCP Bridge Models
|
|
// ============================================================================
|
|
|
|
/// BridgeConnection - tracks active bridge connections from users
|
|
model BridgeConnection {
|
|
id String @id @default(cuid())
|
|
|
|
// Owner relationship
|
|
userId String @unique @map("user_id")
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
// Connection state
|
|
status String @default("disconnected") @db.VarChar(20) // 'connected' | 'disconnected'
|
|
socketId String? @map("socket_id") @db.VarChar(100) // Internal socket identifier for routing
|
|
|
|
// Cached tool definitions from bridge
|
|
tools Json @default("[]") @db.JsonB
|
|
|
|
// Metadata
|
|
lastSeen DateTime? @map("last_seen")
|
|
clientVersion String? @map("client_version") @db.VarChar(20)
|
|
clientOS String? @map("client_os") @db.VarChar(50)
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@index([status])
|
|
@@map("bridge_connections")
|
|
}
|
|
|
|
/// CollectionBridgeTool - tracks which bridge tools are added to collections
|
|
model CollectionBridgeTool {
|
|
id String @id @default(cuid())
|
|
|
|
// Collection relationship
|
|
collectionId String @map("collection_id")
|
|
collection Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)
|
|
|
|
// Bridge tool reference
|
|
serverId String @map("server_id") @db.VarChar(100) // e.g., "chrome-devtools"
|
|
toolName String @map("tool_name") @db.VarChar(100) // e.g., "screenshot"
|
|
|
|
// Display customization
|
|
displayName String? @map("display_name") @db.VarChar(100) // Override tool name in MCP
|
|
note String? @db.VarChar(500) // User notes
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@unique([collectionId, serverId, toolName])
|
|
@@index([collectionId])
|
|
@@map("collection_bridge_tools")
|
|
}
|
|
|
|
// ============================================================================
|
|
// API Key & Usage Tracking Models
|
|
// ============================================================================
|
|
|
|
/// User tier enum - determines rate limits and feature access
|
|
enum UserTier {
|
|
FREE
|
|
PRO
|
|
ENTERPRISE
|
|
}
|
|
|
|
/// TpmjsApiKey - user-owned API keys for programmatic access
|
|
model TpmjsApiKey {
|
|
id String @id @default(cuid())
|
|
|
|
// Owner relationship
|
|
userId String @map("user_id")
|
|
user User @relation("UserTpmjsApiKeys", fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
// Key identification
|
|
name String @db.VarChar(100) // User-provided name (e.g., "Production Server")
|
|
keyHash String @unique @map("key_hash") @db.VarChar(64) // SHA-256 hash (never store raw keys)
|
|
keyPrefix String @map("key_prefix") @db.VarChar(20) // First 16 chars for identification (tpmjs_sk_abc123...)
|
|
|
|
// Permissions
|
|
scopes String[] @default([]) // ["mcp:execute", "agent:chat", "bridge:connect", "usage:read"]
|
|
|
|
// Rate limiting (overrides tier default if set)
|
|
rateLimit Int? @map("rate_limit") // Requests per hour (null = use tier default)
|
|
|
|
// Status
|
|
isActive Boolean @default(true) @map("is_active")
|
|
lastUsedAt DateTime? @map("last_used_at")
|
|
expiresAt DateTime? @map("expires_at")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relations
|
|
usageRecords ApiUsageRecord[]
|
|
|
|
@@index([userId])
|
|
@@index([keyHash])
|
|
@@index([keyPrefix])
|
|
@@index([isActive])
|
|
@@map("tpmjs_api_keys")
|
|
}
|
|
|
|
/// ApiUsageRecord - individual API request logs (kept for 30 days)
|
|
model ApiUsageRecord {
|
|
id String @id @default(cuid())
|
|
|
|
// API key relationship
|
|
apiKeyId String @map("api_key_id")
|
|
apiKey TpmjsApiKey @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)
|
|
|
|
// Request details
|
|
endpoint String @db.VarChar(500)
|
|
method String @db.VarChar(10) // GET, POST, etc.
|
|
statusCode Int @map("status_code")
|
|
latencyMs Int @map("latency_ms")
|
|
|
|
// Resource tracking
|
|
resourceType String? @map("resource_type") @db.VarChar(50) // "mcp" | "agent" | "bridge" | "collection"
|
|
resourceId String? @map("resource_id") @db.VarChar(100) // Collection ID, Agent ID, etc.
|
|
|
|
// LLM usage (if applicable)
|
|
tokensIn Int? @map("tokens_in")
|
|
tokensOut Int? @map("tokens_out")
|
|
model String? @db.VarChar(50) // e.g., "gpt-4o-mini"
|
|
|
|
// Error tracking
|
|
errorCode String? @map("error_code") @db.VarChar(50)
|
|
errorMessage String? @map("error_message") @db.Text
|
|
|
|
// Client metadata
|
|
userAgent String? @map("user_agent") @db.VarChar(500)
|
|
ipAddress String? @map("ip_address") @db.VarChar(45) // IPv4 or IPv6
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@index([apiKeyId])
|
|
@@index([createdAt])
|
|
@@index([endpoint])
|
|
@@index([resourceType, resourceId])
|
|
@@map("api_usage_records")
|
|
}
|
|
|
|
/// ApiUsageSummary - aggregated usage summaries (hourly/daily rollups)
|
|
model ApiUsageSummary {
|
|
id String @id @default(cuid())
|
|
|
|
// User relationship
|
|
userId String @map("user_id")
|
|
user User @relation("UserUsageSummaries", fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
// Optional API key (null for user-level summaries)
|
|
apiKeyId String? @map("api_key_id")
|
|
|
|
// Time period
|
|
periodType String @map("period_type") @db.VarChar(20) // "hourly" | "daily" | "monthly"
|
|
periodStart DateTime @map("period_start")
|
|
|
|
// Request counts
|
|
totalRequests Int @default(0) @map("total_requests")
|
|
successRequests Int @default(0) @map("success_requests")
|
|
errorRequests Int @default(0) @map("error_requests")
|
|
|
|
// Endpoint breakdown (JSON: { "/api/mcp/...": 100, ... })
|
|
endpointCounts Json @default("{}") @map("endpoint_counts") @db.JsonB
|
|
|
|
// LLM usage totals
|
|
totalTokensIn Int @default(0) @map("total_tokens_in")
|
|
totalTokensOut Int @default(0) @map("total_tokens_out")
|
|
|
|
// Performance
|
|
avgLatencyMs Float @default(0) @map("avg_latency_ms")
|
|
p95LatencyMs Float @default(0) @map("p95_latency_ms")
|
|
|
|
// Cost estimation (in cents)
|
|
estimatedCostCents Int @default(0) @map("estimated_cost_cents")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@unique([userId, apiKeyId, periodType, periodStart])
|
|
@@index([userId])
|
|
@@index([periodType, periodStart])
|
|
@@map("api_usage_summaries")
|
|
}
|
|
|
|
// ============================================================================
|
|
// Scenario Models (Integration Testing for Collections)
|
|
// ============================================================================
|
|
|
|
/// Scenario - AI-generated test scenarios for collections
|
|
model Scenario {
|
|
id String @id @default(cuid())
|
|
|
|
// Collection relationship (nullable for orphaned scenarios)
|
|
collectionId String? @map("collection_id")
|
|
collection Collection? @relation(fields: [collectionId], references: [id], onDelete: SetNull)
|
|
|
|
// Content
|
|
prompt String @db.Text // AI-generated free-form prompt
|
|
name String? @db.VarChar(200) // Optional human-readable name
|
|
description String? @db.Text
|
|
|
|
// Validation (optional assertions)
|
|
assertions Json? @db.JsonB // { regex?: string[], schema?: object }
|
|
|
|
// AI-generated metadata
|
|
tags String[] @default([]) @db.Text
|
|
|
|
// Quality metrics (streak-based scoring)
|
|
qualityScore Float @default(0) @map("quality_score")
|
|
consecutivePasses Int @default(0) @map("consecutive_passes")
|
|
consecutiveFails Int @default(0) @map("consecutive_fails")
|
|
totalRuns Int @default(0) @map("total_runs")
|
|
lastRunAt DateTime? @map("last_run_at")
|
|
lastRunStatus String? @map("last_run_status") @db.VarChar(20) // 'pass' | 'fail' | 'error'
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relations
|
|
runs ScenarioRun[]
|
|
embedding ScenarioEmbedding?
|
|
useCase UseCase?
|
|
|
|
@@index([collectionId])
|
|
@@index([qualityScore])
|
|
@@index([createdAt])
|
|
@@index([lastRunStatus])
|
|
@@map("scenarios")
|
|
}
|
|
|
|
/// ScenarioEmbedding - vector embeddings for scenario similarity detection
|
|
model ScenarioEmbedding {
|
|
id String @id @default(cuid())
|
|
|
|
// Scenario relationship
|
|
scenarioId String @unique @map("scenario_id")
|
|
scenario Scenario @relation(fields: [scenarioId], references: [id], onDelete: Cascade)
|
|
|
|
// Embedding data
|
|
embedding Json @db.JsonB // Array of floats (1536 dims for text-embedding-3-small)
|
|
model String @default("text-embedding-3-small") @db.VarChar(50)
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@index([scenarioId])
|
|
@@map("scenario_embeddings")
|
|
}
|
|
|
|
/// ScenarioRun - individual execution records for scenarios
|
|
model ScenarioRun {
|
|
id String @id @default(cuid())
|
|
|
|
// Scenario relationship
|
|
scenarioId String @map("scenario_id")
|
|
scenario Scenario @relation(fields: [scenarioId], references: [id], onDelete: Cascade)
|
|
|
|
// Execution context
|
|
userId String @map("user_id") // Who triggered the run
|
|
agentId String? @map("agent_id") // Ephemeral agent ID (for debugging)
|
|
|
|
// Status
|
|
status String @db.VarChar(20) // 'pending' | 'running' | 'pass' | 'fail' | 'error'
|
|
retryCount Int @default(0) @map("retry_count")
|
|
|
|
// Results
|
|
conversation Json? @db.JsonB // Full message history
|
|
output String? @db.Text // Final output from agent
|
|
errorLog String? @map("error_log") @db.Text // Full error logs (private to owner)
|
|
|
|
// LLM Evaluation
|
|
evaluatorModel String? @map("evaluator_model") @db.VarChar(50) // e.g., "claude-3.5-sonnet"
|
|
evaluatorVerdict String? @map("evaluator_verdict") @db.VarChar(10) // 'pass' | 'fail'
|
|
evaluatorReason String? @map("evaluator_reason") @db.Text // Explanation
|
|
|
|
// Assertions
|
|
assertionResults Json? @map("assertion_results") @db.JsonB // { passed: string[], failed: string[] }
|
|
|
|
// Cost tracking
|
|
inputTokens Int? @map("input_tokens")
|
|
outputTokens Int? @map("output_tokens")
|
|
totalTokens Int? @map("total_tokens")
|
|
executionTimeMs Int? @map("execution_time_ms")
|
|
estimatedCost Decimal? @map("estimated_cost") @db.Decimal(10, 6)
|
|
|
|
// Timestamps
|
|
startedAt DateTime? @map("started_at")
|
|
completedAt DateTime? @map("completed_at")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@index([scenarioId])
|
|
@@index([userId])
|
|
@@index([status])
|
|
@@index([createdAt])
|
|
@@map("scenario_runs")
|
|
}
|
|
|
|
/// ScenarioQuota - daily usage quotas for scenario runs
|
|
model ScenarioQuota {
|
|
id String @id @default(cuid())
|
|
|
|
// User relationship
|
|
userId String @unique @map("user_id")
|
|
|
|
// Quota configuration
|
|
dailyLimit Int @default(50) @map("daily_limit") // Runs per day
|
|
dailyUsed Int @default(0) @map("daily_used")
|
|
lastResetAt DateTime @default(now()) @map("last_reset_at")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@index([userId])
|
|
@@map("scenario_quotas")
|
|
}
|
|
|
|
// ============================================================================
|
|
// Use Cases Models (Marketing Content from Scenarios)
|
|
// ============================================================================
|
|
|
|
/// Persona - user personas for use case targeting (AI-populated)
|
|
model Persona {
|
|
id String @id @default(cuid())
|
|
name String @unique @db.VarChar(100)
|
|
slug String @unique @db.VarChar(100)
|
|
description String? @db.Text
|
|
icon String? @db.VarChar(50) // emoji or icon name
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
// Relations
|
|
useCases UseCasePersona[]
|
|
|
|
@@index([slug])
|
|
@@map("personas")
|
|
}
|
|
|
|
/// Industry - industries for use case categorization (AI-populated)
|
|
model Industry {
|
|
id String @id @default(cuid())
|
|
name String @unique @db.VarChar(100)
|
|
slug String @unique @db.VarChar(100)
|
|
description String? @db.Text
|
|
icon String? @db.VarChar(50)
|
|
parentId String? @map("parent_id")
|
|
parent Industry? @relation("IndustryHierarchy", fields: [parentId], references: [id])
|
|
children Industry[] @relation("IndustryHierarchy")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
// Relations
|
|
useCases UseCaseIndustry[]
|
|
|
|
@@index([parentId])
|
|
@@index([slug])
|
|
@@map("industries")
|
|
}
|
|
|
|
/// Category - categories for use case organization (AI-populated)
|
|
model Category {
|
|
id String @id @default(cuid())
|
|
name String @unique @db.VarChar(100)
|
|
slug String @unique @db.VarChar(100)
|
|
type String @map("type") @db.VarChar(50) // 'functional', 'business-process', 'technical'
|
|
description String? @db.Text
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
// Relations
|
|
useCases UseCaseCategory[]
|
|
|
|
@@index([type])
|
|
@@index([slug])
|
|
@@map("categories")
|
|
}
|
|
|
|
/// UseCase - auto-generated marketing content from qualifying scenarios
|
|
model UseCase {
|
|
id String @id @default(cuid())
|
|
scenarioId String @unique @map("scenario_id")
|
|
scenario Scenario @relation(fields: [scenarioId], references: [id], onDelete: Cascade)
|
|
|
|
// SEO-friendly slug
|
|
slug String @db.VarChar(200)
|
|
|
|
// AI-generated marketing content
|
|
marketingTitle String @map("marketing_title") @db.VarChar(200)
|
|
marketingDesc String @map("marketing_desc") @db.Text
|
|
roiEstimate String? @map("roi_estimate") @db.Text // "Saves ~10 hours/week"
|
|
businessValue String? @map("business_value") @db.Text // Human-readable benefit
|
|
problemStatement String? @map("problem_statement") @db.Text // What problem it solves
|
|
solutionNarrative String? @map("solution_narrative") @db.Text // How it works
|
|
|
|
// Ranking (computed nightly)
|
|
rankScore Float @default(0) @map("rank_score")
|
|
lastRankedAt DateTime @map("last_ranked_at")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
lastRegeneratedAt DateTime? @map("last_regenerated_at")
|
|
|
|
// Relations
|
|
personas UseCasePersona[]
|
|
industries UseCaseIndustry[]
|
|
categories UseCaseCategory[]
|
|
socialProof SocialProof?
|
|
|
|
@@index([scenarioId])
|
|
@@index([slug])
|
|
@@index([rankScore])
|
|
@@index([lastRankedAt])
|
|
@@index([lastRegeneratedAt])
|
|
@@map("use_cases")
|
|
}
|
|
|
|
/// UseCasePersona - junction table for UseCase <-> Persona
|
|
model UseCasePersona {
|
|
useCaseId String @map("use_case_id")
|
|
personaId String @map("persona_id")
|
|
useCase UseCase @relation(fields: [useCaseId], references: [id], onDelete: Cascade)
|
|
persona Persona @relation(fields: [personaId], references: [id], onDelete: Cascade)
|
|
relevance Float? @map("relevance") // Future: relevance score for this persona
|
|
|
|
@@id([useCaseId, personaId])
|
|
@@index([useCaseId])
|
|
@@index([personaId])
|
|
@@map("use_case_personas")
|
|
}
|
|
|
|
/// UseCaseIndustry - junction table for UseCase <-> Industry
|
|
model UseCaseIndustry {
|
|
useCaseId String @map("use_case_id")
|
|
industryId String @map("industry_id")
|
|
useCase UseCase @relation(fields: [useCaseId], references: [id], onDelete: Cascade)
|
|
industry Industry @relation(fields: [industryId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([useCaseId, industryId])
|
|
@@index([useCaseId])
|
|
@@index([industryId])
|
|
@@map("use_case_industries")
|
|
}
|
|
|
|
/// UseCaseCategory - junction table for UseCase <-> Category
|
|
model UseCaseCategory {
|
|
useCaseId String @map("use_case_id")
|
|
categoryId String @map("category_id")
|
|
useCase UseCase @relation(fields: [useCaseId], references: [id], onDelete: Cascade)
|
|
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([useCaseId, categoryId])
|
|
@@index([useCaseId])
|
|
@@index([categoryId])
|
|
@@map("use_case_categories")
|
|
}
|
|
|
|
/// SocialProof - cached metrics from scenario runs for use cases
|
|
model SocialProof {
|
|
id String @id @default(cuid())
|
|
useCaseId String @unique @map("use_case_id")
|
|
useCase UseCase @relation(fields: [useCaseId], references: [id], onDelete: Cascade)
|
|
|
|
qualityScore Float @map("quality_score")
|
|
totalRuns Int @map("total_runs")
|
|
consecutivePasses Int @map("consecutive_passes")
|
|
lastRunStatus String? @map("last_run_status") @db.VarChar(20)
|
|
lastRunAt DateTime? @map("last_run_at")
|
|
|
|
// Computed display fields
|
|
successRate Float? @map("success_rate")
|
|
lastRunAgo String? @map("last_run_ago") // "2 days ago"
|
|
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@index([useCaseId])
|
|
@@index([qualityScore])
|
|
@@index([totalRuns])
|
|
@@map("social_proofs")
|
|
}
|
|
|
|
// ============================================================================
|
|
// Skills Generation Models (Chunked Generation for Large Collections)
|
|
// ============================================================================
|
|
|
|
/// ToolSkillsCache - per-tool cached skills markdown section
|
|
model ToolSkillsCache {
|
|
id String @id @default(cuid())
|
|
|
|
// Tool relationship
|
|
toolId String @unique @map("tool_id")
|
|
tool Tool @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
|
|
|
// Cached markdown section for this tool
|
|
skillsMarkdown String @map("skills_markdown") @db.Text
|
|
|
|
// Timestamps
|
|
generatedAt DateTime @default(now()) @map("generated_at")
|
|
|
|
@@index([toolId])
|
|
@@map("tool_skills_cache")
|
|
}
|
|
|
|
/// SkillsGenerationJob - tracks chunked skills.md generation progress
|
|
model SkillsGenerationJob {
|
|
id String @id @default(cuid())
|
|
|
|
// Collection relationship
|
|
collectionId String @map("collection_id")
|
|
collection Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)
|
|
|
|
// Job status
|
|
status String @default("pending") @db.VarChar(20) // 'pending' | 'processing' | 'completed' | 'failed'
|
|
|
|
// Progress tracking
|
|
currentBatch Int @default(0) @map("current_batch")
|
|
totalBatches Int @map("total_batches")
|
|
completedToolIds String[] @default([]) @map("completed_tool_ids")
|
|
|
|
// Error tracking
|
|
error String? @db.Text
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@index([collectionId])
|
|
@@index([status])
|
|
@@map("skills_generation_jobs")
|
|
}
|
|
|
|
// ============================================================================
|
|
// Omega Models (AI Agent Chat with Full Registry Access)
|
|
// ============================================================================
|
|
|
|
/// OmegaConversation - chat session for Omega AI agent
|
|
model OmegaConversation {
|
|
id String @id @default(cuid())
|
|
|
|
// Owner relationship
|
|
ownerId String @map("owner_id")
|
|
|
|
// Conversation metadata
|
|
title String? @db.VarChar(200)
|
|
|
|
// Execution state
|
|
executionState String @default("idle") @map("execution_state") @db.VarChar(20) // idle, running, paused, cancelled
|
|
|
|
// Token tracking (aggregate across all messages)
|
|
inputTokensTotal Int @default(0) @map("input_tokens_total")
|
|
outputTokensTotal Int @default(0) @map("output_tokens_total")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relations
|
|
messages OmegaMessage[]
|
|
participants OmegaParticipant[]
|
|
toolRuns OmegaToolRun[]
|
|
|
|
@@index([ownerId])
|
|
@@index([createdAt])
|
|
@@map("omega_conversations")
|
|
}
|
|
|
|
/// OmegaMessage - individual message in an Omega conversation
|
|
model OmegaMessage {
|
|
id String @id @default(cuid())
|
|
|
|
// Conversation relationship
|
|
conversationId String @map("conversation_id")
|
|
conversation OmegaConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
|
|
|
|
// Message content
|
|
role MessageRole
|
|
content String @db.Text
|
|
|
|
// Author info (for multi-user conversations)
|
|
authorId String? @map("author_id")
|
|
authorEmail String? @map("author_email")
|
|
authorName String? @map("author_name") @db.VarChar(100)
|
|
|
|
// Tool calls (for ASSISTANT messages)
|
|
toolCalls Json? @map("tool_calls") @db.JsonB
|
|
|
|
// Token tracking
|
|
inputTokens Int? @map("input_tokens")
|
|
outputTokens Int? @map("output_tokens")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@index([conversationId])
|
|
@@index([createdAt])
|
|
@@map("omega_messages")
|
|
}
|
|
|
|
/// OmegaParticipant - tracks users in an Omega conversation
|
|
model OmegaParticipant {
|
|
id String @id @default(cuid())
|
|
|
|
// Conversation relationship
|
|
conversationId String @map("conversation_id")
|
|
conversation OmegaConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
|
|
|
|
// User info
|
|
userId String? @map("user_id")
|
|
displayName String @map("display_name") @db.VarChar(100)
|
|
email String?
|
|
|
|
// Role in conversation
|
|
role String @default("collaborator") @db.VarChar(20) // owner, collaborator
|
|
|
|
// Timestamps
|
|
joinedAt DateTime @default(now()) @map("joined_at")
|
|
|
|
@@unique([conversationId, userId])
|
|
@@index([conversationId])
|
|
@@map("omega_participants")
|
|
}
|
|
|
|
/// OmegaToolRun - tracks tool executions within Omega conversations
|
|
model OmegaToolRun {
|
|
id String @id @default(cuid())
|
|
|
|
// Conversation relationship
|
|
conversationId String @map("conversation_id")
|
|
conversation OmegaConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
|
|
|
|
// Message relationship (optional - for linking to specific message)
|
|
messageId String? @map("message_id")
|
|
|
|
// Tool execution details
|
|
toolName String @map("tool_name") @db.VarChar(200)
|
|
input Json @db.JsonB
|
|
output Json? @db.JsonB
|
|
error String? @db.Text
|
|
|
|
// Status tracking
|
|
status String @db.VarChar(20) // pending, running, success, error
|
|
|
|
// Timing
|
|
startedAt DateTime @default(now()) @map("started_at")
|
|
completedAt DateTime? @map("completed_at")
|
|
executionTimeMs Int? @map("execution_time_ms")
|
|
|
|
@@index([conversationId])
|
|
@@index([status])
|
|
@@map("omega_tool_runs")
|
|
}
|
|
|
|
/// OmegaUserSettings - user preferences for Omega
|
|
model OmegaUserSettings {
|
|
id String @id @default(cuid())
|
|
|
|
// User relationship
|
|
userId String @unique @map("user_id")
|
|
|
|
// Tool preferences
|
|
pinnedToolIds String[] @default([]) @map("pinned_tool_ids")
|
|
blockedToolIds String[] @default([]) @map("blocked_tool_ids")
|
|
|
|
// Customization
|
|
customSystemPrompt String? @map("custom_system_prompt") @db.Text
|
|
|
|
// UI preferences
|
|
showDebugMode Boolean @default(false) @map("show_debug_mode")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@map("omega_user_settings")
|
|
}
|