203 lines
8.0 KiB
PL/PgSQL
203 lines
8.0 KiB
PL/PgSQL
-- Durable project-scoped operational tasks, immutable artifacts and approvals.
|
|
|
|
BEGIN;
|
|
|
|
CREATE SCHEMA IF NOT EXISTS workbench;
|
|
|
|
CREATE TABLE IF NOT EXISTS workbench.operational_tasks (
|
|
project_id uuid NOT NULL,
|
|
task_id uuid NOT NULL,
|
|
create_request_id uuid NOT NULL,
|
|
task_type text NOT NULL CHECK (task_type IN
|
|
('scheduled_flow','external_work_order','event_investigation')),
|
|
workflow text NOT NULL CHECK (length(workflow) > 0),
|
|
status text NOT NULL CHECK (status IN
|
|
('queued','running','waiting_human','completed','failed','cancelled')),
|
|
priority text NOT NULL CHECK (priority IN ('normal','urgent')),
|
|
revision bigint NOT NULL CHECK (revision >= 1),
|
|
execution_generation bigint NOT NULL CHECK (execution_generation >= 1),
|
|
execution_request_id uuid NOT NULL,
|
|
agent_session_id text,
|
|
agent_lease_expires_at timestamptz,
|
|
current_plan_revision bigint,
|
|
current_report_revision bigint,
|
|
scheduled_for timestamptz,
|
|
created_at timestamptz NOT NULL,
|
|
updated_at timestamptz NOT NULL,
|
|
document jsonb NOT NULL,
|
|
PRIMARY KEY (project_id, task_id),
|
|
UNIQUE (project_id, create_request_id),
|
|
UNIQUE (project_id, execution_request_id),
|
|
CHECK ((jsonb_typeof(document)='object'
|
|
AND document->>'task_id'=task_id::text
|
|
AND document->>'task_type'=task_type
|
|
AND document->>'workflow'=workflow
|
|
AND document->>'status'=status
|
|
AND (document->>'revision')::bigint=revision) IS TRUE)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS operational_tasks_status_idx
|
|
ON workbench.operational_tasks(project_id,status,updated_at DESC,task_id);
|
|
CREATE INDEX IF NOT EXISTS operational_tasks_lease_idx
|
|
ON workbench.operational_tasks(project_id,agent_lease_expires_at)
|
|
WHERE status='running' AND agent_lease_expires_at IS NOT NULL;
|
|
CREATE UNIQUE INDEX IF NOT EXISTS operational_tasks_external_source_idx
|
|
ON workbench.operational_tasks(
|
|
project_id,
|
|
(document#>>'{source,kind}'),
|
|
(document#>>'{source,external_id}')
|
|
) WHERE document#>>'{source,external_id}' IS NOT NULL;
|
|
|
|
CREATE TABLE IF NOT EXISTS workbench.operational_task_requests (
|
|
project_id uuid NOT NULL,
|
|
scope text NOT NULL CHECK (length(scope) > 0),
|
|
request_id uuid NOT NULL,
|
|
request_digest text NOT NULL CHECK (length(request_digest) > 0),
|
|
response jsonb NOT NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
PRIMARY KEY (project_id,scope,request_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS workbench.operational_task_evidence (
|
|
project_id uuid NOT NULL,
|
|
task_id uuid NOT NULL,
|
|
evidence_id text NOT NULL CHECK (length(evidence_id) > 0),
|
|
document jsonb NOT NULL,
|
|
created_at timestamptz NOT NULL,
|
|
PRIMARY KEY (project_id,task_id,evidence_id),
|
|
FOREIGN KEY (project_id,task_id)
|
|
REFERENCES workbench.operational_tasks(project_id,task_id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS workbench.operational_task_plans (
|
|
project_id uuid NOT NULL,
|
|
task_id uuid NOT NULL,
|
|
revision bigint NOT NULL CHECK (revision >= 1),
|
|
document jsonb NOT NULL,
|
|
created_at timestamptz NOT NULL,
|
|
PRIMARY KEY (project_id,task_id,revision),
|
|
FOREIGN KEY (project_id,task_id)
|
|
REFERENCES workbench.operational_tasks(project_id,task_id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS workbench.operational_task_reports (
|
|
project_id uuid NOT NULL,
|
|
task_id uuid NOT NULL,
|
|
revision bigint NOT NULL CHECK (revision >= 1),
|
|
document jsonb NOT NULL,
|
|
created_at timestamptz NOT NULL,
|
|
PRIMARY KEY (project_id,task_id,revision),
|
|
FOREIGN KEY (project_id,task_id)
|
|
REFERENCES workbench.operational_tasks(project_id,task_id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS workbench.operational_task_actions (
|
|
project_id uuid NOT NULL,
|
|
task_id uuid NOT NULL,
|
|
action_id uuid NOT NULL,
|
|
version bigint NOT NULL CHECK (version >= 1),
|
|
approval_status text NOT NULL CHECK (approval_status IN
|
|
('pending','approved','rejected')),
|
|
execution_status text NOT NULL CHECK (execution_status IN
|
|
('not_submitted','submitted','succeeded','failed','unsupported','unknown')),
|
|
document jsonb NOT NULL,
|
|
created_at timestamptz NOT NULL,
|
|
updated_at timestamptz NOT NULL,
|
|
PRIMARY KEY (project_id,task_id,action_id),
|
|
FOREIGN KEY (project_id,task_id)
|
|
REFERENCES workbench.operational_tasks(project_id,task_id) ON DELETE CASCADE,
|
|
CHECK ((document->>'action_id'=action_id::text
|
|
AND (document->>'version')::bigint=version
|
|
AND document->>'approval_status'=approval_status
|
|
AND document->>'execution_status'=execution_status) IS TRUE)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS workbench.operational_task_action_revisions (
|
|
project_id uuid NOT NULL,
|
|
task_id uuid NOT NULL,
|
|
action_id uuid NOT NULL,
|
|
version bigint NOT NULL CHECK (version >= 1),
|
|
document jsonb NOT NULL,
|
|
recorded_at timestamptz NOT NULL,
|
|
PRIMARY KEY (project_id,task_id,action_id,version),
|
|
FOREIGN KEY (project_id,task_id,action_id)
|
|
REFERENCES workbench.operational_task_actions(project_id,task_id,action_id)
|
|
ON DELETE CASCADE,
|
|
CHECK ((document->>'action_id'=action_id::text
|
|
AND (document->>'version')::bigint=version) IS TRUE)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS workbench.operational_task_external_feedback (
|
|
project_id uuid NOT NULL,
|
|
task_id uuid NOT NULL,
|
|
source_event_id text NOT NULL CHECK (length(source_event_id) > 0),
|
|
source_revision bigint NOT NULL CHECK (source_revision >= 1),
|
|
document jsonb NOT NULL,
|
|
accepted_at timestamptz NOT NULL,
|
|
PRIMARY KEY (project_id,task_id,source_event_id),
|
|
FOREIGN KEY (project_id,task_id)
|
|
REFERENCES workbench.operational_tasks(project_id,task_id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS workbench.operational_task_notifications (
|
|
project_id uuid NOT NULL,
|
|
notification_id uuid NOT NULL,
|
|
task_id uuid NOT NULL,
|
|
created_at timestamptz NOT NULL,
|
|
document jsonb NOT NULL,
|
|
PRIMARY KEY (project_id,notification_id),
|
|
FOREIGN KEY (project_id,task_id)
|
|
REFERENCES workbench.operational_tasks(project_id,task_id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS operational_task_notifications_unread_idx
|
|
ON workbench.operational_task_notifications(project_id,created_at DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS workbench.operational_task_notification_reads (
|
|
project_id uuid NOT NULL,
|
|
notification_id uuid NOT NULL,
|
|
user_id uuid NOT NULL,
|
|
version bigint NOT NULL CHECK (version >= 2),
|
|
read_at timestamptz NOT NULL,
|
|
PRIMARY KEY (project_id,notification_id,user_id),
|
|
FOREIGN KEY (project_id,notification_id)
|
|
REFERENCES workbench.operational_task_notifications(project_id,notification_id)
|
|
ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS workbench.operational_task_schedules (
|
|
project_id uuid NOT NULL,
|
|
schedule_id uuid NOT NULL,
|
|
create_request_id uuid NOT NULL,
|
|
schedule_key text NOT NULL CHECK (length(schedule_key) > 0),
|
|
next_run_at timestamptz NOT NULL,
|
|
interval_seconds integer NOT NULL CHECK (interval_seconds >= 60),
|
|
enabled boolean NOT NULL,
|
|
version bigint NOT NULL CHECK (version >= 1),
|
|
document jsonb NOT NULL,
|
|
created_at timestamptz NOT NULL,
|
|
updated_at timestamptz NOT NULL,
|
|
PRIMARY KEY (project_id,schedule_id),
|
|
UNIQUE (project_id,create_request_id),
|
|
UNIQUE (project_id,schedule_key),
|
|
CHECK ((document->>'schedule_id'=schedule_id::text
|
|
AND document->>'schedule_key'=schedule_key
|
|
AND (document->>'version')::bigint=version) IS TRUE)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS workbench.operational_schedule_occurrences (
|
|
project_id uuid NOT NULL,
|
|
schedule_id uuid NOT NULL,
|
|
due_at timestamptz NOT NULL,
|
|
task_id uuid NOT NULL,
|
|
created_at timestamptz NOT NULL,
|
|
PRIMARY KEY (project_id,schedule_id,due_at),
|
|
UNIQUE (project_id,task_id),
|
|
FOREIGN KEY (project_id,schedule_id)
|
|
REFERENCES workbench.operational_task_schedules(project_id,schedule_id),
|
|
FOREIGN KEY (project_id,task_id)
|
|
REFERENCES workbench.operational_tasks(project_id,task_id)
|
|
);
|
|
|
|
COMMIT;
|