Skip to main content

Database Schema

STELLA uses PostgreSQL with Prisma ORM for data persistence. This document describes the database structure and relationships between entities.

Entity Relationship Diagram​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ User │──────<β”‚ ProjectMembership β”‚>──────│ Project β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β”‚ owns β”‚ contains
β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ AgentType β”‚ β”‚ Session β”‚
β”‚ PlanTemplateβ”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚EnvVarTemplatβ”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ β”‚ β”‚ β”‚
β–Ό β–Ό β–Ό β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Room β”‚ β”‚AgentInstanceβ”‚ β”‚Particip.β”‚ β”‚ Invitationβ”‚ β”‚ Message β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Core Models​

User​

Represents authenticated users of the platform.

model User {
id String @id @default(uuid())
email String @unique
password String // bcrypt hashed
name String?
verified Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

// Relations
projectMemberships ProjectMembership[]
customAgentTypes AgentType[]
planTemplates PlanTemplate[]
envVarTemplates EnvVarTemplate[]
messages UserMessage[]
sentProjectInvitations ProjectInvitation[]
receivedProjectInvitations ProjectInvitation[]
}

Project​

Organizational container for sessions. Supports public sharing.

model Project {
id String @id @default(uuid())
name String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

// Public Project Configuration
isPublic Boolean @default(false)
publicToken String? @unique
publicAgentTypeId String?
publicAgentConfig Json? // { name, icon, plan, envVarTemplateId }
publicVisualizerType String?
publicVisualizerLocked Boolean @default(false)
publicExpiresAt DateTime?
publicEnabled Boolean @default(true)

// Relations
sessions Session[]
memberships ProjectMembership[]
projectInvitations ProjectInvitation[]
}

Member Roles:

RolePermissions
OWNERFull control, delete project, manage members
ADMINManage sessions, invite members
MEMBERCreate and view sessions

Session​

A conversation instance with participants and agents.

model Session {
id String @id @default(uuid())
projectId String
name String?
status SessionStatus @default(ACTIVE) // ACTIVE, CLOSED
createdAt DateTime @default(now())
closedAt DateTime?

// Relations
room Room?
agents AgentInstance[]
participants Participant[]
invitations Invitation[]
messages Message[]
events RoomEvent[]
state SessionState?
}

Agent System​

AgentType​

Registry of available agent types (built-in and custom).

model AgentType {
id String @id @default(uuid())
slug String @unique // "stella-agent", "memory-coach"
name String // Display name
description String
icon String?
version String @default("1.0.0")
isBuiltIn Boolean @default(true)

// Custom agent ownership
userId String?

// Package storage (custom agents)
packagePath String?
packageSize Int?
packageHash String?

// Docker image configuration
imageUrl String? // Pre-built image URL
dockerfilePath String? // Path within package

// Validation workflow
validationStatus AgentValidationStatus @default(PENDING)
validationNotes String?
validatedAt DateTime?
validatedBy String?

// Configuration schema (JSON Schema format)
configSchema Json?
capabilities Json? // ["voice", "text", "progress"]
defaultConfig Json?

// Resource limits
resourceMemory String? @default("512Mi")
resourceCpu String? @default("250m")
resourceGpu Boolean @default(false)
}

Validation Status:

StatusDescription
PENDINGAwaiting admin review
APPROVEDReady for use
REJECTEDFailed validation

AgentInstance​

Running instance of an agent within a session.

model AgentInstance {
id String @id @default(uuid())
sessionId String
name String
icon String?
status AgentStatus @default(STARTING)
agentType String? @default("stella-agent")
agentTypeId String?
agentConfig Json?

// Kubernetes resources
podName String?
secretName String?
configMapName String?

// Health tracking
healthState String? @default("unknown")
lastHealthCheck DateTime?
lastError String?
messagesProcessed Int @default(0)
grpcAddress String?

// Environment variables
envVarTemplateId String?
}

Agent Status:

StatusDescription
STARTINGPod being created
RUNNINGActive and processing
STOPPINGShutdown in progress
STOPPEDCleanly terminated
FAILEDError state

Session State Machine​

SessionState​

Persists conversation plan execution state.

model SessionState {
id String @id @default(uuid())
sessionId String @unique

// Plan definition
planId String?
planData Json // Full plan (states, tasks, deliverables)

// Execution state
currentStateId String
completedTasks String[] @default([])
skippedTasks String[] @default([])

// Collected deliverables
deliverables Json @default("{}")
// Format: { key: { value, reasoning, collectedAt } }

// Progress tracking
turnsWithoutProgress Int @default(0)
totalTurns Int @default(0)

lastTransitionAt DateTime?
}

Participants & Invitations​

Participant​

Users connected to a session via LiveKit.

model Participant {
id String @id @default(uuid())
sessionId String
name String
identity String // LiveKit identity
isManuallyRegistered Boolean @default(false)
joinedAt DateTime @default(now())
leftAt DateTime?
tokenRevokedAt DateTime?
lastTokenRefresh DateTime?
lastSeenAt DateTime?
}

Invitation​

Shareable links for session access.

model Invitation {
id String @id @default(uuid())
sessionId String
token String @unique // URL token
participantName String
customMessage String?

// Visualizer settings
visualizerType String?
visualizerLocked Boolean @default(false)

// Status
status InvitationStatus @default(PENDING)
expiresAt DateTime?
acceptedAt DateTime?
participantId String? @unique
}

Invitation Status:

StatusDescription
PENDINGWaiting for participant
ACCEPTEDParticipant joined
EXPIREDTime-based expiration
REVOKEDManually revoked

Messages & Events​

Message​

Persisted conversation messages and events.

model Message {
id String @id @default(uuid())
sessionId String
content String @db.Text
messageType String
role String? // "user", "assistant", "system"
status String? // "partial", "final"
metadata Json?
timestamp DateTime @default(now())
}

Message Types:

TypeDescription
transcriptSpeech-to-text transcription
systemSystem notifications
task_updatePlan task progress
deliverableCollected deliverable
state_changeState machine transition
participant_eventJoin/leave events

RoomEvent​

LiveKit room events for audit logging.

model RoomEvent {
id String @id @default(uuid())
sessionId String
eventType String
data Json
timestamp DateTime @default(now())
}

User Templates​

PlanTemplate​

Reusable conversation plan definitions.

model PlanTemplate {
id String @id @default(uuid())
userId String
name String
description String?
content Json // SDK format: { states, system_prompt, session_context }
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

EnvVarTemplate​

Secure storage for API keys and secrets.

model EnvVarTemplate {
id String @id @default(uuid())
userId String
name String
description String?
variables String @db.Text // AES-256-GCM encrypted JSON
agentTypeId String? // Optional scope to agent type
}

Variables are encrypted at rest using AES-256-GCM with the format:

{iv}:{authTag}:{encryptedData}

User Messaging​

UserMessage​

Generic inbox for user notifications.

model UserMessage {
id String @id @default(uuid())
userId String
type UserMessageType // PROJECT_INVITATION
title String
body String?
read Boolean @default(false)
relatedEntityId String?
relatedEntityType String?
createdAt DateTime @default(now())
}

ProjectInvitation​

Collaboration invitations between users.

model ProjectInvitation {
id String @id @default(uuid())
projectId String
inviterId String
inviteeId String
status ProjectInvitationStatus @default(PENDING)
respondedAt DateTime?
}

Database Indexes​

Key indexes for query performance:

TableIndexPurpose
SessionprojectIdList sessions by project
SessionstatusFilter active sessions
MessagesessionId, timestampPaginated message history
AgentInstancestatusMonitor running agents
InvitationtokenFast token lookup
UserMessageuserId, readUnread message count

Migrations​

Prisma manages schema migrations:

# Generate migration from schema changes
npx prisma migrate dev --name description

# Apply migrations in production
npx prisma migrate deploy

# Reset database (development only)
npx prisma migrate reset

Next Steps​