KaireonAI persists all platform state in 101 Prisma models declared inDocumentation Index
Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt
Use this file to discover all available pages before exploring further.
platform/prisma/schema.prisma. This page indexes every model by domain, names the underlying PostgreSQL table (@@map), and links each model back to the API or operator surface that owns it.
What it indexes
The schema file atplatform/prisma/schema.prisma is the single source of truth for every persisted entity in the platform. Every API route, cron job, MCP tool, and worker reads or writes one or more of these models. The Tenant model anchors multi-tenancy — most other models carry a tenantId column and an index on it.
This page exists because operators and contributors need a one-screen overview before they grep for symbols. For per-API request and response shapes, follow the per-domain links in the Reference tables below; this page only documents the persistence layer.
Quick start
grep -n '^model {Name}' platform/prisma/schema.prisma.
How it works
Prisma 7 lifecycle
Every model inschema.prisma maps to one PostgreSQL table via the @@map("table_name") directive. The Prisma client generator at the top of the schema emits a typed client into platform/generated/prisma/; that path is gitignored and regenerated by npm run build (which runs prisma generate && next build) and by the postinstall hook on npm install.
The datasource block in schema.prisma declares only the provider — provider = "postgresql" (no url). The connection URL lives in platform/prisma.config.ts and is read from DATABASE_URL. This split is required by Prisma 7; setting url directly inside schema.prisma errors out with The datasource property 'url' is no longer supported in schema files.
Multi-tenant isolation
Every tenant-scoped model carries atenantId String column and at least one composite index that begins with tenantId. API routes enforce isolation by adding where: { tenantId } on every query through the requireTenant helper at platform/src/lib/tenant.ts. The Tenant table itself (tenants) holds tenant-level settings — settings (JSON), aiAnalyzerSettings (JSON), isPlayground (boolean) — that gate features per tenant.
A handful of models — User, AuditLog, Account, Session, VerificationToken, TenantRegion — either hold cross-tenant rows or scope by userId instead. Each is called out in its row below.
Soft delete vs hard delete
Models with operator-visible “archive” semantics carry a nullabledeletedAt DateTime? column and an index on [tenantId, deletedAt]. API routes filter out soft-deleted rows by default; the audit log captures the soft-delete event. Models with deletedAt include Category, SubCategory, Channel, Placement, FlowRoute, Offer, Creative, OutcomeType, QualificationRule, ContactPolicy, DecisionFlow, TriggerRule, GuardrailRule, ArbitrationProfile, SummaryDefinition.
Other models — Suppression, OutboxEvent, DeadLetterEvent, PipelineRun, DecisionTrace, InteractionHistory — are hard-deleted by retention crons (platform/src/app/api/v1/cron/cleanup/route.ts) per the RetentionConfig.dataClass policy.
IR-native pipelines
Pipeline.irVersion is String NOT NULL DEFAULT "1.0" — every pipeline is IR-native after the legacy ETL editor was deleted on 2026-04-28. The full DAG lives in PipelineIrVersion.ir (JSONB). The legacy PipelineNode and PipelineEdge models were removed in the same change; the pipeline_nodes and pipeline_edges Postgres tables were dropped via platform/prisma/manual-sql/04_drop_legacy_pipeline_tables.sql.
Reference
Each subsection groups models by domain. Tables list the model name, the underlying Postgres table (@@map), the most operationally relevant fields, primary relations, and a one-line purpose. Schema line numbers below are valid against the schema as of 2026-04-30.
Decisioning core
The studio entities that make up an offer catalog and the four-stage decisioning pipeline (Eligibility / Fit Filters / Match Scoring / Ranking).| Model | @@map | Key Fields | Relations | Purpose |
|---|---|---|---|---|
Tenant | tenants | name, slug, settings, aiAnalyzerSettings, isPlayground | Conversation[] | Multi-tenant root; per-tenant feature flags live in settings JSON (schema.prisma:12). |
Category | categories | name, customFields, ordinal, deletedAt | SubCategory[], Offer[] | Top-level offer grouping (e.g. “Cards”, “Loans”). Computed-field formulas live in customFields (schema.prisma:30). |
SubCategory | sub_categories | name, categoryId, customFields | Category, Offer[] | Child grouping below Category (e.g. “Travel” under “Cards”) (schema.prisma:54). |
Channel | channels | channelType, deliveryMode, impressionMode, providerConfig, fileConfig | Creative[], Placement[] | Delivery channel — email/sms/push/web/whatsapp/etc. impressionMode decides whether /recommend auto-records impressions (schema.prisma:80). |
Placement | placements | slotType, maxSlots, channelId, targeting | Channel, Creative[] | A targeted slot inside a channel (hero, banner, modal). Used by FlowRoute lookups (schema.prisma:105). |
FlowRoute | flow_routes | channelId, placementId, decisionFlowId, priority | — | Maps (channel, placement) to a DecisionFlow. Cached 120s in the /recommend hot path (schema.prisma:127). |
Offer | offers | categoryId, subCategoryId, priority, mandatory, eligibility, budget, schedule | Category?, SubCategory?, Creative[], InteractionHistory[] | Decisioning offer — what the platform recommends. mandatory=true bypasses eligibility (schema.prisma:147). |
Creative | creatives | offerId, channelId, placementId, templateType, content, personalization, weight | Offer, Channel, Placement?, ContentItem?, InteractionHistory[] | Channel-specific rendering of an offer. Maps to legacy Treatment table semantically (schema.prisma:194). |
OutcomeType | outcome_types | key, classification, category, isSystem | — | Per-tenant taxonomy of outcomes (impression, click, dismiss, convert). System rows are undeletable (schema.prisma:231). |
QualificationRule | qualification_rules | ruleType, config, priority, stage, scope (deprecated) | QualificationRuleScope[] | Stages: eligibility, fit, match. The legacy scope/scopeId columns are kept for back-compat; new code uses scopes[] (schema.prisma:360). |
QualificationRuleScope | qualification_rule_scopes | qualificationRuleId, scope, scopeId | QualificationRule | Multi-scope assignment — one rule can apply globally and to specific categories/offers (schema.prisma:387). |
ContactPolicy | contact_policies | ruleType, config, priority, scope (deprecated) | ContactPolicyScope[] | Frequency caps, cooldowns, mutual exclusion. ruleType includes customer_total_cap (Phase 2B-3) and offer_category_cap (schema.prisma:403). |
ContactPolicyScope | contact_policy_scopes | contactPolicyId, scope, scopeId | ContactPolicy | Multi-scope assignment for contact policies (schema.prisma:429). |
DecisionFlow | decision_flows | key, draftConfig, publishedVersions, arbitrationProfileId, isDefault, isProtected | Run[] | Visual decisioning flow. draftConfig holds the working version; publishedVersions[] holds immutable snapshots (schema.prisma:765). |
ArbitrationProfile | arbitration_profiles | key, weights, status | — | Multi-objective ranking weights (revenue, margin, propensity, engagement) (schema.prisma:1705). |
CrossOfferConstraint | cross_offer_constraints | scope, ruleType, config, status | — | Multi-offer arbitration constraints. Read by Lagrangian arbitration in lib/arbitration/cross-offer.ts; threaded into both realtime (realtime-wire.ts:194) and batch (batch-executor.ts:489-510) decisioning paths (schema.prisma:2273). |
GuardrailRule | guardrail_rules | key, severity, expressionAst | — | Hard/soft filter expressions evaluated alongside qualification rules (schema.prisma:743). |
Suppression | suppressions | customerId, scope, policyId, expiresAt | — | Pre-computed contact-policy block per customer × scope. Expired rows cleaned by retention cron (schema.prisma:1883). |
VolumeConstraint | volume_constraints | scope, scopeId, maxVolume, period, currentCount, resetAt | — | System-wide delivery caps on offers, categories, channels. See Volume Constraints (schema.prisma:1840). |
BudgetAllocation | budget_allocations | scope, scopeId, periodType, maxImpressions, maxSpend, maxConversions, periodKey | — | Budget tracking with rolling-window counters per scope (global / category / offer) (schema.prisma:1307). |
Customer & interactions
Customer-scoped rows that drive the decisioning loop and the analytics fact tables.| Model | @@map | Key Fields | Relations | Purpose |
|---|---|---|---|---|
InteractionHistory | interaction_history | customerId, recommendationId, offerId, creativeId, interactionType, outcomeTypeKey, direction, deduplicationId | Offer?, Creative | Append-only fact table for impressions, recommendations, clicks, conversions. Partitioned in production via manual-sql/ (schema.prisma:255). |
InteractionSummary | interaction_summaries | periodType, periodKey, customerId, offerId, dimensionKey, definitionId, impressions, positive, converts, totalValue | — | Pre-aggregated rollups by [periodType, periodKey, customerId, offerId, creativeId, channelId]. Driven by SummaryDefinition (schema.prisma:304). |
Impression | impressions | customerId, offerId, creativeId, channelId, placementId, context | — | Channel-level impression mirror written by /respond; InteractionHistory is the canonical record (schema.prisma:1976). |
CustomerEngagementHealth | customer_engagement_health | customerId, score (0-1), inputs, computedAt | — | Nightly-computed engagement score from a 90-day rollup. Read by engagement-aware contact-policy caps (Phase 2C-3) (schema.prisma:344). |
CustomerCLV | customer_clv | customerId, clvScore, predictedRevenue, churnProbability, rfmRecency, rfmFrequency, rfmMonetary, segment | — | Per-customer RFM and lifetime-value scores. Segments: high, medium, low, at_risk (schema.prisma:2061). |
IdentityLink | identity_links | canonicalId, identifierType, identifierValue, confidence | — | Identity resolution graph — maps email/phone/session/device → canonicalId per tenant (schema.prisma:1333). |
Segment | segments | baseSchemaId, joins, filters, viewName, customerCount | DataSchema, Run[] | Definition of an audience over DataSchema rows. Materializes to a Postgres view named seg_{idPrefix} (schema.prisma:796). |
ConsentRecord | consent_records | subjectId, purpose, status, source, grantedAt, revokedAt | — | GDPR/privacy consent ledger per customer × purpose (schema.prisma:1996). |
Algorithm models
ML model registry, versioning, governance, and per-scope adaptive learning state.| Model | @@map | Key Fields | Relations | Purpose |
|---|---|---|---|---|
AlgorithmModel | algorithm_models | key, modelType, targetField, predictors, metrics, modelState, outcomeWeights, registryStatus, registryFamily | ModelVersion[], ModelAdaptation[], Experiment[], ExperimentChallenger[] | The model record. modelType is one of scorecard, bayesian, logistic_regression, gradient_boosted (schema.prisma:572). |
ModelVersion | model_versions | modelId, version, config, modelState, metrics, predictors | AlgorithmModel | Immutable historical snapshot of AlgorithmModel state (schema.prisma:657). |
ModelAdaptation | model_adaptations | modelId, scope, scopeId, positives, negatives, positiveRate, predictorBins, predictorAucs | AlgorithmModel | Per-scope (global / category / offer / channel) learned propensity. Updated atomically by online learning loop (schema.prisma:629). |
ModelApproval | model_approvals | modelId, version, status, requestedBy, reviewedBy, metrics | — | Production-promotion governance ticket per model version (schema.prisma:1231). |
ModelDriftCheck | model_drift_checks | modelId, checkType, baseline, current, driftScore, drifted | — | Periodic drift snapshot. checkType is one of psi, ks_test, auc_decay, feature_drift (schema.prisma:1249). |
Experiment | experiments | key, championModelId, trafficSplit, autoPromote, holdoutPercent, results | AlgorithmModel?, ExperimentChallenger[] | Champion/challenger experiment definition (schema.prisma:676). |
ExperimentChallenger | experiment_challengers | experimentId, modelId, trafficPct | Experiment, AlgorithmModel | Join row binding a challenger model to an experiment with a traffic percentage (schema.prisma:701). |
ExperimentAssignment | experiment_assignments | customerId, experimentId, variant, assignedAt | — | Sticky customer-to-experiment mapping (schema.prisma:1959). |
VariantAssignment | variant_assignments | customerId, experimentKey, variantName, assignedAt, expiresAt | — | Variant assignment with optional TTL — used for blueprint/decision-flow A/B tests (schema.prisma:1449). |
MlJobResult | ml_job_results | jobType, status, input, result, error | — | Async ML job ledger — policy_analysis, segmentation, content_analysis (schema.prisma:1746). |
Audit & compliance
Tamper-evident logs, retention, consent, and DSAR machinery.| Model | @@map | Key Fields | Relations | Purpose |
|---|---|---|---|---|
AuditLog | audit_logs | requestId, integrityHash, prevHash, userId, action, entityType, entityId, before, after, entityVersion | — | Immutable audit chain. integrityHash = SHA-256(content + prevHash) builds a tamper-evident chain. API routes block UPDATE/DELETE on this table (schema.prisma:1063). |
RetentionConfig | retention_configs | dataClass, retentionDays, legalHold | — | Per-tenant retention policy. dataClass includes interactions, decisions, metrics, audit. Cleanup cron honors per-tenant overrides (schema.prisma:1690). |
DsarRequest | dsar_requests | requestType (export/delete/rectify), subjectId, subjectType, status, requestedBy, result | — | Data Subject Access Request workflow. See DSAR Portability (schema.prisma:1286). |
PolicySnapshot | policy_snapshots | policyVersionHash, interactionId, eligibilityPolicies, suppressionPolicies, guardrailRules | — | Frozen policy configuration referenced by DecisionTrace.policyVersionHash. One row per unique 16-char hash per tenant (schema.prisma:1269). |
DecisionTrace | decision_traces | requestId, customerId, candidateCount, afterQualification, afterContactPolicy, qualificationResults, scoringResults, selectedOffers, policyVersionHash, degradedScoring | — | Forensic per-decision trace. Sample rate set by tenantSettings.decisionTraceSampleRate (schema.prisma:1604). |
Governance
Approval workflows, four-eyes governance, and operator-driven change control.| Model | @@map | Key Fields | Relations | Purpose |
|---|---|---|---|---|
ApprovalRequest | approval_requests | entityType, entityId, action, payload, requesterId, approverId, status | — | Single-stage approval ticket — gates production changes when four-eyes is enabled (schema.prisma:930). |
ApprovalRequestStage | approval_request_stages | approvalRequestId, stageName, ordinal, requiredRole, status, approverId | — | Multi-stage four-eyes (W14) — one ApprovalRequest can require N sequential approvals (schema.prisma:2255). |
CustomRole | custom_roles | name, permissions (JSON array of permission strings) | CustomRoleAssignment[] | Tenant-defined role bundles for fine-grained authorization (schema.prisma:1418). |
CustomRoleAssignment | custom_role_assignments | userId, roleId | CustomRole | Join row binding a User to a CustomRole per tenant (schema.prisma:1434). |
SsoConfig | sso_configs | provider (saml/oidc/none), samlEntityId, oidcIssuer, defaultRole, allowedDomains, autoProvision, enforceForAllUsers | — | Per-tenant SSO configuration. One row per tenant (unique on tenantId) (schema.prisma:1393). |
WebAuthnCredential | webauthn_credentials | userId, credentialId, publicKey (CBOR base64), counter, transports, deviceLabel | — | Hardware-backed FIDO2/WebAuthn credentials per user (W18) (schema.prisma:2303). |
Operator & infra
Tables consumed by operators, cron jobs, and out-of-band workers.| Model | @@map | Key Fields | Relations | Purpose |
|---|---|---|---|---|
User | users | email, password, role, mfaSecret, mfaEnabled, mfaBackupCodes, lockedUntil, failedLoginAttempts, onboardingProgress | Account[], Session[], Conversation[] | NextAuth v5 user. Optional tenantId because some users (admins) are cross-tenant (schema.prisma:990). |
Account | accounts | userId, provider, providerAccountId, OAuth tokens | User | NextAuth v5 OAuth account binding (schema.prisma:1018). |
Session | sessions | sessionToken, userId, expires | User | NextAuth v5 active sessions (schema.prisma:1039). |
VerificationToken | verification_tokens | identifier, token, expires | — | NextAuth v5 email-verification + magic-link tokens (schema.prisma:1051). |
ApiKey | api_keys | prefix (first 12 chars displayed), hashedKey (SHA-256), expiresAt, lastUsedAt, revokedAt | — | Long-lived API key for X-API-Key auth. Raw key starts with krn_ (schema.prisma:1124). |
OAuthClient | oauth_clients | clientId (kci_-prefixed), hashedSecret, scopes (read,write,admin) | — | OAuth2 client credentials grant — server-to-server callers (schema.prisma:1144). |
TenantSettings | tenant_settings | mlWorkerConfig, aiAnalyzerSettings, flowIrEnabled | — | Per-tenant operational toggles. aiAnalyzerSettings.arbitration holds EXP3-IX bandit config (schema.prisma:1944). |
PlatformSetting | platform_settings | category, key, value, encrypted | — | Per-tenant key-value config — SES from-address, Twilio SID, etc. AES-encrypted when encrypted=true (schema.prisma:1586). |
OutboxEvent | outbox_events | topic, payload, status, retryCount, maxRetries, lastError, publishedAt | — | Transactional outbox for events. Drained by the outbox publisher worker; on max retries the row moves to DeadLetterEvent (schema.prisma:1162). |
DeadLetterEvent | dead_letter_events | originalEventId, topic, payload, failedAt, errorMessage | — | Terminal event store for outbox publish failures. Read by Operations Runbook (schema.prisma:1180). |
ChannelDelivery | channel_deliveries | interactionId, channelType, providerName, providerMessageId, idempotencyKey, status (pending/sent/delivered/bounced/failed/opened/clicked), attempts | — | Per-message delivery tracking with provider IDs and idempotency. Powers retry/bounce handling (schema.prisma:1196). |
ExportCheckpoint | export_checkpoints | exportType, lastExportAt, filePath, status | — | Resume point for the Hive interaction-history export job (schema.prisma:1906). |
AlertRule | alert_rules | metric, operator, threshold, windowMinutes, cooldownMinutes, channels, lastFiredAt, status | — | Threshold-based alerts. channels is a JSON list of notification destinations (schema.prisma:1466). |
Run | runs | decisionFlowId (mapped to blueprintId), segmentId, scheduleType, volumeConstraints, fileConfig, channelIds | DecisionFlow, Segment, CampaignRun[] | Scheduled batch campaign config. Triggers CampaignRun rows on each execution (schema.prisma:823). |
CampaignRun | campaign_runs | campaignId, runNumber, status, totalCustomers, processed, recommended, summary | Run | One execution of a Run (campaign). One row per fired schedule tick (schema.prisma:876). |
TriggerRule | trigger_rules | eventType, condition, actionType, actionConfig, priority, cooldownMs | — | Event-driven trigger — when eventType matches condition, fire actionType (schema.prisma:904). |
SimulationRun | simulation_runs | segmentId, decisionFlowKey (mapped to blueprintKey), sampleSize, config, results | — | What-if simulation snapshot. Re-runs a flow over a segment sample without writing decisions (schema.prisma:955). |
AttributionResult | attribution_results | customerId, conversionId, model, touchpoints, totalValue | — | Per-conversion multi-touch attribution result. model is the attribution model name (e.g. linear, time_decay) (schema.prisma:973). |
Geofence | geofences | latitude, longitude, radiusMeters, triggerOn (enter/exit/dwell), action | — | Per-tenant geofence — fires action.type (recommend/notify) when a customer crosses (schema.prisma:2036). |
TenantRegion | tenant_regions | tenantId (PK), region, primary, failoverRegion | — | Per-tenant region tag for active-active routing (W18) (schema.prisma:2292). |
AI & imports
Conversation ledger, AI recommendations, and the AI document import pipeline (V1).| Model | @@map | Key Fields | Relations | Purpose |
|---|---|---|---|---|
Conversation | conversations | userId, title | Tenant, User, ConversationMessage[] | One AI assistant conversation per (tenant, user) (schema.prisma:1807). |
ConversationMessage | conversation_messages | conversationId, role, content, toolInvocations | Conversation | Single message in a conversation. toolInvocations is the tool-call/result trace (schema.prisma:1824). |
AiRecommendation | ai_recommendations | type (policy/rule/segment/content), title, payload, confidence, source (llm/ml_worker), status | — | Pending AI suggestion that can be applied as an entity (schema.prisma:1726). |
CustomerSegmentAi | customer_segments_ai | name, filterRules, schemaId, size, percentage, characteristics, suggestedUse | — | AI-generated customer segment proposal — separate from the user-defined Segment (schema.prisma:1785). |
CreativePerformance | creative_performance | creativeId, channelId, offerId, impressions, clicks, conversions, revenue, periodStart, periodEnd | — | Pre-aggregated creative-level performance window for AI content analysis (schema.prisma:1764). |
AiAttachment (no @@map) | AiAttachment | conversationId, originalFilename, mimeType, sha256, storageKey, pageCount, tokensUsed, estimatedTokens, status | — | Uploaded document (PDF/PPTX) for AI document import. Dedup by [tenantId, sha256] (schema.prisma:2170). |
AiImportProposal (no @@map) | AiImportProposal | attachmentId, entityType, extractedName, extractedFields, sourcePageNumber, sourceQuote, dedupeMatchId, dedupeStrategy, verdict | — | Typed proposal extracted from an attachment with page citations (schema.prisma:2196). |
AiImportApply (no @@map) | AiImportApply | attachmentId, conversationId, appliedById, createdEntityIds, mergedEntityIds, skippedProposalIds, status, revertedAt | — | Atomic apply ledger — records what was created/merged/skipped per import. Soft-revert via revertedAt (schema.prisma:2217). |
AiImportTokenLedger (no @@map) | AiImportTokenLedger | tenantId, yearMonth, tokensUsed | — | Per-tenant per-month LLM token spend for AI document import (schema.prisma:2233). |
AiImportSkipDigest (no @@map) | AiImportSkipDigest | digest, entityType, extractedName | — | Skip-tally bookkeeping — remembers proposals the operator dismissed so re-imports don’t re-surface them (schema.prisma:2243). |
NegotiationSession | negotiation_sessions | customerId, offerId, state, status (active/accepted/rejected/expired) | — | Multi-turn negotiation state (W15). state deserializes to MultiTurnSession from lib/negotiation/multi-turn.ts (schema.prisma:2320). |
Journeys
Multi-step customer journey orchestration — entry conditions, step definitions, and per-customer enrollment state.| Model | @@map | Key Fields | Relations | Purpose |
|---|---|---|---|---|
Journey | journeys | name, definition (JourneyDefinition JSON), entryCondition, maxDurationDays | JourneyEnrollment[] | Visual journey definition — steps, branches, wait/decision/action nodes. definition is the full DAG (schema.prisma:1349). |
JourneyEnrollment | journey_enrollments | journeyId, customerId, currentStepId, status (active/completed/exited), enteredAt, lastStepAt, history | Journey | Per-customer enrollment state. history is the chronological list of visited steps (schema.prisma:1368). |
Flow & pipeline
Data ingestion, schema management, and pipeline runtime.| Model | @@map | Key Fields | Relations | Purpose |
|---|---|---|---|---|
Connector | connectors | type (54 registered types), config, authMethod, authConfig, status, lastTestedAt, lastError | Pipeline[] | External data source connection (S3, Snowflake, Kafka, Salesforce, etc.). type enum lives in src/domain/connector-registry.ts (schema.prisma:501). |
DataSchema | data_schemas | name, tableName (ds_*), entityType, schemaType, linkedSchemaId, joinMapping, summaryColumns, autoEnrich | SchemaField[], Pipeline[], Segment[] | Defines an entity (customer, account, custom). Creates a real Postgres table named ds_{name} (schema.prisma:445). |
SchemaField | schema_fields | name, dataType, length, precision, scale, isNullable, isPrimaryKey, isUnique, isPredictor, defaultValue | DataSchema | Typed column on a DataSchema. isPredictor=true exposes the field to ML model training (schema.prisma:476). |
SchemaJoin | schema_joins | primarySchemaId, primaryKey, foreignSchemaId, foreignKey, joinType (left/inner), autoEnrich | — | Auto-enrichment join definition between two DataSchemas. Used by the runtime to widen customer rows (schema.prisma:2016). |
DataSource | data_sources | connectorKey, sourceConfig, fileFormat, syncMode (full_refresh/incremental_append/incremental_dedupe/cdc), schedule, schemaKey | — | A logical source bound to a Connector. Schedules + sync mode drive the pipeline runner (schema.prisma:716). |
Pipeline | pipelines | connectorId, schemaId, irVersion (always "1.0"), executionConfig, lastRunStatus | Connector, DataSchema, PipelineRun[] | IR-native pipeline. The DAG is in PipelineIrVersion.ir (JSONB) — there is no PipelineNode/PipelineEdge table anymore (schema.prisma:525). |
PipelineIrVersion | pipeline_ir_versions | pipelineId, version, ir, authoredBy (user id or "ai"), comment | — | Version-controlled pipeline IR document. version is monotonically increasing per pipeline (schema.prisma:550). |
PipelineRun | pipeline_runs | pipelineId, status, rowsProcessed, rowsTotal, rowsFailed, validationErrors, loadStrategy (append/truncate/upsert/blue_green), partitions, lastProcessedRow | Pipeline | Single pipeline execution record. lastProcessedRow is the resume checkpoint (schema.prisma:1091). |
Content
Reusable content templates, CMS-sync content items, and template inheritance.| Model | @@map | Key Fields | Relations | Purpose |
|---|---|---|---|---|
Template | templates | category (email/push/sms/blueprint/offer), type, content, variables, isSystem | — | Reusable template — including system-shipped seeds when isSystem=true (schema.prisma:1489). |
ContentItem | (no @@map; inferred ContentItem table) | name, channelType, status (draft/in_review/approved/published/archived), parentTemplateId, sourceType (internal/wordpress/contentful/strapi/sanity), version | ContentItem? (parent), ContentItem[] (children), ContentSource?, ContentVersion[], Creative[] | Channel-typed content payload. CMS-synced when sourceType != "internal" (schema.prisma:1510). |
ContentVersion | (no @@map) | contentItemId, version, content, blocks, personalization, changedBy, changeNote | ContentItem | Immutable historical snapshot of ContentItem (schema.prisma:1545). |
ContentSource | (no @@map) | provider (wordpress/contentful/strapi/sanity), config, syncMode (webhook/polling), autoPublish, mappings, webhookSecret | ContentItem[] | External CMS connection — pulls content into ContentItem rows (schema.prisma:1562). |
Treatment | treatments | name, channel, subject, headline, body, config, impressions, clicks, conversions | — | AI-generated content entity — separate table from Creative (schema.prisma:1921). |
Reports
Scheduled report templates, schedules, and execution runs.| Model | @@map | Key Fields | Relations | Purpose |
|---|---|---|---|---|
ReportTemplate | report_templates | dataSources, sections, formats (default ["pdf"]), narrative ({enabled, prompt?, modelOverride?}), filters, enabled | — | Composable report definition. Reusable across schedules (schema.prisma:2103). |
ReportSchedule | report_schedules | templateId, cronExpression, timezone, destinations, lastRunAt, nextRunAt, lastStatus | — | Cron schedule binding a template to delivery destinations (schema.prisma:2123). |
ReportRun | report_runs | templateId, scheduleId, triggeredBy (default cron), sectionsData, narrativeOutput, artifactPayloads, deliveryResults | — | Per-execution audit row. Artifact payloads are inlined; the runner documents an S3 upgrade path (schema.prisma:2143). |
Behavioral metrics & summaries
User-defined metrics evaluated against the interaction stream.| Model | @@map | Key Fields | Relations | Purpose |
|---|---|---|---|---|
MetricDefinition | metric_definitions | aggregateFunction (count/sum/avg/min/max/ratio), sourceField, windowDays (max 365), groupByDimensions (max 2), filterConditions, sqlFilter (max 500 chars), computeMode (realtime/batch), batchIntervalMin | MetricValue[] | User-defined behavioral metric. Compiled into a query against InteractionSummary (schema.prisma:1641). |
MetricValue | metric_values | metricId, customerId, dimensionKey, value, computedAt | MetricDefinition | Materialized per-customer × dimension value. Unique on [tenantId, metricId, customerId, dimensionKey] (schema.prisma:1670). |
SummaryDefinition | summary_definitions | dimensions, aggregates (default ["count"]), windows (default ["7d","30d"]), isSystem | — | Pluggable shape for InteractionSummary aggregation. isSystem=true rows are undeletable (schema.prisma:1860). |
Configuration
Prisma 7 datasource split
url field is illegal inside schema.prisma under Prisma 7. The connection URL is read from DATABASE_URL by prisma.config.ts and passed to the generated client.
ds_* tables created outside the schema
DataSchema rows do not declare their column shape inside schema.prisma. Each DataSchema row holds metadata; the actual ds_{name} table is created at runtime by platform/src/lib/db/ddl.ts via CREATE TABLE statements when the schema is published. Adding a SchemaField issues ALTER TABLE ds_{name} ADD COLUMN.
This split exists because the column shape is per-tenant and dynamic — it cannot be declared statically in a global schema.prisma. Operators viewing \d ds_* in psql will see real Postgres tables that are not represented in schema.prisma.
Manual SQL for partitioning and migrations
Schema changes that Prisma cannot express are stored inplatform/prisma/manual-sql/:
| File | Purpose |
|---|---|
01_registry_status_check.sql | Adds CHECK constraint to algorithm_models.registryStatus |
02_flow_ir_phase1.sql | Initial flow IR table grants |
04_drop_legacy_pipeline_tables.sql | Drops legacy pipeline_nodes + pipeline_edges (2026-04-28) |
05_campaign_id_additive.sql | Adds nullable campaignId to interaction_history + interaction_summaries |
06_customer_engagement_health.sql | Bootstrap for CustomerEngagementHealth |
07_flow_run_checkpoints.sql | Per-tenant flow checkpoint storage |
08_ai_import.sql | AI document import bootstrap |
09_parity_w11_to_w19.sql | W11–W19 parity-sprint additions |
psql -f or prisma db execute --file.
Honest limits
ds_*tables are not inschema.prisma. The dynamic per-tenant entity tables created fromDataSchemarows live outside the schema file. There is no way to type-check them through Prisma — runtime queries againstds_{name}go through raw SQL or generated query builders.InteractionHistoryis partitioned in production. The model declares one logical table; production deployments range-partitioninteraction_historyby month, which is why/recommendwrites useprisma.$executeRawinstead ofprisma.createMany({ skipDuplicates }). The Prisma model does not declare partitioning.- Soft-delete is not Prisma-enforced. Models with
deletedAtrely on every API route to filterwhere: { deletedAt: null }. There is no global Prisma middleware enforcing this — a raw query or a route that forgets the filter will return soft-deleted rows. CrossOfferConstrainthas no UI surface yet. The model is wired into Lagrangian arbitration in both realtime (lib/arbitration/realtime-wire.ts:194) and batch (lib/batch-executor.ts:489-510) decisioning paths vialib/arbitration/cross-offer.ts, but rows must be inserted directly via SQL or a future admin API — there is no Studio UI for editing them today.- Some operator-internal models have no public API surface.
OutboxEvent,DeadLetterEvent,ChannelDelivery,ExportCheckpoint,MlJobResult,AiImportTokenLedger,AiImportSkipDigest,PolicySnapshot,ApprovalRequestStage,CustomRoleAssignment,VerificationToken,WebAuthnCredential,TenantRegion,ModelAdaptation,CustomerEngagementHealthare read/written by internal code paths only — there is no/api/v1/{model}REST surface for them. - Several alternate storage backends are referenced but not declared here. ScyllaDB / DynamoDB / OpenSearch backends mentioned in
architecture/scaling.mdxare write paths insideplatform/src/lib/adapters; their row shapes are not declared inschema.prisma. Treatschema.prismaas the authoritative shape for the canonical Postgres path only. - AI import models (
AiAttachment,AiImportProposal,AiImportApply,AiImportTokenLedger,AiImportSkipDigest) and content models (ContentItem,ContentVersion,ContentSource) lack@@mapdirectives. Their Postgres table names default to the model name as written (AiAttachment,ContentItem, etc.) rather than snake_case — verify via\dtin psql.
Related
- Schemas API — the
DataSchema+SchemaFieldREST surface that creates the dynamicds_*tables. - Audit Logs API — query the tamper-evident
AuditLogchain. - Decision Traces API — query
DecisionTracerows. - Decisioning Gates — the rule-engine surface backed by
QualificationRule. - Contact Policies API — the
ContactPolicy+ContactPolicyScopesurface. - Volume Constraints — operator semantics for the
VolumeConstraintmodel. - Operations Runbook — operator view of
OutboxEvent,DeadLetterEvent,ChannelDelivery. - Architecture Overview — system-level view above this index.
- Prisma 7 Schema Reference — upstream Prisma docs.