Skip to main content

Data Model

This document describes the database schema, tenant isolation rules, and key entity relationships.

Schema Location​

All table definitions are in shared/schema.ts. This file uses Drizzle ORM with PostgreSQL.

Tenant Isolation Rules​

Hard Rule

Every table with user data must include tenant_id and scope all queries by it.

Pattern (verified from shared/schema.ts):

export const yourTable = pgTable("your_table", {
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
tenantId: varchar("tenant_id").notNull().references(() => tenants.id),
// ... other columns
}, (table) => ({
tenantIdx: index("your_table_tenant_idx").on(table.tenantId)
}));

Query pattern (verified from server/lib/vectorStore.ts:75):

WHERE tenant_id = ${tenantId}

API enforcement (verified from server/routes.ts:161-172):

  • Use requireTenant(req, res) helper in every route
  • Returns null and sends error response if tenant missing/invalid
  • No silent fallbacks allowed

Core Entities​

Tenants (tenants)​

Organization-level isolation unit.

Schema (shared/schema.ts:39-43):

export const tenants = pgTable("tenants", {
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
name: text("name").notNull(),
createdAt: timestamp("created_at").defaultNow().notNull()
});

Packs (packs)​

Requirement packs (e.g., SAMA Pre-Submission).

Schema (shared/schema.ts:67-75):

export const packs = pgTable("packs", {
id: varchar("id").primaryKey(),
name: text("name").notNull(),
description: text("description"),
regulatorCode: varchar("regulator_code", { length: 20 }),
version: varchar("version", { length: 20 }).default("1.0"),
isActive: integer("is_active").default(1),
createdAt: timestamp("created_at").defaultNow().notNull()
});

Documents (documents)​

Evidence files uploaded by users.

Schema (shared/schema.ts:192-218):

ColumnTypePurpose
idvarcharPrimary key (UUID)
tenantIdvarcharForeign key to tenants
originalFilenametextUser's filename
fileTypevarcharExtension (pdf, docx, etc.)
sha256Hashvarchar(64)Deduplication hash
parentDocumentIdvarcharFor ZIP children
statusvarcharLifecycle state
filePathtextStorage path

Indexes: tenantIdx, sha256Idx, statusIdx, parentIdx

Chunks (chunks)​

Text segments from documents for vector search.

Schema (shared/schema.ts:236-250):

ColumnTypePurpose
idvarcharPrimary key
tenantIdvarcharForeign key to tenants
documentIdvarcharForeign key to documents
chunkIndexintegerOrder within document
contenttextText content
pageNumberintegerSource page (nullable)
startOffsetintegerCharacter offset start
endOffsetintegerCharacter offset end
tokenCountintegerToken count

Chunk Embeddings (chunk_embeddings)​

Vector storage for semantic search.

Schema (shared/schema.ts:263-271):

ColumnTypePurpose
idvarcharPrimary key
tenantIdvarcharForeign key to tenants
chunkIdvarcharForeign key to chunks
embeddingvector(1536)OpenAI embedding

Vector type: Custom type defined at lines 7-17.

Runs (runs)​

Assessment batch runs.

Schema (shared/schema.ts:330-366):

ColumnTypePurpose
idvarcharPrimary key
tenantIdvarcharForeign key to tenants
packIdvarcharPack being assessed
environmentvarcharDEV/STAGING/PROD
statusvarcharRun lifecycle state
snapshotStatusvarcharReplay snapshot state
traceIdvarchar(64)OpenTelemetry trace ID
rootSpanIdvarchar(64)Root span ID
snapshot*varcharPinned version IDs (6 fields)

Snapshot fields for deterministic replay:

  • snapshotCriteriaVersionId
  • snapshotCorpusActivationId
  • snapshotRetrievalVersionId
  • snapshotPromptVersionId
  • snapshotChunkingVersionId
  • snapshotAgentVersionId

Run Replay Snapshots (run_replay_snapshots)​

Immutable snapshot store for deterministic replay.

Schema (shared/schema.ts:382-397):

ColumnTypePurpose
idvarcharPrimary key
runIdvarcharForeign key to runs (unique)
tenantIdvarcharForeign key to tenants
snapshotHashvarchar(64)Content hash
assessmentsDatajsonbFrozen assessments
tasksDatajsonbFrozen tasks
exportsDatajsonbFrozen exports
configSnapshotjsonbFrozen config
capturedAttimestampWhen captured

Assessments (assessments)​

Individual requirement evaluations.

Schema (shared/schema.ts:419-437):

ColumnTypePurpose
idvarcharPrimary key
runIdvarcharForeign key to runs
tenantIdvarcharForeign key to tenants
requirementIdvarcharRequirement being assessed
statusvarcharCOMPLETE/PARTIAL/MISSING/FAILED
confidencereal0.0-1.0 confidence score
citationsjsonbEvidence citations
retrievedChunksjsonbChunks used for assessment
reasoningtextLLM reasoning
retrievalModevarcharprimary/fallback/skipped

Tasks (tasks)​

Generated remediation tasks.

Schema (shared/schema.ts:476-502):

ColumnTypePurpose
idvarcharPrimary key
tenantIdvarcharForeign key to tenants
createdByRunIdvarcharRun that created this task
assessmentIdvarcharRelated assessment
titletextTask title
descriptiontextTask description
gapTypevarcharGap classification
suggestedArtifacttextWhat to produce
acceptanceCriteriajsonbSuccess criteria
statusvarcharOPEN/IN_PROGRESS/BLOCKED/DONE
closedByRunIdvarcharRun that closed this task

Status Enums​

EvidenceStatus (Portal)​

Document processing lifecycle.

Definition (shared/schema.ts:160-167):

export const EvidenceStatus = {
UPLOADED: "UPLOADED",
EXTRACTED: "EXTRACTED",
PARSED: "PARSED",
INDEXED: "INDEXED",
READY: "READY",
FAILED: "FAILED"
} as const;

RunStatus​

Assessment run lifecycle.

Definition (shared/schema.ts:294-299):

export const RunStatus = {
PENDING: "PENDING",
IN_PROGRESS: "IN_PROGRESS",
COMPLETED: "COMPLETED",
FAILED: "FAILED"
} as const;

SnapshotStatus​

Deterministic replay snapshot state.

Definition (shared/schema.ts:306-311):

export const SnapshotStatus = {
PENDING: "PENDING", // Run not yet completed
CAPTURED: "CAPTURED", // Snapshot captured - deterministic replay available
FAILED: "FAILED", // Snapshot capture failed
LEGACY: "LEGACY" // Pre-Step 9 run - no snapshot exists
} as const;

AssessmentStatus​

Requirement evaluation outcome.

Definition (shared/schema.ts:318-323):

export const AssessmentStatus = {
COMPLETE: "COMPLETE",
PARTIAL: "PARTIAL",
MISSING: "MISSING",
FAILED: "FAILED"
} as const;

TaskStatus​

Remediation task lifecycle.

Definition (shared/schema.ts:450-455):

export const TaskStatus = {
OPEN: "OPEN",
IN_PROGRESS: "IN_PROGRESS",
BLOCKED: "BLOCKED",
DONE: "DONE"
} as const;

Environment​

Deployment environment.

Definition (shared/schema.ts:283-287):

export const Environment = {
DEV: "DEV",
STAGING: "STAGING",
PROD: "PROD"
} as const;

Entity Relationships​

tenants
│
├─► packs (via pack_bindings)
│
├─► documents
│ │
│ └─► chunks
│ │
│ └─► chunk_embeddings
│
├─► runs
│ │
│ ├─► assessments
│ │ │
│ │ └─► tasks
│ │
│ ├─► run_steps
│ │
│ ├─► run_replay_snapshots
│ │
│ └─► exports
│
└─► audit_logs

Constants and Limits​

File limits (shared/schema.ts:172-179):

export const ALLOWED_FILE_TYPES = ["pdf", "docx", "xlsx", "csv", "png", "jpg", "jpeg", "zip", "txt"] as const;

export const ZIP_LIMITS = {
MAX_DEPTH: 5,
MAX_FILES: 1000,
MAX_TOTAL_SIZE_BYTES: 500 * 1024 * 1024 // 500MB
} as const;

Upload limit (server/routes.ts:88):

limits: { fileSize: 100 * 1024 * 1024 } // 100MB

Schema Migrations​

Use Drizzle's schema push:

npm run db:push

For destructive changes, use:

npm run db:push --force
warning

Never manually alter primary key types. See [important_database_safety_rules] in development guidelines.