Files
story/migrations/000027_ops_sensitive_access.up.sql
T

63 lines
3.7 KiB
SQL

CREATE TABLE ops_sensitive_access_request (
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),
conversation_id uuid NOT NULL,
requester_user_id uuid NOT NULL,
capabilities text[] NOT NULL,
reason varchar(500) NOT NULL,
requested_expires_at timestamptz NOT NULL,
status varchar(24) NOT NULL DEFAULT 'PENDING'
CHECK (status IN ('PENDING','APPROVED','REJECTED','REVOKED','EXPIRED')),
reviewed_by uuid,
review_reason varchar(500),
reviewed_at timestamptz,
revoked_by uuid,
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 ops_sensitive_access_conversation_tenant_fk FOREIGN KEY (conversation_id,tenant_id) REFERENCES conversation(id,tenant_id),
CONSTRAINT ops_sensitive_access_requester_tenant_fk FOREIGN KEY (requester_user_id,tenant_id) REFERENCES user_account(id,tenant_id),
CONSTRAINT ops_sensitive_access_reviewer_tenant_fk FOREIGN KEY (reviewed_by,tenant_id) REFERENCES user_account(id,tenant_id),
CONSTRAINT ops_sensitive_access_revoker_tenant_fk FOREIGN KEY (revoked_by,tenant_id) REFERENCES user_account(id,tenant_id),
CONSTRAINT ops_sensitive_access_capabilities_check CHECK (
capabilities=ARRAY['RECORDING_PLAY']::text[]
OR capabilities=ARRAY['TRANSCRIPT_READ']::text[]
OR capabilities=ARRAY['RECORDING_PLAY','TRANSCRIPT_READ']::text[]
),
CONSTRAINT ops_sensitive_access_expiry_check CHECK (requested_expires_at > created_at AND requested_expires_at <= created_at + interval '4 hours'),
CONSTRAINT ops_sensitive_access_review_check CHECK (
(status='PENDING' AND reviewed_by IS NULL AND reviewed_at IS NULL)
OR (status<>'PENDING')
)
);
CREATE UNIQUE INDEX ops_sensitive_access_one_open_key
ON ops_sensitive_access_request(tenant_id,conversation_id,requester_user_id)
WHERE status IN ('PENDING','APPROVED');
CREATE INDEX ops_sensitive_access_review_queue_idx
ON ops_sensitive_access_request(tenant_id,status,created_at DESC);
CREATE TABLE ops_sensitive_access_log (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id uuid NOT NULL REFERENCES tenant(id),
access_request_id uuid NOT NULL REFERENCES ops_sensitive_access_request(id),
actor_user_id uuid NOT NULL,
conversation_id uuid NOT NULL,
media_segment_id uuid,
capability varchar(32) NOT NULL CHECK (capability IN ('TRANSCRIPT_READ','RECORDING_PLAY')),
result varchar(16) NOT NULL CHECK (result IN ('SUCCESS','DENIED')),
reason_code varchar(64),
request_id varchar(128),
accessed_at timestamptz NOT NULL DEFAULT now(),
CONSTRAINT ops_sensitive_access_log_actor_tenant_fk FOREIGN KEY (actor_user_id,tenant_id) REFERENCES user_account(id,tenant_id),
CONSTRAINT ops_sensitive_access_log_conversation_tenant_fk FOREIGN KEY (conversation_id,tenant_id) REFERENCES conversation(id,tenant_id),
CONSTRAINT ops_sensitive_access_log_segment_tenant_fk FOREIGN KEY (media_segment_id,tenant_id) REFERENCES media_segment(id,tenant_id)
);
CREATE INDEX ops_sensitive_access_log_request_time_idx
ON ops_sensitive_access_log(access_request_id,accessed_at DESC);
CREATE INDEX ops_sensitive_access_log_tenant_time_idx
ON ops_sensitive_access_log(tenant_id,accessed_at DESC);