chore: establish local platform baseline
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE subject_profile (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
public_id uuid NOT NULL UNIQUE DEFAULT gen_random_uuid(),
|
||||
tenant_id uuid NOT NULL REFERENCES tenant(id),
|
||||
household_id uuid NOT NULL,
|
||||
preferred_name varchar(120) NOT NULL,
|
||||
status varchar(24) NOT NULL DEFAULT 'active'
|
||||
CHECK (status IN ('active', 'inactive', 'deleted')),
|
||||
profile_version bigint NOT NULL DEFAULT 1 CHECK (profile_version > 0),
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
deleted_at timestamptz,
|
||||
CONSTRAINT subject_household_tenant_fk FOREIGN KEY (household_id, tenant_id)
|
||||
REFERENCES household (id, tenant_id),
|
||||
CONSTRAINT subject_id_tenant_key UNIQUE (id, tenant_id)
|
||||
);
|
||||
CREATE INDEX subject_tenant_household_status_idx ON subject_profile (tenant_id, household_id, status);
|
||||
|
||||
CREATE TABLE device (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
public_id uuid NOT NULL UNIQUE DEFAULT gen_random_uuid(),
|
||||
tenant_id uuid REFERENCES tenant(id),
|
||||
serial_digest char(64) NOT NULL UNIQUE,
|
||||
model varchar(120) NOT NULL,
|
||||
hardware_revision varchar(80),
|
||||
status varchar(24) NOT NULL DEFAULT 'registered'
|
||||
CHECK (status IN ('registered', 'quarantined', 'revoked')),
|
||||
credential_ref varchar(500) NOT NULL,
|
||||
minimum_security_version varchar(80),
|
||||
registered_at timestamptz NOT NULL DEFAULT now(),
|
||||
revoked_at timestamptz,
|
||||
version bigint NOT NULL DEFAULT 1 CHECK (version > 0),
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT device_id_tenant_key UNIQUE (id, tenant_id)
|
||||
);
|
||||
CREATE INDEX device_tenant_status_idx ON device (tenant_id, status);
|
||||
|
||||
CREATE TABLE device_binding (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
public_id uuid NOT NULL UNIQUE DEFAULT gen_random_uuid(),
|
||||
tenant_id uuid NOT NULL REFERENCES tenant(id),
|
||||
device_id uuid NOT NULL,
|
||||
household_id uuid NOT NULL,
|
||||
subject_id uuid NOT NULL,
|
||||
bound_at timestamptz NOT NULL DEFAULT now(),
|
||||
unbound_at timestamptz,
|
||||
bound_by uuid,
|
||||
unbound_by uuid,
|
||||
reason varchar(255),
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT device_binding_device_tenant_fk FOREIGN KEY (device_id, tenant_id)
|
||||
REFERENCES device (id, tenant_id),
|
||||
CONSTRAINT device_binding_household_tenant_fk FOREIGN KEY (household_id, tenant_id)
|
||||
REFERENCES household (id, tenant_id),
|
||||
CONSTRAINT device_binding_subject_tenant_fk FOREIGN KEY (subject_id, tenant_id)
|
||||
REFERENCES subject_profile (id, tenant_id),
|
||||
CONSTRAINT device_binding_bound_by_tenant_fk FOREIGN KEY (bound_by, tenant_id)
|
||||
REFERENCES user_account (id, tenant_id),
|
||||
CONSTRAINT device_binding_unbound_by_tenant_fk FOREIGN KEY (unbound_by, tenant_id)
|
||||
REFERENCES user_account (id, tenant_id)
|
||||
);
|
||||
CREATE UNIQUE INDEX device_binding_current_device_key ON device_binding (device_id) WHERE unbound_at IS NULL;
|
||||
CREATE INDEX device_binding_tenant_subject_idx ON device_binding (tenant_id, subject_id) WHERE unbound_at IS NULL;
|
||||
|
||||
CREATE TABLE device_twin (
|
||||
device_id uuid PRIMARY KEY,
|
||||
tenant_id uuid NOT NULL REFERENCES tenant(id),
|
||||
desired_revision bigint NOT NULL DEFAULT 1 CHECK (desired_revision > 0),
|
||||
desired_config jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
reported_revision bigint,
|
||||
reported_config jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
firmware_version varchar(80),
|
||||
board_revision varchar(80),
|
||||
rtc_sdk_version varchar(80),
|
||||
capabilities jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
last_reported_at timestamptz,
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT device_twin_device_tenant_fk FOREIGN KEY (device_id, tenant_id)
|
||||
REFERENCES device (id, tenant_id)
|
||||
);
|
||||
|
||||
CREATE TABLE consent_snapshot (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
public_id uuid NOT NULL UNIQUE DEFAULT gen_random_uuid(),
|
||||
tenant_id uuid NOT NULL REFERENCES tenant(id),
|
||||
subject_id uuid NOT NULL,
|
||||
snapshot_version bigint NOT NULL CHECK (snapshot_version > 0),
|
||||
effective_consents jsonb NOT NULL,
|
||||
source_consent_ids jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT consent_snapshot_subject_tenant_fk FOREIGN KEY (subject_id, tenant_id)
|
||||
REFERENCES subject_profile (id, tenant_id),
|
||||
CONSTRAINT consent_snapshot_id_tenant_key UNIQUE (id, tenant_id)
|
||||
);
|
||||
|
||||
CREATE TABLE context_snapshot (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
public_id uuid NOT NULL UNIQUE DEFAULT gen_random_uuid(),
|
||||
tenant_id uuid NOT NULL REFERENCES tenant(id),
|
||||
subject_id uuid NOT NULL,
|
||||
profile_version bigint NOT NULL CHECK (profile_version > 0),
|
||||
consent_snapshot_id uuid NOT NULL,
|
||||
memory_versions jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
prompt_bundle_version varchar(80) NOT NULL,
|
||||
engine_mode varchar(32) NOT NULL CHECK (engine_mode IN ('s2s_pure', 's2s_hybrid', 'cascade')),
|
||||
content_digest char(64) NOT NULL,
|
||||
sanitized_summary varchar(1000),
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT context_snapshot_subject_tenant_fk FOREIGN KEY (subject_id, tenant_id)
|
||||
REFERENCES subject_profile (id, tenant_id),
|
||||
CONSTRAINT context_snapshot_consent_tenant_fk FOREIGN KEY (consent_snapshot_id, tenant_id)
|
||||
REFERENCES consent_snapshot (id, tenant_id),
|
||||
CONSTRAINT context_snapshot_id_tenant_key UNIQUE (id, tenant_id)
|
||||
);
|
||||
|
||||
CREATE TABLE conversation (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
public_id uuid NOT NULL UNIQUE DEFAULT gen_random_uuid(),
|
||||
tenant_id uuid NOT NULL REFERENCES tenant(id),
|
||||
household_id uuid NOT NULL,
|
||||
subject_id uuid NOT NULL,
|
||||
device_id uuid NOT NULL,
|
||||
consent_snapshot_id uuid NOT NULL,
|
||||
context_snapshot_id uuid NOT NULL,
|
||||
provider_task_ref varchar(200) NOT NULL UNIQUE,
|
||||
engine_mode varchar(32) NOT NULL CHECK (engine_mode IN ('s2s_pure', 's2s_hybrid', 'cascade')),
|
||||
retention_mode varchar(32) NOT NULL CHECK (retention_mode IN ('none', 'transcript_only', 'transcript_and_audio')),
|
||||
status varchar(32) NOT NULL CHECK (status IN ('PREPARING', 'ROOM_ISSUED', 'STARTING_AGENT', 'ACTIVE', 'STOPPING', 'COMPLETED', 'FAILED', 'EXPIRED')),
|
||||
allocation_expires_at timestamptz NOT NULL,
|
||||
lease_expires_at timestamptz,
|
||||
last_heartbeat_seq bigint NOT NULL DEFAULT 0 CHECK (last_heartbeat_seq >= 0),
|
||||
started_at timestamptz,
|
||||
ended_at timestamptz,
|
||||
stop_reason varchar(64),
|
||||
failure_code varchar(64),
|
||||
version bigint NOT NULL DEFAULT 1 CHECK (version > 0),
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT conversation_household_tenant_fk FOREIGN KEY (household_id, tenant_id)
|
||||
REFERENCES household (id, tenant_id),
|
||||
CONSTRAINT conversation_subject_tenant_fk FOREIGN KEY (subject_id, tenant_id)
|
||||
REFERENCES subject_profile (id, tenant_id),
|
||||
CONSTRAINT conversation_device_tenant_fk FOREIGN KEY (device_id, tenant_id)
|
||||
REFERENCES device (id, tenant_id),
|
||||
CONSTRAINT conversation_consent_tenant_fk FOREIGN KEY (consent_snapshot_id, tenant_id)
|
||||
REFERENCES consent_snapshot (id, tenant_id),
|
||||
CONSTRAINT conversation_context_tenant_fk FOREIGN KEY (context_snapshot_id, tenant_id)
|
||||
REFERENCES context_snapshot (id, tenant_id),
|
||||
CONSTRAINT conversation_id_tenant_key UNIQUE (id, tenant_id)
|
||||
);
|
||||
CREATE INDEX conversation_tenant_subject_time_idx ON conversation (tenant_id, subject_id, created_at DESC);
|
||||
CREATE INDEX conversation_device_status_idx ON conversation (device_id, status);
|
||||
CREATE UNIQUE INDEX conversation_one_active_per_device ON conversation (device_id)
|
||||
WHERE status NOT IN ('COMPLETED', 'FAILED', 'EXPIRED');
|
||||
|
||||
CREATE TABLE conversation_state_history (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
conversation_id uuid NOT NULL REFERENCES conversation(id),
|
||||
from_status varchar(32),
|
||||
to_status varchar(32) NOT NULL,
|
||||
reason varchar(255),
|
||||
source varchar(40) NOT NULL CHECK (source IN ('device', 'platform', 'provider', 'worker', 'operator')),
|
||||
provider_event_id uuid,
|
||||
request_id varchar(128),
|
||||
occurred_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX conversation_history_time_idx ON conversation_state_history (conversation_id, occurred_at, id);
|
||||
|
||||
CREATE TABLE rtc_task (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
conversation_id uuid NOT NULL UNIQUE REFERENCES conversation(id),
|
||||
provider varchar(40) NOT NULL,
|
||||
provider_task_ref varchar(200) NOT NULL UNIQUE,
|
||||
room_id varchar(200) NOT NULL UNIQUE,
|
||||
device_rtc_user_id varchar(200) NOT NULL,
|
||||
agent_rtc_user_id varchar(200) NOT NULL,
|
||||
status varchar(32) NOT NULL CHECK (status IN ('ALLOCATED', 'STARTING', 'ACTIVE', 'STOPPING', 'COMPLETED', 'FAILED', 'UNKNOWN')),
|
||||
lease_expires_at timestamptz,
|
||||
start_attempts integer NOT NULL DEFAULT 0 CHECK (start_attempts >= 0),
|
||||
stop_attempts integer NOT NULL DEFAULT 0 CHECK (stop_attempts >= 0),
|
||||
last_checked_at timestamptz,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT rtc_distinct_users CHECK (device_rtc_user_id <> agent_rtc_user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE provider_event (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id uuid NOT NULL REFERENCES tenant(id),
|
||||
conversation_id uuid NOT NULL,
|
||||
provider varchar(40) NOT NULL,
|
||||
provider_event_key varchar(255) NOT NULL,
|
||||
provider_task_ref varchar(200) NOT NULL,
|
||||
event_type varchar(100) NOT NULL,
|
||||
occurred_at timestamptz NOT NULL,
|
||||
received_at timestamptz NOT NULL DEFAULT now(),
|
||||
payload_digest char(64) NOT NULL,
|
||||
sanitized_payload jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
processing_status varchar(24) NOT NULL DEFAULT 'pending'
|
||||
CHECK (processing_status IN ('pending', 'processed', 'ignored', 'failed')),
|
||||
processed_at timestamptz,
|
||||
last_error varchar(500),
|
||||
CONSTRAINT provider_event_conversation_tenant_fk FOREIGN KEY (conversation_id, tenant_id)
|
||||
REFERENCES conversation (id, tenant_id),
|
||||
CONSTRAINT provider_event_key UNIQUE (provider, provider_event_key)
|
||||
);
|
||||
CREATE INDEX provider_event_conversation_time_idx ON provider_event (conversation_id, received_at);
|
||||
CREATE INDEX provider_event_pending_idx ON provider_event (processing_status, received_at)
|
||||
WHERE processing_status IN ('pending', 'failed');
|
||||
|
||||
COMMIT;
|
||||
Reference in New Issue
Block a user