Files
agentlens/packages/database/prisma/schema.prisma
Vectry 64c827ee84 feat: add command palette, accessibility, scroll animations, demo workspace, and keyboard navigation
- COMP-139: Command palette for quick navigation
- COMP-140: Accessibility improvements
- COMP-141: Scroll animations with animate-on-scroll component
- COMP-143: Demo workspace with seed data and demo banner
- COMP-145: Keyboard navigation and shortcuts help

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-Claude)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-10 18:06:36 +00:00

271 lines
5.9 KiB
Plaintext

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
// ─── Auth & Billing ────────────────────────────────────────────
model User {
id String @id @default(cuid())
email String @unique
passwordHash String
name String?
emailVerified Boolean @default(false)
demoSeeded Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
subscription Subscription?
apiKeys ApiKey[]
traces Trace[]
passwordResetTokens PasswordResetToken[]
emailVerificationTokens EmailVerificationToken[]
@@index([email])
}
model PasswordResetToken {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
token String @unique // SHA-256 hash of the raw token
expiresAt DateTime
used Boolean @default(false)
createdAt DateTime @default(now())
@@index([token])
@@index([userId])
}
model EmailVerificationToken {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
token String @unique // SHA-256 hash of the raw token
expiresAt DateTime
used Boolean @default(false)
createdAt DateTime @default(now())
@@index([token])
@@index([userId])
}
model ApiKey {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
name String @default("Default")
keyHash String @unique // SHA-256 hash of the actual key
keyPrefix String // First 8 chars for display: "al_xxxx..."
lastUsedAt DateTime?
revoked Boolean @default(false)
createdAt DateTime @default(now())
@@index([keyHash])
@@index([userId])
}
model Subscription {
id String @id @default(cuid())
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
tier SubscriptionTier @default(FREE)
stripeCustomerId String? @unique
stripeSubscriptionId String? @unique
stripePriceId String?
currentPeriodStart DateTime?
currentPeriodEnd DateTime?
// Usage tracking for the current billing period
sessionsUsed Int @default(0)
sessionsLimit Int @default(20) // Free tier: 20/day, paid: per month
status SubscriptionStatus @default(ACTIVE)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([stripeCustomerId])
@@index([stripeSubscriptionId])
}
enum SubscriptionTier {
FREE // 20 sessions/day
STARTER // $5/mo — 1,000 sessions/mo
PRO // $20/mo — 100,000 sessions/mo
}
enum SubscriptionStatus {
ACTIVE
PAST_DUE
CANCELED
UNPAID
}
// ─── Observability ─────────────────────────────────────────────
model Trace {
id String @id @default(cuid())
sessionId String?
name String
status TraceStatus @default(RUNNING)
tags String[] @default([])
metadata Json?
isDemo Boolean @default(false)
userId String?
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
totalCost Float?
totalTokens Int?
totalDuration Int?
startedAt DateTime @default(now())
endedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
decisionPoints DecisionPoint[]
spans Span[]
events Event[]
@@index([sessionId])
@@index([status])
@@index([createdAt])
@@index([name])
@@index([userId])
}
model DecisionPoint {
id String @id @default(cuid())
traceId String
trace Trace @relation(fields: [traceId], references: [id], onDelete: Cascade)
type DecisionType
reasoning String?
chosen Json
alternatives Json[]
contextSnapshot Json?
durationMs Int?
costUsd Float?
parentSpanId String?
span Span? @relation(fields: [parentSpanId], references: [id])
timestamp DateTime @default(now())
@@index([traceId])
@@index([type])
@@index([timestamp])
}
model Span {
id String @id @default(cuid())
traceId String
trace Trace @relation(fields: [traceId], references: [id], onDelete: Cascade)
parentSpanId String?
parentSpan Span? @relation("SpanTree", fields: [parentSpanId], references: [id])
childSpans Span[] @relation("SpanTree")
name String
type SpanType
input Json?
output Json?
tokenCount Int?
costUsd Float?
durationMs Int?
status SpanStatus @default(RUNNING)
statusMessage String?
startedAt DateTime @default(now())
endedAt DateTime?
metadata Json?
decisionPoints DecisionPoint[]
@@index([traceId])
@@index([parentSpanId])
@@index([type])
@@index([startedAt])
}
model Event {
id String @id @default(cuid())
traceId String
trace Trace @relation(fields: [traceId], references: [id], onDelete: Cascade)
spanId String?
type EventType
name String
metadata Json?
timestamp DateTime @default(now())
@@index([traceId])
@@index([type])
@@index([timestamp])
}
enum TraceStatus {
RUNNING
COMPLETED
ERROR
}
enum DecisionType {
TOOL_SELECTION
ROUTING
RETRY
ESCALATION
MEMORY_RETRIEVAL
PLANNING
CUSTOM
}
enum SpanType {
LLM_CALL
TOOL_CALL
MEMORY_OP
CHAIN
AGENT
CUSTOM
}
enum SpanStatus {
RUNNING
COMPLETED
ERROR
}
enum EventType {
ERROR
RETRY
FALLBACK
CONTEXT_OVERFLOW
USER_FEEDBACK
CUSTOM
}