System Design

Database Schema

Complete reference for all PostgreSQL tables, columns, relationships, and enums.

Database Schema

Cognova uses PostgreSQL with Drizzle ORM. The schema is defined in server/db/schema.ts and migrations are stored in server/drizzle/migrations/.

This page is the single source of truth for all table and column definitions. API documentation references types defined here.

Entity Relationship Overview

user ──┬── session
       ├── account
       ├── projects ──── tasks ──── reminders
       ├── documents
       ├── cronAgents ── cronAgentRuns
       ├── secrets
       └── userSettings

conversations ──── conversationMessages

hookEvents          (standalone)
memoryChunks        (standalone)
tokenUsage          (standalone)

Auth Tables

These tables are managed by BetterAuth and follow its expected schema. Do not modify column names without checking BetterAuth compatibility.

user

The single admin user. Created automatically on first startup via the seed script.

ColumnTypeNullableDefaultDescription
idtextNo-Primary key (BetterAuth-generated)
nametextNo-Display name
emailtextNo-Unique email address
email_verifiedbooleanNofalseEmail verification status
imagetextYes-Avatar URL
created_attimestamptzNonow()Account creation time
updated_attimestamptzNonow()Last profile update

session

Active login sessions. BetterAuth creates and validates these automatically.

ColumnTypeNullableDefaultDescription
idtextNo-Primary key
user_idtextNo-FK to user.id (cascade delete)
tokentextNo-Unique session token
expires_attimestamptzNo-Session expiry (default: 7 days)
ip_addresstextYes-Client IP at login
user_agenttextYes-Browser user agent at login
created_attimestamptzNonow()Session creation time
updated_attimestamptzNonow()Last session refresh

account

Authentication provider accounts. For credential auth, stores the hashed password.

ColumnTypeNullableDefaultDescription
idtextNo-Primary key
user_idtextNo-FK to user.id (cascade delete)
account_idtextNo-Provider-specific account ID
provider_idtextNo-Auth provider name (credential)
access_tokentextYes-OAuth access token
refresh_tokentextYes-OAuth refresh token
access_token_expires_attimestamptzYes-Access token expiry
refresh_token_expires_attimestamptzYes-Refresh token expiry
scopetextYes-OAuth scope
id_tokentextYes-OIDC ID token
passwordtextYes-Hashed password (credential auth only)
created_attimestamptzNonow()Record creation time
updated_attimestamptzNonow()Last update time

verification

Email verification and password reset tokens.

ColumnTypeNullableDefaultDescription
idtextNo-Primary key
identifiertextNo-Email or other identifier
valuetextNo-Verification token
expires_attimestamptzNo-Token expiry
created_attimestamptzNonow()Record creation time
updated_attimestamptzNonow()Last update time

Application Tables

projects

Organizational containers for tasks and documents. Support soft delete.

ColumnTypeNullableDefaultDescription
iduuidNogen_random_uuid()Primary key
nametextNo-Project name
colortextNo-Hex color string (e.g., #3b82f6)
descriptiontextYes-Optional markdown description
created_attimestamptzNonow()Creation time
modified_attimestamptzYes-Last modification time
deleted_attimestamptzYes-Soft delete timestamp
created_bytextYes-FK to user.id (set null on delete)
modified_bytextYes-FK to user.id (set null on delete)
deleted_bytextYes-FK to user.id (set null on delete)

Relations: Has many tasks. Has many documents.

tasks

Individual work items. Support soft delete, priority levels, and tagging.

ColumnTypeNullableDefaultDescription
iduuidNogen_random_uuid()Primary key
titletextNo-Task title
descriptiontextYes-Markdown description
statustextNo'todo'Enum: todo, in_progress, done, blocked
priorityintegerNo21 = Low, 2 = Medium, 3 = High
project_iduuidYes-FK to projects.id (set null on delete)
due_datetimestamptzYes-Optional deadline
tagstextNo[]Array of tag strings
created_attimestamptzNonow()Creation time
modified_attimestamptzYes-Last modification time
completed_attimestamptzYes-When status changed to done
deleted_attimestamptzYes-Soft delete timestamp
created_bytextYes-FK to user.id (set null on delete)
modified_bytextYes-FK to user.id (set null on delete)
deleted_bytextYes-FK to user.id (set null on delete)

Relations: Belongs to projects. Has many reminders.

reminders

Time-based notifications attached to tasks.

ColumnTypeNullableDefaultDescription
iduuidNogen_random_uuid()Primary key
task_iduuidYes-FK to tasks.id (cascade delete)
messagetextNo-Notification message text
remind_attimestamptzNo-When to fire the reminder
notifiedbooleanNofalseWhether the reminder has been sent
created_attimestamptzNonow()Creation time

Relations: Belongs to tasks.

documents

Metadata for vault files. The actual file content lives on disk; this table tracks metadata, tags, sharing state, and sync status.

ColumnTypeNullableDefaultDescription
iduuidNogen_random_uuid()Primary key
titletextNo-Document title (from frontmatter or filename)
pathtextNo-Unique relative path within vault
contenttextYes-Cached file content
content_hashtextYes-Hash for change detection
tagstextNo[]Array of tag strings
project_iduuidYes-FK to projects.id (set null on delete)
sharedbooleanNofalseWhether publicly accessible
share_typetextYes-Enum: public, private
file_typetextNo-File extension (e.g., md, txt)
mime_typetextYes-MIME type
synced_attimestamptzYes-Last sync with filesystem
created_attimestamptzNonow()Record creation time
created_bytextYes-FK to user.id (set null on delete)
modified_attimestamptzYes-Last modification time
modified_bytextYes-FK to user.id (set null on delete)
deleted_attimestamptzYes-Soft delete timestamp
deleted_bytextYes-FK to user.id (set null on delete)

Relations: Belongs to projects.

Conversation Tables

conversations

Chat sessions between the user and Claude via the web UI.

ColumnTypeNullableDefaultDescription
iduuidNogen_random_uuid()Primary key
session_idtextNo-Unique client session identifier
sdk_session_idtextYes-Claude Agent SDK session ID
titletextYes-Conversation title (auto-generated)
summarytextYes-Brief summary of the conversation
statustextNo'idle'Enum: idle, streaming, interrupted, error
total_cost_usdrealNo0Cumulative API cost
started_attimestamptzNonow()Conversation start time
ended_attimestamptzYes-Conversation end time
message_countintegerNo0Total messages in conversation

Relations: Has many conversationMessages.

conversation_messages

Individual messages within a conversation.

ColumnTypeNullableDefaultDescription
iduuidNogen_random_uuid()Primary key
conversation_iduuidNo-FK to conversations.id (cascade delete)
roletextNo-Enum: user, assistant
contenttextNo-JSON string of content blocks
cost_usdrealYes-Cost for this message
duration_msintegerYes-Response generation time
created_attimestamptzNonow()Message timestamp

Relations: Belongs to conversations.

Agent Tables

cron_agents

Scheduled Claude agents that run on a cron schedule.

ColumnTypeNullableDefaultDescription
iduuidNogen_random_uuid()Primary key
nametextNo-Agent display name
descriptiontextYes-What this agent does
scheduletextNo-Cron expression (e.g., 0 4 * * *)
prompttextNo-The prompt sent to Claude on each run
enabledbooleanNotrueWhether the agent is active
max_turnsintegerYes50Maximum conversation turns per run
max_budget_usdrealYes-Cost cap per run
last_run_attimestamptzYes-Timestamp of most recent run
last_statustextYes-Enum: success, error, budget_exceeded, cancelled
created_attimestamptzNonow()Creation time
updated_attimestamptzNonow()Last update time
created_bytextYes-FK to user.id (set null on delete)

Relations: Has many cronAgentRuns.

cron_agent_runs

Execution history for each agent run with full metrics.

ColumnTypeNullableDefaultDescription
iduuidNogen_random_uuid()Primary key
agent_iduuidNo-FK to cron_agents.id (cascade delete)
statustextNo-Enum: running, success, error, budget_exceeded, cancelled
outputtextYes-Agent output on success
errortextYes-Error message on failure
cost_usdrealYes-Total API cost for this run
input_tokensintegerYes-Input tokens consumed
output_tokensintegerYes-Output tokens generated
num_turnsintegerYes-Conversation turns used
started_attimestamptzNonow()Run start time
completed_attimestamptzYes-Run completion time
duration_msintegerYes-Total execution time in milliseconds

Relations: Belongs to cronAgents.

System Tables

secrets

Encrypted key-value store for API tokens and credentials used by skills and agents.

ColumnTypeNullableDefaultDescription
iduuidNogen_random_uuid()Primary key
keytextNo-Unique secret name (e.g., GITHUB_TOKEN)
encrypted_valuetextNo-AES-256-GCM encrypted value with auth tag
ivtextNo-Initialization vector (hex)
descriptiontextYes-Human-readable description
created_attimestamptzNonow()Creation time
updated_attimestamptzNonow()Last update time
created_bytextYes-FK to user.id (set null on delete)

See Security for encryption details.

hook_events

Analytics log for Claude Code hook executions. Used to track tool usage patterns and blocked operations.

ColumnTypeNullableDefaultDescription
iduuidNogen_random_uuid()Primary key
event_typetextNo-Enum: SessionStart, SessionEnd, PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit
session_idtextYes-Claude Code session identifier
project_dirtextYes-Working directory for the session
tool_nametextYes-Tool that triggered the event
tool_matchertextYes-Hook matcher pattern
event_datatextYes-JSON string with event-specific data
exit_codeintegerYes-Hook script exit code
blockedbooleanNofalseWhether the operation was blocked
block_reasontextYes-Why the operation was blocked
duration_msintegerYes-Hook execution time
hook_scripttextYes-Path to the hook script
created_attimestamptzNonow()Event timestamp

memory_chunks

Persistent memory extracted from Claude Code conversations. Stores concise facts, decisions, and patterns for injection into future sessions.

ColumnTypeNullableDefaultDescription
iduuidNogen_random_uuid()Primary key
session_idtextYes-Claude session that created this memory
project_pathtextYes-Project scope for filtering
chunk_typetextNo-Enum: decision, fact, solution, pattern, preference, summary
contenttextNo-The extracted memory (concise statement)
source_excerpttextYes-Original context for reference
relevance_scorerealNo1.00.0--1.0 relevance weight (decays over time)
access_countintegerNo0Retrieval count
last_accessed_attimestamptzYes-Last time this memory was retrieved
created_attimestamptzNonow()Extraction time
expires_attimestamptzYes-Expiry for dynamic forgetting

token_usage

Unified cost and token tracking across all AI operations.

ColumnTypeNullableDefaultDescription
iduuidNogen_random_uuid()Primary key
sourcetextNo-Enum: chat, agent, memory_extraction
source_idtextYes-ID of the originating resource
source_nametextYes-Human-readable source label
input_tokensintegerNo0Input tokens consumed
output_tokensintegerNo0Output tokens generated
cost_usdrealNo0Total cost in USD
duration_msintegerYes-Operation duration
num_turnsintegerYes-Conversation turns (for agents)
created_attimestamptzNonow()Record timestamp

user_settings

Per-user application preferences stored as a JSON string.

ColumnTypeNullableDefaultDescription
iduuidNogen_random_uuid()Primary key
user_idtextNo-Unique FK to user.id (cascade delete)
settingstextNo'{}'JSON string of user preferences
created_attimestamptzNonow()Record creation time
updated_attimestamptzNonow()Last update time

Relations: Belongs to user (one-to-one).

Enum Reference

All enum values used across the schema:

TableColumnValues
tasksstatustodo, in_progress, done, blocked
documentsshare_typepublic, private
conversationsstatusidle, streaming, interrupted, error
conversation_messagesroleuser, assistant
cron_agentslast_statussuccess, error, budget_exceeded, cancelled
cron_agent_runsstatusrunning, success, error, budget_exceeded, cancelled
hook_eventsevent_typeSessionStart, SessionEnd, PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit
memory_chunkschunk_typedecision, fact, solution, pattern, preference, summary
token_usagesourcechat, agent, memory_extraction

Soft Delete Pattern

The projects, tasks, and documents tables use soft delete. Records are never physically removed -- instead, deleted_at is set to the current timestamp and deleted_by records who performed the deletion.

API queries filter out soft-deleted records by default:

.where(isNull(schema.tasks.deletedAt))

Restore operations set deleted_at and deleted_by back to null.

Audit Fields

Tables with user-driven mutations include three audit columns:

ColumnSet When
created_byRecord is created
modified_byRecord is updated
deleted_byRecord is soft-deleted

All audit columns are nullable foreign keys to user.id with ON DELETE SET NULL, so deleting a user does not cascade-delete their created content.