This document describes the PostgreSQL schema used by the MIDAS community edition.
It complements the architectural rationale described in:
docs/architecture/why-the-schema-looks-like-this.md
The schema is defined in:
internal/store/postgres/schema.sql
This file is the single source of truth for the database structure. There is no migration system in v1 — EnsureSchema applies the full schema at startup using CREATE TABLE IF NOT EXISTS throughout and is safe to run against an already-initialised database. This document provides a human-readable reference for contributors.
MIDAS stores governance configuration and runtime evaluation evidence across the following primary tables.
| Table | Purpose |
|---|---|
| business_services | Organizational service offerings; the structural anchor in the v1 service-led model |
| capabilities | Logical business abilities (e.g. identity verification, fraud detection) |
| business_service_capabilities | M:N junction linking BusinessServices to Capabilities |
| processes | Governed actions; each Process belongs to exactly one BusinessService |
| decision_surfaces | Registry of governed business decisions |
| authority_profiles | Authority rules and thresholds for a surface |
| agents | Autonomous actors (AI, service, or operator) |
| authority_grants | Grants linking agents to authority profiles |
| operational_envelopes | Runtime evaluation records |
Stores logical business domains that group related processes. Capabilities and processes form the structural layer that evaluation requests are mapped to.
| Column | Type | Description |
|---|---|---|
| capability_id | text | Capability identifier |
| name | text | Human-readable name |
| status | text | active or deprecated |
| origin | text | Always manual in v1 (the inferred enum value is reserved). |
| managed | boolean | Always true in v1 (the false value is reserved). |
| replaces | text | ID of a previously-superseded capability, when a new record replaces an old one (nullable). |
| description | text | Optional description |
| owner_id | text | Owning team or system (nullable) |
| parent_capability_id | text | Parent capability for hierarchical grouping (nullable) |
| created_at | timestamp | Record creation time |
| updated_at | timestamp | Last update time |
capability_id
In v1, capabilities are always operator-declared via control-plane apply
(origin=manual, managed=true). The inferred/false enum values
remain in the schema for forward compatibility but are unreachable from
v1 code paths. The replaces column tracks lineage when one capability
supersedes another.
Stores governed actions within a capability. Each decision surface is associated with a process; each process belongs to a capability.
| Column | Type | Description |
|---|---|---|
| process_id | text | Process identifier |
| business_service_id | text | Parent business service (NOT NULL, FK to business_services) |
| name | text | Human-readable name |
| status | text | active or deprecated |
| origin | text | Always manual in v1. |
| managed | boolean | Always true in v1. |
| replaces | text | ID of a previously-superseded process (nullable). |
| description | text | Optional description |
| owner_id | text | Owning team or system (nullable) |
| parent_process_id | text | Parent process for sub-process hierarchies (nullable) |
| level | integer | Depth in the process hierarchy (nullable) |
| created_at | timestamp | Record creation time |
| updated_at | timestamp | Last update time |
process_id
business_service_idis a NOT NULL foreign key tobusiness_services.business_service_id(v1 service-led model).- The
originandmanagedcolumns follow the same v1 semantics as capabilities (see above). - The Capability ↔ BusinessService relationship is M:N via the
business_service_capabilitiesjunction; processes inherit their capability set indirectly through the parent business service's links.
Stores the registry of governed decisions.
Surfaces are versioned, allowing governance configuration to evolve while preserving auditability.
| Column | Type | Description |
|---|---|---|
| id | text | Logical surface identifier |
| version | integer | Surface version |
| name | text | Human readable name |
| domain | text | Business domain |
| business_owner | text | Business owner |
| technical_owner | text | Technical owner |
| status | text | draft, review, active, deprecated, retired |
| process_id | text | Governing process (nullable, FK to processes) |
| effective_date | timestamp | When this version became active |
| created_at | timestamp | Record creation time |
| updated_at | timestamp | Last update time |
(id, version)
The orchestrator resolves the active surface version using:
effective_date <= evaluation_time
Defines authority thresholds and policy configuration for a surface.
Profiles are versioned so governance changes remain traceable.
| Column | Type | Description |
|---|---|---|
| id | text | Logical profile identifier |
| version | integer | Profile version |
| surface_id | text | Associated decision surface |
| name | text | Profile name |
| confidence_threshold | double | Minimum confidence required |
| consequence_type | text | financial or risk_rating. The control-plane API accepts monetary as the canonical amount/currency value and persists it as financial. |
| consequence_amount | double | Monetary threshold |
| consequence_currency | text | Currency for monetary threshold |
| consequence_risk_rating | text | Risk rating threshold |
| policy_reference | text | Rego policy bundle reference |
| escalation_mode | text | auto or manual |
| fail_mode | text | open or closed |
| required_context_keys | jsonb | Required context fields |
| effective_date | timestamp | Version activation time |
| created_at | timestamp | Record creation time |
| updated_at | timestamp | Last update time |
(id, version)
Stores metadata about autonomous actors interacting with MIDAS.
| Column | Type | Description |
|---|---|---|
| id | text | Agent identifier |
| name | text | Agent name |
| type | text | ai, service, operator |
| owner | text | Owning team or system |
| model_version | text | AI model version |
| endpoint | text | Service endpoint |
| operational_state | text | active, suspended, revoked |
| created_at | timestamp | Record creation time |
| updated_at | timestamp | Last update time |
id
Stores grants linking agents to authority profiles.
Grants contain no authority rules themselves.
| Column | Type | Description |
|---|---|---|
| grant_id | text | Grant identifier |
| agent_id | text | Agent receiving authority |
| profile_id | text | Authority profile |
| granted_by | text | User or system granting authority |
| effective_date | timestamp | Grant activation |
| status | text | active, suspended, revoked |
| created_at | timestamp | Record creation time |
| updated_at | timestamp | Last update time |
grant_id
Stores runtime evaluation records.
Every evaluation creates one envelope.
| Column | Type | Description |
|---|---|---|
| id | text | Envelope identifier |
| request_id | text | Correlation ID |
| surface_id | text | Evaluated decision surface |
| surface_version | integer | Surface version used |
| profile_id | text | Authority profile used |
| profile_version | integer | Profile version used |
| agent_id | text | Agent performing evaluation |
| state | text | Envelope lifecycle state |
| outcome | text | Authority outcome |
| reason_code | text | Reason for outcome |
| created_at | timestamp | Envelope creation |
| updated_at | timestamp | Last update |
| closed_at | timestamp | Final state timestamp |
id
Operational envelopes follow this lifecycle:
RECEIVED
→ EVALUATING
→ OUTCOME_RECORDED
→ ESCALATED (optional)
→ CLOSED
The envelope stores references to configuration versions so that the exact authority conditions applied during evaluation can always be reconstructed.
Stores organizational service offerings. Every Process belongs to exactly one BusinessService via processes.business_service_id (NOT NULL). Capabilities link to BusinessServices through the business_service_capabilities junction table (M:N).
| Column | Type | Description |
|---|---|---|
| business_service_id | text | Business service identifier |
| name | text | Human-readable name |
| description | text | Optional description |
| service_type | text | customer_facing, internal, or technical |
| regulatory_scope | text | Regulatory scope (nullable) |
| status | text | active or deprecated |
| origin | text | Always manual in v1. |
| managed | boolean | Always true in v1. |
| replaces | text | ID of a previously-superseded business service (nullable). |
| owner_id | text | Owning team or system (nullable) |
| created_at | timestamp | Record creation time |
| updated_at | timestamp | Last update time |
business_service_id
- The
originandmanagedcolumns follow the same semantics as capabilities and processes replacesis a self-referencing FK for promotion lineage
M:N junction table linking BusinessServices to Capabilities. This is the canonical Capability ↔ BusinessService relationship in the v1 service-led model: a BusinessService is enabled by zero or more Capabilities, and a Capability enables zero or more BusinessServices.
| Column | Type | Description |
|---|---|---|
| business_service_id | text | FK to business_services.business_service_id (ON DELETE CASCADE) |
| capability_id | text | FK to capabilities.capability_id (ON DELETE RESTRICT) |
| created_at | timestamp | Record creation time |
(business_service_id, capability_id)
The junction row carries no lifecycle of its own — no origin, managed, replaces, or status columns. The lifecycle of the relationship is conveyed by the participating BusinessService and Capability rows.
DecisionSurface → AuthorityProfile → AuthorityGrant → Agent
Runtime evaluations record resolved configuration versions inside the envelope.
surface_id + surface_version
profile_id + profile_version
This allows deterministic audit reconstruction of any decision evaluation.
Capability ←─ business_service_capabilities ─→ BusinessService ←─ Process ←─ DecisionSurface
The v1 model is service-led: BusinessService is the structural anchor.
processes.business_service_id(NOT NULL) — every Process belongs to exactly one BusinessService.decision_surfaces.process_id(NOT NULL) — every Surface belongs to exactly one Process.business_service_capabilities— M:N junction. A Capability enables many BusinessServices and vice versa. The junction has no lifecycle columns; lineage and status live on the participating rows.
There is no direct foreign key from Process to Capability. The relationship between a Process and a Capability is indirect, traversed via Process → BusinessService → BusinessServiceCapability → Capability.
The full schema is defined in a single file:
internal/store/postgres/schema.sql
There are no migration files. The schema is applied at startup by EnsureSchema, which uses CREATE TABLE IF NOT EXISTS throughout and is safe to run against an already-initialised database.
The MIDAS schema is designed to support:
- versioned governance configuration
- deterministic evaluation auditing
- clear separation of authority and identity
- operational traceability for every decision
The schema prioritizes governance integrity and auditability over simplicity.