Overview
Shannon uses PostgreSQL for persistent storage. The database is organized into two schemas:auth- Authentication, multi-tenancy, and securitypublic- Core application tables (tasks, agents, sessions)
Entity Relationship Diagram
Schema: auth (Authentication & Multi-Tenancy)
auth.tenants
Purpose: Multi-tenant organization management
Indexes:
- Primary key on
slug(UNIQUE)
auth.users
Purpose: User authentication and profile management
Indexes:
idx_users_emailON (email)idx_users_tenant_idON (tenant_id)
auth.api_keys
Purpose: API key management for programmatic access
Indexes:
idx_api_keys_tenant_idON (tenant_id)idx_api_keys_key_prefixON (key_prefix)
workflows:read: Allow reading workflow/task status and resultsworkflows:write: Allow submitting and managing workflows/tasksagents:execute: Allow agent execution
auth.refresh_tokens
Purpose: JWT refresh token storage and revocation
Indexes:
idx_refresh_tokens_user_idON (user_id)idx_refresh_tokens_token_hashON (token_hash)
auth.audit_logs
Purpose: Security event audit trail
Indexes:
idx_audit_logs_user_idON (user_id)idx_audit_logs_tenant_idON (tenant_id)idx_audit_logs_event_typeON (event_type)idx_audit_logs_created_atON (created_at)
login- User loginlogout- User logoutapi_key_created- API key generationpermission_changed- Role/permission modification
Schema: public (Core Application)
users
Purpose: Application user profiles (legacy, linked to auth.users)
Indexes:
idx_users_tenant_idON (tenant_id)idx_users_external_idON (external_id)
auth.users.
sessions
Purpose: User session management and context
Indexes:
idx_sessions_user_idON (user_id)idx_sessions_tenant_idON (tenant_id)idx_sessions_expires_atON (expires_at)idx_sessions_external_idON ((context->>‘external_id’)) WHERE context->>‘external_id’ IS NOT NULLidx_sessions_user_external_idUNIQUE ON (user_id, (context->>‘external_id’)) WHERE context->>‘external_id’ IS NOT NULL AND deleted_at IS NULLidx_sessions_not_deletedON (id) WHERE deleted_at IS NULLidx_sessions_deleted_atON (deleted_at) WHERE deleted_at IS NOT NULL
- External IDs (non-UUID session IDs) are stored in
context->>'external_id'to enable dual-ID lookups - Soft delete support via
deleted_atcolumn - sessions with non-NULLdeleted_atare considered deleted
task_executions
Purpose: Task/workflow execution history and metrics
Indexes:
idx_task_user_sessionON (user_id, session_id)idx_task_created_atON (created_at DESC)idx_task_statusON (status)idx_task_workflow_idON (workflow_id)idx_task_executions_tenant_idON (tenant_id)idx_task_executions_session_idON (session_id)
RUNNING- Task in progressCOMPLETED- Task finished successfullyFAILED- Task failed with errorCANCELLED- Task cancelled by user
agent_executions
Purpose: Individual agent execution details within tasks
Indexes:
idx_agent_executions_workflow_idON (workflow_id)idx_agent_executions_created_atON (created_at DESC)idx_agent_executions_stateON (state)
IDLE- Agent idleANALYZING- Analyzing inputPLANNING- Planning executionRETRIEVING- Retrieving informationEXECUTING- Executing taskVALIDATING- Validating resultsSYNTHESIZING- Synthesizing responseCOMPLETED- Execution completeFAILED- Execution failed
tool_executions
Purpose: Tool invocation history and performance
Indexes:
idx_tool_executions_workflow_idON (workflow_id)idx_tool_executions_tool_nameON (tool_name)idx_tool_executions_created_atON (created_at DESC)idx_tool_executions_successON (success)
event_logs
Purpose: Streaming event storage for audit and replay
Indexes:
idx_event_logs_workflow_idON (workflow_id)idx_event_logs_task_idON (task_id)idx_event_logs_typeON (type)idx_event_logs_tsON (timestamp DESC)idx_event_logs_seqON (workflow_id, seq)idx_event_logs_workflow_tsON (workflow_id, timestamp DESC)uq_event_logs_wf_type_seqUNIQUE ON (workflow_id, type, seq) WHERE seq IS NOT NULL
task.started- Task execution startedtask.completed- Task execution completedagent.thinking- Agent processingtool.called- Tool invocation
token_usage
Purpose: Detailed token usage tracking per task
Indexes:
idx_token_usage_user_idON (user_id)idx_token_usage_created_atON (created_at DESC)idx_token_usage_provider_modelON (provider, model)idx_token_usage_task_idON (task_id)
usage_daily_aggregates
Purpose: Pre-computed daily usage statistics
Indexes:
idx_usage_daily_user_dateON (user_id, date)idx_usage_daily_dateON (date DESC)
Additional Tables
tool_calls
Purpose: Legacy tool call tracking (use tool_executions instead)prompts
Purpose: Prompt versioning and A/B testinglearning_cases
Purpose: Reinforcement learning case storagesession_archives
Purpose: Long-term session snapshots from Redisaudit_logs (public)
Purpose: Application audit trail (separate from auth.audit_logs)Database Functions
update_updated_at_column()
Purpose: Automatically updateupdated_at on row changes
Usage: Attached as trigger to users and sessions tables
update_daily_aggregate(user_id, date)
Purpose: Update or create daily usage aggregate for a user Usage: Called automatically via trigger on task completiontrigger_update_daily_aggregate()
Purpose: Trigger function to update aggregates on task status changes Usage: Automatically fires on task_executions INSERT/UPDATESample Queries
Task Analytics
Cost Analysis
Performance Monitoring
Best Practices
1. Indexing
Always use indexes for:- Foreign key columns (user_id, tenant_id, task_execution_id, etc.)
- Frequently filtered columns (status, created_at, expires_at)
- JSONB queries (context->>‘external_id’)
- Time-based queries (created_at DESC)
2. Partitioning
For high-volume tables, consider partitioning:3. Data Retention
Recommended policies:event_logs: 90 days (high volume, archivable)task_executions: 1 year (archive older)audit_logs: 2 years (compliance)token_usage: Aggregate to daily, archive raw data after 90 days
4. Query Optimization
Use EXPLAIN ANALYZE:5. Connection Pooling
Configuration (already configured in Shannon):Maintenance
Vacuum and Analyze
Statistics
Related Documentation
Environment Variables
Database configuration
Performance Tuning
Query optimization
Monitoring
Database monitoring