Files
story/migrations/000009_privacy_request.up.sql
T

70 lines
3.6 KiB
PL/PgSQL
Raw Normal View History

2026-08-26 06:41:07 +08:00
BEGIN;
CREATE TABLE privacy_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),
subject_id uuid NOT NULL,
request_type varchar(32) NOT NULL
CHECK (request_type IN ('ACCESS', 'CORRECTION', 'CONSENT_WITHDRAWAL', 'DELETE')),
scope jsonb NOT NULL DEFAULT '{}'::jsonb CHECK (jsonb_typeof(scope)='object'),
requested_by uuid NOT NULL,
status varchar(32) NOT NULL DEFAULT 'SUBMITTED'
CHECK (status IN ('SUBMITTED', 'VERIFYING', 'EXECUTING', 'COMPLETED', 'PARTIAL_FAILED')),
deadline_at timestamptz,
legal_hold boolean NOT NULL DEFAULT false,
result_summary jsonb NOT NULL DEFAULT '{}'::jsonb CHECK (jsonb_typeof(result_summary)='object'),
idempotency_key varchar(255) NOT NULL,
request_digest char(64) NOT NULL,
version bigint NOT NULL DEFAULT 1 CHECK (version > 0),
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
completed_at timestamptz,
CONSTRAINT privacy_request_subject_tenant_fk
FOREIGN KEY (subject_id, tenant_id) REFERENCES subject_profile (id, tenant_id),
CONSTRAINT privacy_request_requester_tenant_fk
FOREIGN KEY (requested_by, tenant_id) REFERENCES user_account (id, tenant_id),
CONSTRAINT privacy_request_actor_idempotency_key
UNIQUE (tenant_id, requested_by, idempotency_key)
);
CREATE INDEX privacy_request_subject_time_idx
ON privacy_request (tenant_id, subject_id, created_at DESC, id DESC);
CREATE INDEX privacy_request_work_idx
ON privacy_request (status, updated_at) WHERE status IN ('SUBMITTED', 'VERIFYING', 'EXECUTING', 'PARTIAL_FAILED');
CREATE TABLE privacy_subtask (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
public_id uuid NOT NULL UNIQUE DEFAULT gen_random_uuid(),
privacy_request_id uuid NOT NULL REFERENCES privacy_request(id) ON DELETE CASCADE,
subsystem varchar(32) NOT NULL
CHECK (subsystem IN ('postgresql', 'redis', 'object_storage', 'pgvector', 'provider_index', 'export_files')),
target_type varchar(64) NOT NULL,
target_ref varchar(300) NOT NULL,
status varchar(24) NOT NULL DEFAULT 'PENDING'
CHECK (status IN ('PENDING', 'RUNNING', 'COMPLETED', 'FAILED', 'SKIPPED')),
attempts integer NOT NULL DEFAULT 0 CHECK (attempts >= 0),
next_attempt_at timestamptz,
last_error varchar(500),
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
completed_at timestamptz,
CONSTRAINT privacy_subtask_target_key
UNIQUE (privacy_request_id, subsystem, target_type, target_ref)
);
CREATE INDEX privacy_subtask_work_idx
ON privacy_subtask (status, next_attempt_at, created_at)
WHERE status IN ('PENDING', 'RUNNING', 'FAILED');
CREATE TABLE tombstone (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id uuid NOT NULL REFERENCES tenant(id),
resource_type varchar(80) NOT NULL,
resource_digest char(64) NOT NULL,
deleted_at timestamptz NOT NULL DEFAULT now(),
deletion_request_id uuid NOT NULL REFERENCES privacy_request(id),
retention_reason varchar(500) NOT NULL,
CONSTRAINT tombstone_resource_key UNIQUE (tenant_id, resource_type, resource_digest)
);
COMMIT;