-- +goose Up ALTER TABLE task_events RENAME TO task_events_v7; CREATE TABLE task_events ( id TEXT PRIMARY KEY NOT NULL CHECK (length(id) = 36), task_id TEXT NOT NULL REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE CASCADE, event_type TEXT NOT NULL CHECK ( event_type IN ( 'TASK_CREATED', 'TASK_CLAIMED', 'TASK_RECLAIMED', 'TASK_RELEASED', 'TASK_STARTED', 'TASK_CANCEL_REQUESTED', 'TASK_CANCELED', 'CANDIDATES_READY', 'ORDER_AUTHORIZATION_CREATED' ) ), message TEXT NOT NULL, occurred_at TEXT NOT NULL, actor_user_id TEXT REFERENCES users(id) ON UPDATE RESTRICT ON DELETE RESTRICT, actor_device_id TEXT REFERENCES devices(id) ON UPDATE RESTRICT ON DELETE RESTRICT ); INSERT INTO task_events ( id, task_id, event_type, message, occurred_at, actor_user_id, actor_device_id ) SELECT id, task_id, event_type, message, occurred_at, actor_user_id, actor_device_id FROM task_events_v7; DROP TABLE task_events_v7; CREATE INDEX task_events_task_occurred_idx ON task_events (task_id, occurred_at ASC, id ASC); CREATE INDEX task_events_actor_user_idx ON task_events (actor_user_id, occurred_at DESC, id DESC); CREATE INDEX task_events_actor_device_idx ON task_events (actor_device_id, occurred_at DESC, id DESC); CREATE TABLE order_authorizations ( id TEXT PRIMARY KEY NOT NULL CHECK (length(id) = 36), task_id TEXT NOT NULL REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE RESTRICT, execution_id TEXT NOT NULL REFERENCES task_executions(id) ON UPDATE RESTRICT ON DELETE RESTRICT, authorization_version INTEGER NOT NULL CHECK (authorization_version > 0), candidate_key TEXT NOT NULL REFERENCES candidate_observation_identities(candidate_key) ON UPDATE RESTRICT ON DELETE RESTRICT, task_content_sha256 TEXT NOT NULL CHECK ( length(task_content_sha256) = 64 AND task_content_sha256 NOT GLOB '*[^0-9a-f]*' ), task_version INTEGER NOT NULL CHECK (task_version > 0), review_id TEXT NOT NULL REFERENCES candidate_human_reviews(id) ON UPDATE RESTRICT ON DELETE RESTRICT, review_version INTEGER NOT NULL CHECK (review_version > 0), user_id TEXT NOT NULL REFERENCES users(id) ON UPDATE RESTRICT ON DELETE RESTRICT, device_id TEXT NOT NULL REFERENCES devices(id) ON UPDATE RESTRICT ON DELETE RESTRICT, claim_generation INTEGER NOT NULL CHECK (claim_generation > 0), original_sku TEXT NOT NULL CHECK ( length(trim(original_sku)) > 0 AND length(CAST(original_sku AS BLOB)) <= 512 ), quantity INTEGER NOT NULL CHECK (quantity > 0), candidate_sku_text TEXT NOT NULL CHECK (length(CAST(candidate_sku_text AS BLOB)) <= 512), candidate_price_text TEXT NOT NULL CHECK (length(CAST(candidate_price_text AS BLOB)) <= 64), card_signature TEXT NOT NULL CHECK ( length(card_signature) = 64 AND card_signature NOT GLOB '*[^0-9a-f]*' ), detail_signature TEXT NOT NULL CHECK ( length(detail_signature) = 64 AND detail_signature NOT GLOB '*[^0-9a-f]*' ), detail_evidence_sha256 TEXT NOT NULL CHECK ( length(detail_evidence_sha256) = 64 AND detail_evidence_sha256 NOT GLOB '*[^0-9a-f]*' ), specification_evidence_sha256 TEXT NOT NULL CHECK ( length(specification_evidence_sha256) = 64 AND specification_evidence_sha256 NOT GLOB '*[^0-9a-f]*' ), status TEXT NOT NULL CHECK ( status IN ( 'PENDING_DELIVERY', 'DELIVERED', 'ACKNOWLEDGED', 'EXECUTING', 'CONSUMED', 'FAILED', 'REVOKED', 'SUPERSEDED' ) ), supersedes_authorization_id TEXT REFERENCES order_authorizations(id) ON UPDATE RESTRICT ON DELETE RESTRICT, created_by_user_id TEXT NOT NULL REFERENCES users(id) ON UPDATE RESTRICT ON DELETE RESTRICT, created_at TEXT NOT NULL, delivered_at TEXT, acknowledged_at TEXT, execution_started_at TEXT, consumed_at TEXT, failed_at TEXT, revoked_at TEXT, failure_code TEXT, failure_message TEXT, UNIQUE (execution_id, authorization_version) ); CREATE UNIQUE INDEX order_authorizations_active_execution_idx ON order_authorizations (execution_id) WHERE status IN ( 'PENDING_DELIVERY', 'DELIVERED', 'ACKNOWLEDGED', 'EXECUTING' ); CREATE INDEX order_authorizations_task_created_idx ON order_authorizations (task_id, created_at DESC, id DESC); CREATE TABLE admin_order_authorization_requests ( actor_user_id TEXT NOT NULL REFERENCES users(id) ON UPDATE RESTRICT ON DELETE RESTRICT, idempotency_key TEXT NOT NULL CHECK ( length(trim(idempotency_key)) > 0 AND length(CAST(idempotency_key AS BLOB)) <= 128 ), request_sha256 TEXT NOT NULL CHECK ( length(request_sha256) = 64 AND request_sha256 NOT GLOB '*[^0-9a-f]*' ), task_id TEXT NOT NULL REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE RESTRICT, authorization_id TEXT NOT NULL REFERENCES order_authorizations(id) ON UPDATE RESTRICT ON DELETE RESTRICT, created_at TEXT NOT NULL, PRIMARY KEY (actor_user_id, idempotency_key) ); -- +goose Down CREATE TEMP TABLE order_authorizations_v8_down_guard ( allowed INTEGER NOT NULL CHECK (allowed = 1) ); INSERT INTO order_authorizations_v8_down_guard (allowed) SELECT CASE WHEN EXISTS (SELECT 1 FROM order_authorizations) OR EXISTS ( SELECT 1 FROM task_events WHERE event_type IN ( 'CANDIDATES_READY', 'ORDER_AUTHORIZATION_CREATED' ) ) THEN 0 ELSE 1 END; DROP TABLE order_authorizations_v8_down_guard; DROP TABLE admin_order_authorization_requests; DROP TABLE order_authorizations; ALTER TABLE task_events RENAME TO task_events_v8; CREATE TABLE task_events ( id TEXT PRIMARY KEY NOT NULL CHECK (length(id) = 36), task_id TEXT NOT NULL REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE CASCADE, event_type TEXT NOT NULL CHECK ( event_type IN ( 'TASK_CREATED', 'TASK_CLAIMED', 'TASK_RECLAIMED', 'TASK_RELEASED', 'TASK_STARTED', 'TASK_CANCEL_REQUESTED', 'TASK_CANCELED' ) ), message TEXT NOT NULL, occurred_at TEXT NOT NULL, actor_user_id TEXT REFERENCES users(id) ON UPDATE RESTRICT ON DELETE RESTRICT, actor_device_id TEXT REFERENCES devices(id) ON UPDATE RESTRICT ON DELETE RESTRICT ); INSERT INTO task_events ( id, task_id, event_type, message, occurred_at, actor_user_id, actor_device_id ) SELECT id, task_id, event_type, message, occurred_at, actor_user_id, actor_device_id FROM task_events_v8; DROP TABLE task_events_v8; CREATE INDEX task_events_task_occurred_idx ON task_events (task_id, occurred_at ASC, id ASC); CREATE INDEX task_events_actor_user_idx ON task_events (actor_user_id, occurred_at DESC, id DESC); CREATE INDEX task_events_actor_device_idx ON task_events (actor_device_id, occurred_at DESC, id DESC);