Files
cmroubao/backend-api/migrations/00005_execution_results.sql
T

205 lines
7.1 KiB
SQL
Raw Normal View History

2026-07-27 12:23:05 +08:00
-- +goose Up
CREATE TABLE execution_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,
execution_id TEXT NOT NULL
REFERENCES task_executions(id) ON UPDATE RESTRICT ON DELETE CASCADE,
step TEXT NOT NULL
CHECK (
length(trim(step)) > 0
AND length(CAST(step AS BLOB)) <= 64
),
event_type TEXT NOT NULL
CHECK (
length(trim(event_type)) > 0
AND length(CAST(event_type AS BLOB)) <= 64
),
message TEXT NOT NULL
CHECK (length(CAST(message AS BLOB)) <= 1000),
occurred_at TEXT NOT NULL,
received_at TEXT NOT NULL,
received_after_execution_expiry INTEGER NOT NULL DEFAULT 0
CHECK (received_after_execution_expiry IN (0, 1))
);
CREATE INDEX execution_events_execution_occurred_idx
ON execution_events (execution_id, occurred_at ASC, id ASC);
CREATE TABLE execution_evidence_assets (
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,
execution_id TEXT NOT NULL
REFERENCES task_executions(id) ON UPDATE RESTRICT ON DELETE CASCADE,
media_type TEXT NOT NULL
CHECK (media_type = 'image/jpeg'),
size_bytes INTEGER NOT NULL
CHECK (size_bytes > 0),
sha256 TEXT NOT NULL
CHECK (
length(sha256) = 64
AND sha256 NOT GLOB '*[^0-9a-f]*'
),
storage_key TEXT NOT NULL UNIQUE
CHECK (
length(storage_key) > 0
AND substr(storage_key, 1, 1) <> '/'
AND instr(storage_key, '\') = 0
AND instr(storage_key, '..') = 0
),
created_at TEXT NOT NULL,
received_after_execution_expiry INTEGER NOT NULL DEFAULT 0
CHECK (received_after_execution_expiry IN (0, 1))
);
CREATE INDEX execution_evidence_execution_created_idx
ON execution_evidence_assets (execution_id, created_at ASC, id ASC);
CREATE TABLE execution_candidate_batches (
execution_id TEXT PRIMARY KEY NOT NULL
REFERENCES task_executions(id) ON UPDATE RESTRICT ON DELETE CASCADE,
task_id TEXT NOT NULL
REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE CASCADE,
task_content_sha256 TEXT NOT NULL
CHECK (
length(task_content_sha256) = 64
AND task_content_sha256 NOT GLOB '*[^0-9a-f]*'
),
execution_mode TEXT NOT NULL
CHECK (execution_mode IN ('MANUAL_FIRST', 'AI_ASSISTED')),
search_query TEXT NOT NULL
CHECK (
length(trim(search_query)) > 0
AND length(CAST(search_query AS BLOB)) <= 512
),
provenance_json TEXT,
candidates_json TEXT NOT NULL
CHECK (length(CAST(candidates_json AS BLOB)) <= 65536),
recommendation_json TEXT,
received_at TEXT NOT NULL,
received_after_execution_expiry INTEGER NOT NULL DEFAULT 0
CHECK (received_after_execution_expiry IN (0, 1))
);
CREATE TABLE execution_outcomes (
execution_id TEXT PRIMARY KEY NOT NULL
REFERENCES task_executions(id) ON UPDATE RESTRICT ON DELETE CASCADE,
task_id TEXT NOT NULL
REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE CASCADE,
result_type TEXT NOT NULL
CHECK (result_type IN ('COMPLETE', 'FAIL')),
execution_mode TEXT
CHECK (execution_mode IS NULL OR execution_mode IN ('MANUAL_FIRST', 'AI_ASSISTED')),
task_content_sha256 TEXT
CHECK (
task_content_sha256 IS NULL
OR (
length(task_content_sha256) = 64
AND task_content_sha256 NOT GLOB '*[^0-9a-f]*'
)
),
outcome TEXT
CHECK (
outcome IS NULL
OR outcome IN (
'CANDIDATE_ACCEPTED',
'CANDIDATE_REJECTED',
'NO_MATCH',
'MANUAL_REQUIRED'
)
),
operator_reason TEXT
CHECK (
operator_reason IS NULL
OR length(CAST(operator_reason AS BLOB)) <= 1000
),
selected_candidate_json TEXT,
evidence_asset_ids_json TEXT,
error_code TEXT
CHECK (error_code IS NULL OR length(CAST(error_code AS BLOB)) <= 64),
error_message TEXT
CHECK (error_message IS NULL OR length(CAST(error_message AS BLOB)) <= 1000),
error_step TEXT
CHECK (error_step IS NULL OR length(CAST(error_step AS BLOB)) <= 64),
retryable INTEGER
CHECK (retryable IS NULL OR retryable IN (0, 1)),
order_submitted INTEGER NOT NULL DEFAULT 0
CHECK (order_submitted = 0),
received_at TEXT NOT NULL,
received_after_execution_expiry INTEGER NOT NULL DEFAULT 0
CHECK (received_after_execution_expiry IN (0, 1)),
CHECK (
(result_type = 'COMPLETE'
AND execution_mode IS NOT NULL
AND task_content_sha256 IS NOT NULL
AND outcome IS NOT NULL
AND operator_reason IS NOT NULL
AND error_code IS NULL)
OR
(result_type = 'FAIL'
AND error_code IS NOT NULL
AND error_message IS NOT NULL
AND error_step IS NOT NULL)
)
);
CREATE TABLE execution_result_requests (
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,
operation TEXT NOT NULL
CHECK (operation IN ('EVENTS', 'EVIDENCE', 'CANDIDATES', 'COMPLETE', 'FAIL')),
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]*'
),
claim_token_sha256 TEXT NOT NULL
CHECK (
length(claim_token_sha256) = 64
AND claim_token_sha256 NOT GLOB '*[^0-9a-f]*'
),
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,
resource_id TEXT,
created_at TEXT NOT NULL,
PRIMARY KEY (user_id, device_id, operation, idempotency_key)
);
-- +goose Down
CREATE TEMP TABLE execution_results_v5_down_guard (
allowed INTEGER NOT NULL
CHECK (allowed = 1)
);
INSERT INTO execution_results_v5_down_guard (allowed)
SELECT CASE
WHEN EXISTS (SELECT 1 FROM execution_events)
OR EXISTS (SELECT 1 FROM execution_evidence_assets)
OR EXISTS (SELECT 1 FROM execution_candidate_batches)
OR EXISTS (SELECT 1 FROM execution_outcomes)
OR EXISTS (SELECT 1 FROM execution_result_requests)
THEN 0
ELSE 1
END;
DROP TABLE execution_results_v5_down_guard;
DROP TABLE execution_result_requests;
DROP TABLE execution_outcomes;
DROP TABLE execution_candidate_batches;
DROP INDEX execution_evidence_execution_created_idx;
DROP TABLE execution_evidence_assets;
DROP INDEX execution_events_execution_occurred_idx;
DROP TABLE execution_events;