Data model¶
Status: Current | Last reviewed: 2026-09-01
The conceptual shape of TrueServe's data. For the concrete table list, read tables.md.
Top-level entities¶
tenants ─┐
├── users
├── agents ────── agent_versions (1 draft + N published)
│ └── surface_configs
├── workflow_configs ── workflow_versions
│ └── trigger_rules
├── integrations (encrypted credentials)
├── tools (optionally referencing integrations)
└── conversations
├── conversation_messages
└── conversation_recordings
The agent / agent_version split¶
The most important pattern in this schema. Read this carefully.
agents carries identity:
| Column | Purpose |
|---|---|
id |
Primary key |
name |
Human label |
description |
Human description |
surface_config_id |
Which surface to render in |
tenant_id |
Owner |
agent_versions carries runtime config:
| Column | Purpose |
|---|---|
agent_id |
Foreign key |
version |
0 = draft, 1+ = published |
is_current_published |
At most one per agent |
config |
JSONB. The pipeline graph, prompts, tools, etc. |
created_by, published_at, notes, weight |
Audit + A/B traffic split |
Note: name and description live only on
agents. Adding them toagent_versionsis a recurring mistake. The orchestrator never reads them — it readsagent_versions.configexclusively, viaresolve_agent_version().
agent_configs was a view that joined the two during the migration. It was dropped in init-script 104. If you find a reference to it, the reference is stale.
For the SQL functions that operate on this model (resolve_agent_version, publish_agent_version, create_new_agent_draft, update_agent_draft, resolve_agent_version_weighted), see sql-functions.md.
The TypeScript types for the JSONB blob live in apps/ai-manager/lib/pipeline-types.ts.
The same pattern, applied to workflows¶
workflow_configs (identity) + workflow_versions (config JSONB) mirrors the agent split exactly. Workflows are addressed by the numeric workflow_configs.id; workflow_versions keys on (workflow_id, version_number) where workflow_id is an integer FK to workflow_configs.id (renamed from base_workflow_id in the 2026-06-20 squash). The old text-slug column (legacy_slug) from the migration-130 cutover was dropped in that squash. See rename-map.md.
Surfaces¶
A surface is the UI an end user sees. The agent points at a surface_configs row that controls layout, branding, theme, and embedded widgets.
The same agent can appear in multiple surfaces by being referenced from different surface configs — common when the same brain runs on the web, in Salesforce, and on phone.
Integrations and tools¶
integrations rows hold tenant-scoped credentials for third-party services (Genesys org, OpenAI key, Salesforce org). The credential blob is encrypted with AES-256-GCM keyed off MASTER_ENCRYPTION_KEY. See secret-storage.md.
tools rows expose actions to agents. A tool may reference an integration row for credentials, or carry its own auth. The tool catalog also feeds workflow nodes (a tool node in async-agent invokes an MCP tool through agent-host).
Conversations¶
conversations is the long-form record of a session — voice, chat, or async. It carries the agent it was bound to, the surface it ran in, the user (where authenticated), tenant, timestamps, and metadata.
Per-message detail lives in conversation_messages; transcript rows also carry lifecycle lineage fields (message_key, session_seq, variant, revision) so streaming interim/final/enhanced updates replay in order without duplicate variants. Audio recordings live in conversation_recordings, which references object storage (the recordings-role bucket, STORAGE_BUCKET_RECORDINGS). conversation_search_documents holds one indexed row per conversation for global and per-agent history search. When archiving is enabled, transcript/event/recording detail can move to an object-storage archive bundle while search metadata stays hot.
Tenants and isolation¶
Multi-tenancy is enforced via row-level security on every tenant-scoped table. The tenants.slug column drives URL paths, catalog directories, and integration namespacing — and is consequently locked while a tenant owns dependent rows. See multi-tenancy.md.
Catalogs (A2UI)¶
a2ui_catalogs rows describe published component bundles built from TypeScript source. The bundle artifact lives in object storage; the row points at it. catalog-builder writes; multimodal-service reads. Source is archived alongside the build so it survives volume wipes.
Knowledge graph¶
knowledge_* tables hold ingestion checkpoints, assertions, and event logs. The actual graph lives in Neo4j; the Postgres tables are the durable source for replay and reconciliation.