ClearFrame uses PostgreSQL 16+ as its single source of truth for all pipeline state, entity relationships, financial accounting, and cryptographic audit records.
Two architectural invariants govern the entire database:
- Financial Integrity: All monetary values are represented as 64-bit integer micro-dollars (
bigint), eliminating floating-point rounding errors. - Append-Only History: Audit history and chain-of-title records are strictly immutable and protected by PostgreSQL row-level triggers and SHA-256 cryptographic chaining.
erDiagram
orgs ||--o{ users : "has members"
orgs ||--o{ productions : "owns"
productions ||--o{ cuts : "has versions (Pass n)"
productions ||--o{ findings : "contains"
productions ||--o{ activity : "logs feed"
productions ||--o{ cost_events : "tracks spend"
productions ||--o{ ledger : "hash-chains events"
productions ||--o{ reports : "generates E&O snapshots"
productions ||--o{ jobs : "schedules pipeline steps"
findings ||--o{ evidence : "cites retrieved sources"
findings ||--o{ decisions : "records counsel resolutions"
findings ||--o| outreach : "drafts license inquiry"
findings ||--o| watches : "arms continuous monitoring"
users ||--o{ decisions : "author of"
users ||--o{ reports : "signs"
Multi-tenant isolation root. Every user, production, finding, and spend event is partitioned by organization ID.
CREATE TABLE orgs (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
name text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);Authenticated participants with strict role-based access control (RBAC).
CREATE TYPE user_role AS ENUM ('producer', 'coordinator', 'counsel', 'reviewer');
CREATE TABLE users (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
org_id uuid NOT NULL REFERENCES orgs(id) ON DELETE CASCADE,
email text NOT NULL,
name text NOT NULL,
password_hash text NOT NULL,
role user_role NOT NULL DEFAULT 'producer',
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE UNIQUE INDEX users_email_idx ON users (lower(email));
CREATE INDEX users_org_idx ON users (org_id);The container for a film or television project, maintaining the spend ledger and clearance lifecycle.
CREATE TYPE production_status AS ENUM
('draft', 'breakdown', 'running', 'review', 'complete', 'failed');
CREATE TABLE productions (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
org_id uuid NOT NULL REFERENCES orgs(id) ON DELETE CASCADE,
title text NOT NULL,
format text NOT NULL DEFAULT 'Feature film',
status production_status NOT NULL DEFAULT 'draft',
budget_cap_micros bigint NOT NULL,
spent_micros bigint NOT NULL DEFAULT 0,
created_by uuid REFERENCES users(id),
error text,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX productions_org_idx ON productions (org_id, updated_at DESC);Represents an individual revision or pass of a screenplay (e.g., Shooting Draft, White Revision, Blue Revision).
CREATE TABLE cuts (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
production_id uuid NOT NULL REFERENCES productions(id) ON DELETE CASCADE,
n int NOT NULL, -- Pass sequence number (Pass 1, Pass 2, etc.)
filename text NOT NULL,
storage_key text NOT NULL, -- GCS or local storage pointer
mime_type text NOT NULL,
content_hash text NOT NULL, -- SHA-256 of raw file bytes
stats jsonb NOT NULL DEFAULT '{}', -- Page count, token count, cue counts
created_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (production_id, n)
);The central clearance record for each third-party element discovered in the project.
CREATE TYPE finding_status AS ENUM (
'queued', 'researching', 'verifying', 'tracing', 'assessing',
'review', 'cleared', 'approved', 'licensed', 'replaced', 'rejected',
'withdrawn', 'held', 'failed'
);
CREATE TYPE risk_level AS ENUM ('LOW', 'MEDIUM', 'HIGH');
CREATE TABLE findings (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
production_id uuid NOT NULL REFERENCES productions(id) ON DELETE CASCADE,
first_cut_id uuid REFERENCES cuts(id),
pass_n int NOT NULL DEFAULT 1,
item text NOT NULL, -- Display title (e.g. "Midnight City")
category text NOT NULL, -- music_cue, brand, artwork, likeness, footage
scene text, -- Scene number or slug (e.g. "SCENE 14")
page text, -- Page reference (e.g. "p. 22")
context text NOT NULL DEFAULT '', -- Narrative context / excerpt
item_key text NOT NULL, -- CATEGORY|normalised_name (Unique per production)
content_hash text NOT NULL, -- SHA-256 of (scene + page + context)
status finding_status NOT NULL DEFAULT 'queued',
risk risk_level,
confidence numeric(4,3), -- Range: 0.000 to 1.000
summary text,
assessment text,
recommendation text,
verification jsonb, -- Adversarial verifier report
chains jsonb NOT NULL DEFAULT '[]', -- Dual chain-of-title nodes (Master & Publishing)
tier text,
parallel_run_id text,
error text,
stages_done text[] NOT NULL DEFAULT '{}', -- Checkpoint array for pipeline resume
research_sources jsonb, -- Cache of verified URLs
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (production_id, item_key)
);
CREATE INDEX findings_prod_idx ON findings (production_id, status);Verified live-web source citations supporting a finding. Links are validated against the real retrieval pool.
CREATE TABLE evidence (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
finding_id uuid NOT NULL REFERENCES findings(id) ON DELETE CASCADE,
url text NOT NULL,
title text,
domain text NOT NULL,
stance text NOT NULL CHECK (stance IN ('supports', 'conflicts', 'context')),
note text NOT NULL DEFAULT '',
publish_date date,
snapshot_key text, -- Stored copy of webpage at crawl time
retrieved_at timestamptz NOT NULL DEFAULT now(),
round int NOT NULL DEFAULT 1,
UNIQUE (finding_id, url)
);
CREATE INDEX evidence_finding_idx ON evidence (finding_id, retrieved_at);Counsel resolutions that legally approve, license, replace, or reject a finding.
CREATE TABLE decisions (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
finding_id uuid NOT NULL REFERENCES findings(id) ON DELETE CASCADE,
action text NOT NULL CHECK (action IN ('approved','licensed','replaced','rejected')),
rationale text NOT NULL DEFAULT '',
actor_id uuid REFERENCES users(id),
actor_name text NOT NULL,
actor_role user_role NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);Drafted rights-holder licensing inquiries created by autonomous agents and gated behind counsel authorization.
CREATE TABLE outreach (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
finding_id uuid NOT NULL REFERENCES findings(id) ON DELETE CASCADE UNIQUE,
addressed_to text NOT NULL,
subject text NOT NULL,
body text NOT NULL,
state text NOT NULL DEFAULT 'draft' CHECK (state IN ('drafting','draft','approved','failed')),
approved_by uuid REFERENCES users(id),
approved_name text,
approved_at timestamptz,
error text,
created_at timestamptz NOT NULL DEFAULT now()
);Monitors armed by the Sentinel agent to detect catalog acquisitions, litigation, or ownership disputes on live web endpoints.
CREATE TABLE watches (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
finding_id uuid NOT NULL REFERENCES findings(id) ON DELETE CASCADE UNIQUE,
provider text NOT NULL DEFAULT 'internal',
provider_watch_id text,
state text NOT NULL DEFAULT 'active' CHECK (state IN ('active','paused')),
last_checked_at timestamptz,
next_check_at timestamptz NOT NULL DEFAULT now(),
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX watches_due_idx ON watches (next_check_at) WHERE state = 'active';Human-readable event feed displayed in the clearance workspace and broadcast via Server-Sent Events.
CREATE TABLE activity (
id bigserial PRIMARY KEY,
production_id uuid NOT NULL REFERENCES productions(id) ON DELETE CASCADE,
finding_id uuid REFERENCES findings(id) ON DELETE CASCADE,
stage text NOT NULL,
text text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX activity_prod_idx ON activity (production_id, id DESC);Audit trail of every LLM token and web research query executed by ClearFrame.
CREATE TABLE cost_events (
id bigserial PRIMARY KEY,
production_id uuid NOT NULL REFERENCES productions(id) ON DELETE CASCADE,
finding_id uuid REFERENCES findings(id) ON DELETE SET NULL,
stage text NOT NULL,
provider text NOT NULL, -- 'gemini-2.5-pro', 'gemini-2.5-flash', 'parallel'
detail text,
input_tokens int NOT NULL DEFAULT 0,
output_tokens int NOT NULL DEFAULT 0,
units int NOT NULL DEFAULT 0,
cost_micros bigint NOT NULL DEFAULT 0, -- 1 micro-dollar = $0.000001 USD
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX cost_prod_idx ON cost_events (production_id);Transactional worker queue executed with PostgreSQL FOR UPDATE SKIP LOCKED.
CREATE TABLE jobs (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
production_id uuid REFERENCES productions(id) ON DELETE CASCADE,
kind text NOT NULL, -- 'breakdown', 'investigate', 'sweep'
payload jsonb NOT NULL DEFAULT '{}',
state text NOT NULL DEFAULT 'ready' CHECK (state IN ('ready','running','done','failed')),
attempts int NOT NULL DEFAULT 0,
max_attempts int NOT NULL DEFAULT 3,
run_at timestamptz NOT NULL DEFAULT now(),
locked_at timestamptz,
locked_by text,
last_error text,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX jobs_claim_idx ON jobs (state, run_at) WHERE state = 'ready';
CREATE INDEX jobs_prod_idx ON jobs (production_id, state);SHA-256 hash-chained immutable audit log.
CREATE TABLE ledger (
production_id uuid NOT NULL REFERENCES productions(id) ON DELETE CASCADE,
seq int NOT NULL,
ts timestamptz NOT NULL DEFAULT now(),
actor text NOT NULL,
event jsonb NOT NULL,
prev_hash text NOT NULL,
hash text NOT NULL,
PRIMARY KEY (production_id, seq)
);
-- Trigger: Refuse UPDATE unconditionally; refuse DELETE unless explicitly opted-in
CREATE OR REPLACE FUNCTION ledger_is_append_only() RETURNS trigger AS $$
BEGIN
IF TG_OP = 'DELETE' AND current_setting('clearframe.allow_purge', true) = 'on' THEN
RETURN OLD;
END IF;
RAISE EXCEPTION 'ledger is append-only (set clearframe.allow_purge to purge)';
END; $$ LANGUAGE plpgsql;
CREATE TRIGGER ledger_no_mutate
BEFORE UPDATE OR DELETE ON ledger
FOR EACH ROW EXECUTE FUNCTION ledger_is_append_only();Errors & Omissions (E&O) insurance clearance reports generated from a snapshot of the ledger.
CREATE TABLE reports (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
production_id uuid NOT NULL REFERENCES productions(id) ON DELETE CASCADE,
storage_key text, -- PDF asset path
ledger_head text NOT NULL, -- SHA-256 hash of latest ledger entry
ledger_length int NOT NULL, -- Sequence count
snapshot jsonb NOT NULL, -- Complete finding and chain-of-title state
signed_by uuid REFERENCES users(id),
signed_name text,
signed_role user_role,
signed_at timestamptz,
generated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX reports_prod_idx ON reports (production_id, generated_at DESC);stateDiagram-v2
[*] --> queued
queued --> researching : Worker Claims Job
researching --> verifying : Parallel Recon Done
verifying --> tracing : Adversarial Pass
verifying --> researching : Challenge Filed (Retry)
tracing --> assessing : Dual-Chain Traced
assessing --> review : Risk Counsel Scored
review --> approved : Counsel Action (No License Needed)
review --> licensed : Counsel Action (Agreement Signed)
review --> replaced : Counsel Action (Asset Swapped)
review --> rejected : Counsel Action (Asset Dropped)
review --> held : Counsel Action (Investigation Pending)
approved --> researching : Sentinel Watch Alert Re-opens
licensed --> researching : Sentinel Watch Alert Re-opens
When a new cut (Pass
-
item_keyis calculated asUPPER(category) + '|' + NORMALIZE(item_name). -
content_hashis calculated asSHA-256(scene + page + context). - If
item_keyexists in Pass$N$ andcontent_hashmatches:- Status and clearance determinations are carried forward untouched (Cost: $0.00).
- If
item_keyexists butcontent_hashhas changed:- Status resets to
queuedand re-enters the pipeline for contextual re-assessment.
- Status resets to
- If
item_keywas present in Pass$N$ but is omitted in Pass$N+1$ :- Status transitions to
withdrawn(the element was cut from the film, never deleted from the ledger).
- Status transitions to