Files
pikasTech-HWLAB/deploy/gitops/node/jd01/runtime-v03/postgres.yaml
T
2026-06-30 11:36:07 +00:00

943 lines
32 KiB
YAML

apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ConfigMap
metadata:
name: hwlab-v03-postgres-init
namespace: hwlab-v03
labels:
app.kubernetes.io/name: hwlab-v03-postgres
app.kubernetes.io/part-of: hwlab
hwlab.pikastech.local/environment: v03
hwlab.pikastech.local/gitops-target: v03
hwlab.pikastech.local/profile: v03
hwlab.pikastech.local/source-commit: a2c42faec2b85dbe1115156b76b7d67f205cf07a
data:
0001_cloud_core_skeleton.sql: >
-- SPEC: PJ2026-0104010803 Workbench唯一投影
draft-2026-06-24-p0-aggregate-event-stream.
-- HWLAB L1 Cloud Core schema skeleton.
-- This file is source schema only; applying it to DEV/PROD is a
separate
-- operator action and is not performed by source tests or smokes.
CREATE TABLE IF NOT EXISTS projects (
id TEXT PRIMARY KEY,
name TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'pending',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
display_name TEXT NOT NULL DEFAULT '',
role TEXT NOT NULL CHECK (role IN ('admin', 'user')),
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'disabled')),
password_hash TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS user_sessions (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL REFERENCES users(id),
session_token_hash TEXT NOT NULL UNIQUE,
created_at TEXT NOT NULL,
last_seen_at TEXT NOT NULL,
expires_at TEXT NOT NULL,
revoked_at TEXT
);
CREATE TABLE IF NOT EXISTS gateway_sessions (
id TEXT PRIMARY KEY,
project_id TEXT,
gateway_service_id TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'pending',
started_at TEXT,
ended_at TEXT,
gateway_session_json TEXT NOT NULL DEFAULT '{}'
);
CREATE TABLE IF NOT EXISTS box_resources (
id TEXT PRIMARY KEY,
project_id TEXT,
gateway_session_id TEXT,
resource_state TEXT NOT NULL DEFAULT 'available',
labels_json TEXT NOT NULL DEFAULT '{}',
resource_json TEXT NOT NULL DEFAULT '{}',
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS box_capabilities (
id TEXT PRIMARY KEY,
box_resource_id TEXT NOT NULL,
capability_type TEXT NOT NULL,
capability_json TEXT NOT NULL DEFAULT '{}',
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS wiring_configs (
id TEXT PRIMARY KEY,
project_id TEXT,
wiring_json TEXT NOT NULL DEFAULT '{}',
status TEXT NOT NULL DEFAULT 'pending',
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS patch_panel_status (
id TEXT PRIMARY KEY,
gateway_session_id TEXT,
wiring_config_id TEXT,
status_json TEXT NOT NULL DEFAULT '{}',
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS hardware_operations (
id TEXT PRIMARY KEY,
project_id TEXT,
requested_by TEXT,
operation_type TEXT NOT NULL,
operation_json TEXT NOT NULL DEFAULT '{}',
status TEXT NOT NULL DEFAULT 'requested',
requested_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS audit_events (
id TEXT PRIMARY KEY,
request_id TEXT NOT NULL,
actor TEXT NOT NULL,
source TEXT NOT NULL,
operation TEXT NOT NULL,
target TEXT NOT NULL,
result TEXT NOT NULL,
timestamp TEXT NOT NULL,
event_json TEXT NOT NULL DEFAULT '{}'
);
CREATE TABLE IF NOT EXISTS agent_sessions (
id TEXT PRIMARY KEY,
project_id TEXT,
agent_id TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'pending',
started_at TEXT,
ended_at TEXT,
owner_user_id TEXT REFERENCES users(id),
conversation_id TEXT,
thread_id TEXT,
last_trace_id TEXT,
session_json TEXT NOT NULL DEFAULT '{}',
updated_at TEXT
);
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS owner_user_id TEXT
REFERENCES users(id);
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS conversation_id
TEXT;
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS thread_id TEXT;
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS last_trace_id TEXT;
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS session_json TEXT
NOT NULL DEFAULT '{}';
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS updated_at TEXT;
CREATE INDEX IF NOT EXISTS idx_agent_sessions_owner ON
agent_sessions(owner_user_id);
CREATE INDEX IF NOT EXISTS idx_agent_sessions_conversation ON
agent_sessions(conversation_id);
CREATE INDEX IF NOT EXISTS idx_agent_sessions_active_updated ON
agent_sessions(updated_at DESC, id DESC) WHERE status <> 'archived';
CREATE INDEX IF NOT EXISTS idx_agent_sessions_owner_active_updated ON
agent_sessions(owner_user_id, updated_at DESC, id DESC) WHERE status <>
'archived';
CREATE TABLE IF NOT EXISTS account_workspaces (
id TEXT PRIMARY KEY,
owner_user_id TEXT NOT NULL REFERENCES users(id),
project_id TEXT NOT NULL,
name TEXT NOT NULL DEFAULT 'Default Workbench',
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'archived')),
is_default BOOLEAN NOT NULL DEFAULT true,
selected_conversation_id TEXT,
selected_agent_session_id TEXT,
active_trace_id TEXT,
provider_profile TEXT,
workspace_json TEXT NOT NULL DEFAULT '{}',
revision INTEGER NOT NULL DEFAULT 1,
updated_by_session_id TEXT,
updated_by_client TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_account_workspaces_default ON
account_workspaces(owner_user_id, project_id) WHERE is_default = TRUE
AND status = 'active';
CREATE INDEX IF NOT EXISTS idx_account_workspaces_owner ON
account_workspaces(owner_user_id, project_id, updated_at DESC);
CREATE TABLE IF NOT EXISTS worker_sessions (
id TEXT PRIMARY KEY,
agent_session_id TEXT,
worker_id TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'pending',
started_at TEXT,
ended_at TEXT
);
CREATE TABLE IF NOT EXISTS agent_trace_events (
id TEXT PRIMARY KEY,
trace_id TEXT NOT NULL,
agent_session_id TEXT,
worker_session_id TEXT,
level TEXT NOT NULL DEFAULT 'info',
message TEXT NOT NULL DEFAULT '',
event_json TEXT NOT NULL DEFAULT '{}',
occurred_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_agent_trace_events_trace_order ON
agent_trace_events(trace_id, occurred_at, id);
CREATE INDEX IF NOT EXISTS idx_agent_trace_events_session_order ON
agent_trace_events(agent_session_id, occurred_at, id);
CREATE INDEX IF NOT EXISTS idx_agent_trace_events_worker_order ON
agent_trace_events(worker_session_id, occurred_at, id);
CREATE TABLE IF NOT EXISTS workbench_projection_state (
trace_id TEXT PRIMARY KEY,
session_id TEXT,
conversation_id TEXT,
thread_id TEXT,
run_id TEXT NOT NULL,
command_id TEXT NOT NULL,
last_agentrun_seq INTEGER NOT NULL DEFAULT 0,
last_projected_seq INTEGER NOT NULL DEFAULT 0,
upstream_latest_seq INTEGER,
projection_status TEXT NOT NULL DEFAULT 'projecting',
projection_health TEXT NOT NULL DEFAULT 'healthy',
result_sync_state TEXT NOT NULL DEFAULT 'not_started',
last_projected_at TEXT,
last_result_sync_at TEXT,
last_error_code TEXT,
last_error_message TEXT,
failure_count INTEGER NOT NULL DEFAULT 0,
next_retry_at TEXT,
projection_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS
idx_workbench_projection_state_status_retry_updated ON
workbench_projection_state(projection_status, next_retry_at,
updated_at);
CREATE INDEX IF NOT EXISTS idx_workbench_projection_state_run_command ON
workbench_projection_state(run_id, command_id);
CREATE INDEX IF NOT EXISTS
idx_workbench_projection_state_session_updated ON
workbench_projection_state(session_id, updated_at DESC);
CREATE TABLE IF NOT EXISTS workbench_sessions (
session_id TEXT PRIMARY KEY,
owner_user_id TEXT REFERENCES users(id),
project_id TEXT,
conversation_id TEXT,
thread_id TEXT,
status TEXT NOT NULL DEFAULT 'unknown',
last_trace_id TEXT,
projected_seq INTEGER NOT NULL DEFAULT 0,
source_seq INTEGER NOT NULL DEFAULT 0,
source_event_id TEXT,
terminal BOOLEAN NOT NULL DEFAULT false,
sealed BOOLEAN NOT NULL DEFAULT false,
session_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_workbench_sessions_owner_updated ON
workbench_sessions(owner_user_id, updated_at DESC, session_id);
CREATE INDEX IF NOT EXISTS idx_workbench_sessions_status_updated ON
workbench_sessions(status, updated_at DESC, session_id);
CREATE TABLE IF NOT EXISTS workbench_messages (
message_id TEXT PRIMARY KEY,
session_id TEXT NOT NULL,
turn_id TEXT,
trace_id TEXT,
role TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'unknown',
projected_seq INTEGER NOT NULL DEFAULT 0,
source_seq INTEGER NOT NULL DEFAULT 0,
source_event_id TEXT,
terminal BOOLEAN NOT NULL DEFAULT false,
sealed BOOLEAN NOT NULL DEFAULT false,
message_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_workbench_messages_session_updated ON
workbench_messages(session_id, updated_at ASC, message_id);
CREATE INDEX IF NOT EXISTS idx_workbench_messages_trace ON
workbench_messages(trace_id, message_id);
CREATE INDEX IF NOT EXISTS idx_workbench_messages_turn ON
workbench_messages(turn_id, message_id);
CREATE TABLE IF NOT EXISTS workbench_parts (
part_id TEXT PRIMARY KEY,
message_id TEXT NOT NULL,
session_id TEXT NOT NULL,
turn_id TEXT,
trace_id TEXT,
part_index INTEGER NOT NULL DEFAULT 0,
part_type TEXT NOT NULL DEFAULT 'text',
status TEXT NOT NULL DEFAULT 'unknown',
projected_seq INTEGER NOT NULL DEFAULT 0,
source_seq INTEGER NOT NULL DEFAULT 0,
source_event_id TEXT,
terminal BOOLEAN NOT NULL DEFAULT false,
sealed BOOLEAN NOT NULL DEFAULT false,
part_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_workbench_parts_message_index ON
workbench_parts(message_id, part_index, part_id);
CREATE INDEX IF NOT EXISTS idx_workbench_parts_session_trace ON
workbench_parts(session_id, trace_id, part_index);
CREATE TABLE IF NOT EXISTS workbench_turns (
turn_id TEXT PRIMARY KEY,
session_id TEXT NOT NULL,
trace_id TEXT,
message_id TEXT,
status TEXT NOT NULL DEFAULT 'unknown',
projected_seq INTEGER NOT NULL DEFAULT 0,
source_seq INTEGER NOT NULL DEFAULT 0,
source_event_id TEXT,
terminal BOOLEAN NOT NULL DEFAULT false,
sealed BOOLEAN NOT NULL DEFAULT false,
final_response_json TEXT NOT NULL DEFAULT 'null',
diagnostic_json TEXT NOT NULL DEFAULT '{}',
turn_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_workbench_turns_session_updated ON
workbench_turns(session_id, updated_at DESC, turn_id);
CREATE INDEX IF NOT EXISTS idx_workbench_turns_trace ON
workbench_turns(trace_id, turn_id);
CREATE TABLE IF NOT EXISTS workbench_trace_events (
id TEXT PRIMARY KEY,
trace_id TEXT NOT NULL,
session_id TEXT,
turn_id TEXT,
message_id TEXT,
source_seq INTEGER NOT NULL DEFAULT 0,
source_event_id TEXT,
projected_seq INTEGER NOT NULL DEFAULT 0,
event_type TEXT NOT NULL DEFAULT 'event',
terminal BOOLEAN NOT NULL DEFAULT false,
sealed BOOLEAN NOT NULL DEFAULT false,
event_json TEXT NOT NULL DEFAULT '{}',
occurred_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_workbench_trace_events_trace_seq ON
workbench_trace_events(trace_id, source_seq, projected_seq, id);
CREATE INDEX IF NOT EXISTS idx_workbench_trace_events_session_seq ON
workbench_trace_events(session_id, source_seq, projected_seq, id);
WITH duplicate_trace_source_events AS (
SELECT
id,
ROW_NUMBER() OVER (
PARTITION BY trace_id, source_event_id
ORDER BY occurred_at, id
) AS duplicate_rank
FROM workbench_trace_events
WHERE trace_id IS NOT NULL AND source_event_id IS NOT NULL
), trace_source_event_rewrites AS (
SELECT
id,
'workbench_trace_events:' || id AS stable_source_event_id
FROM duplicate_trace_source_events
WHERE duplicate_rank > 1
)
UPDATE workbench_trace_events AS target
SET
source_event_id = trace_source_event_rewrites.stable_source_event_id,
updated_at = COALESCE(NULLIF(target.updated_at, ''), target.occurred_at, CURRENT_TIMESTAMP::text)
FROM trace_source_event_rewrites
WHERE target.id = trace_source_event_rewrites.id
AND target.source_event_id IS DISTINCT FROM trace_source_event_rewrites.stable_source_event_id;
WITH trace_event_projected_seq_conflicts AS (
SELECT trace_id
FROM workbench_trace_events
WHERE trace_id IS NOT NULL
GROUP BY trace_id
HAVING COUNT(*) <> COUNT(DISTINCT projected_seq)
), trace_event_resequence AS (
SELECT
workbench_trace_events.id,
(ROW_NUMBER() OVER (
PARTITION BY workbench_trace_events.trace_id
ORDER BY
CASE WHEN workbench_trace_events.projected_seq > 0 THEN 0 ELSE 1 END,
workbench_trace_events.projected_seq,
workbench_trace_events.occurred_at,
workbench_trace_events.id
))::integer AS durable_projected_seq
FROM workbench_trace_events
INNER JOIN trace_event_projected_seq_conflicts
ON trace_event_projected_seq_conflicts.trace_id = workbench_trace_events.trace_id
)
UPDATE workbench_trace_events AS target
SET
projected_seq = trace_event_resequence.durable_projected_seq,
source_seq = CASE
WHEN target.source_seq > 0 THEN target.source_seq
ELSE trace_event_resequence.durable_projected_seq
END,
updated_at = COALESCE(NULLIF(target.updated_at, ''), target.occurred_at, CURRENT_TIMESTAMP::text)
FROM trace_event_resequence
WHERE target.id = trace_event_resequence.id
AND (
target.projected_seq IS DISTINCT FROM trace_event_resequence.durable_projected_seq
OR target.source_seq <= 0
);
DROP INDEX IF EXISTS idx_workbench_trace_events_trace_source_event;
CREATE UNIQUE INDEX idx_workbench_trace_events_trace_source_event ON
workbench_trace_events(trace_id, source_event_id) WHERE source_event_id
IS NOT NULL;
DROP INDEX IF EXISTS idx_workbench_trace_events_trace_projected_seq;
CREATE UNIQUE INDEX idx_workbench_trace_events_trace_projected_seq ON
workbench_trace_events(trace_id, projected_seq);
CREATE TABLE IF NOT EXISTS workbench_event_sequences (
aggregate_id TEXT PRIMARY KEY,
aggregate_type TEXT NOT NULL DEFAULT 'trace',
session_id TEXT,
turn_id TEXT,
trace_id TEXT,
last_seq INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_workbench_event_sequences_session ON
workbench_event_sequences(session_id, updated_at DESC, aggregate_id);
CREATE INDEX IF NOT EXISTS idx_workbench_event_sequences_trace ON
workbench_event_sequences(trace_id, updated_at DESC, aggregate_id);
CREATE TABLE IF NOT EXISTS workbench_events (
event_seq BIGSERIAL PRIMARY KEY,
event_id TEXT NOT NULL UNIQUE,
aggregate_id TEXT NOT NULL,
aggregate_type TEXT NOT NULL DEFAULT 'trace',
aggregate_seq INTEGER NOT NULL,
session_id TEXT,
turn_id TEXT,
trace_id TEXT,
message_id TEXT,
source_run_id TEXT,
source_command_id TEXT,
source_seq INTEGER NOT NULL DEFAULT 0,
source_event_id TEXT,
event_type TEXT NOT NULL DEFAULT 'event',
projection_revision INTEGER NOT NULL DEFAULT 0,
terminal BOOLEAN NOT NULL DEFAULT false,
sealed BOOLEAN NOT NULL DEFAULT false,
payload_json TEXT NOT NULL DEFAULT '{}',
occurred_at TEXT NOT NULL,
committed_at TEXT NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_workbench_events_aggregate_seq ON
workbench_events(aggregate_id, aggregate_seq);
CREATE UNIQUE INDEX IF NOT EXISTS
idx_workbench_events_aggregate_source_event ON
workbench_events(aggregate_id, source_event_id) WHERE source_event_id IS
NOT NULL;
CREATE INDEX IF NOT EXISTS idx_workbench_events_trace_seq ON
workbench_events(trace_id, event_seq);
CREATE INDEX IF NOT EXISTS idx_workbench_events_session_seq ON
workbench_events(session_id, event_seq);
CREATE INDEX IF NOT EXISTS idx_workbench_events_type_seq ON
workbench_events(event_type, event_seq);
CREATE TABLE IF NOT EXISTS workbench_session_inputs (
input_id TEXT PRIMARY KEY,
session_id TEXT NOT NULL,
turn_id TEXT,
trace_id TEXT,
message_id TEXT,
command_id TEXT,
delivery TEXT NOT NULL DEFAULT 'queue',
admitted_seq INTEGER NOT NULL DEFAULT 0,
promoted_seq INTEGER,
status TEXT NOT NULL DEFAULT 'admitted',
error_code TEXT,
source_event_id TEXT,
input_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_workbench_session_inputs_session_seq ON
workbench_session_inputs(session_id, admitted_seq, input_id);
CREATE INDEX IF NOT EXISTS idx_workbench_session_inputs_trace ON
workbench_session_inputs(trace_id, input_id);
CREATE INDEX IF NOT EXISTS idx_workbench_session_inputs_command ON
workbench_session_inputs(command_id, input_id) WHERE command_id IS NOT
NULL;
CREATE UNIQUE INDEX IF NOT EXISTS
idx_workbench_session_inputs_source_event ON
workbench_session_inputs(session_id, source_event_id) WHERE
source_event_id IS NOT NULL;
CREATE TABLE IF NOT EXISTS workbench_projection_checkpoints (
trace_id TEXT PRIMARY KEY,
session_id TEXT,
turn_id TEXT,
run_id TEXT,
command_id TEXT,
projected_seq INTEGER NOT NULL DEFAULT 0,
source_seq INTEGER NOT NULL DEFAULT 0,
source_event_id TEXT,
projection_status TEXT NOT NULL DEFAULT 'projecting',
projection_health TEXT NOT NULL DEFAULT 'healthy',
terminal BOOLEAN NOT NULL DEFAULT false,
sealed BOOLEAN NOT NULL DEFAULT false,
diagnostic_json TEXT NOT NULL DEFAULT '{}',
checkpoint_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS
idx_workbench_projection_checkpoints_status_updated ON
workbench_projection_checkpoints(projection_status, updated_at DESC,
trace_id);
CREATE INDEX IF NOT EXISTS
idx_workbench_projection_checkpoints_session_updated ON
workbench_projection_checkpoints(session_id, updated_at DESC, trace_id);
CREATE TABLE IF NOT EXISTS workbench_projection_outbox (
outbox_seq BIGSERIAL PRIMARY KEY,
event_seq BIGINT,
aggregate_id TEXT,
aggregate_seq INTEGER NOT NULL DEFAULT 0,
projection_revision INTEGER NOT NULL DEFAULT 0,
trace_id TEXT NOT NULL,
session_id TEXT,
turn_id TEXT,
message_id TEXT,
projected_seq INTEGER NOT NULL DEFAULT 0,
source_seq INTEGER NOT NULL DEFAULT 0,
source_event_id TEXT,
commit_type TEXT NOT NULL DEFAULT 'event',
terminal BOOLEAN NOT NULL DEFAULT false,
sealed BOOLEAN NOT NULL DEFAULT false,
payload_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL
);
ALTER TABLE workbench_projection_outbox ADD COLUMN IF NOT EXISTS
event_seq BIGINT;
ALTER TABLE workbench_projection_outbox ADD COLUMN IF NOT EXISTS
aggregate_id TEXT;
ALTER TABLE workbench_projection_outbox ADD COLUMN IF NOT EXISTS
aggregate_seq INTEGER NOT NULL DEFAULT 0;
ALTER TABLE workbench_projection_outbox ADD COLUMN IF NOT EXISTS
projection_revision INTEGER NOT NULL DEFAULT 0;
CREATE INDEX IF NOT EXISTS idx_workbench_projection_outbox_trace_seq ON
workbench_projection_outbox(trace_id, outbox_seq);
CREATE INDEX IF NOT EXISTS idx_workbench_projection_outbox_session_seq
ON workbench_projection_outbox(session_id, outbox_seq);
CREATE INDEX IF NOT EXISTS idx_workbench_projection_outbox_after_seq ON
workbench_projection_outbox(outbox_seq);
CREATE INDEX IF NOT EXISTS idx_workbench_projection_outbox_event_seq ON
workbench_projection_outbox(event_seq) WHERE event_seq IS NOT NULL;
INSERT INTO workbench_sessions (
session_id,
owner_user_id,
project_id,
conversation_id,
thread_id,
status,
last_trace_id,
projected_seq,
source_seq,
source_event_id,
terminal,
sealed,
session_json,
created_at,
updated_at
)
SELECT
id,
owner_user_id,
project_id,
conversation_id,
thread_id,
status,
last_trace_id,
0,
0,
id,
status IN ('completed', 'failed', 'canceled', 'cancelled', 'archived'),
status IN ('completed', 'failed', 'canceled', 'cancelled', 'archived') AND ended_at IS NOT NULL,
COALESCE(NULLIF(session_json, ''), '{}'),
COALESCE(started_at, updated_at, CURRENT_TIMESTAMP::text),
COALESCE(updated_at, ended_at, started_at, CURRENT_TIMESTAMP::text)
FROM agent_sessions
WHERE id IS NOT NULL
ON CONFLICT (session_id) DO NOTHING;
INSERT INTO workbench_trace_events (
id,
trace_id,
session_id,
turn_id,
message_id,
source_seq,
source_event_id,
projected_seq,
event_type,
terminal,
sealed,
event_json,
occurred_at,
updated_at
)
SELECT
source_trace_events.id,
source_trace_events.trace_id,
source_trace_events.agent_session_id,
source_trace_events.trace_id,
NULL,
source_trace_events.durable_projection_seq,
source_trace_events.id,
source_trace_events.durable_projection_seq,
'agent_trace_event',
false,
false,
COALESCE(NULLIF(source_trace_events.event_json, ''), '{}'),
source_trace_events.occurred_at,
source_trace_events.occurred_at
FROM (
SELECT
agent_trace_events.*,
(ROW_NUMBER() OVER (PARTITION BY trace_id ORDER BY occurred_at, id))::integer AS durable_projection_seq
FROM agent_trace_events
WHERE id IS NOT NULL AND trace_id IS NOT NULL
) AS source_trace_events
ON CONFLICT DO NOTHING;
INSERT INTO workbench_turns (
turn_id,
session_id,
trace_id,
message_id,
status,
projected_seq,
source_seq,
source_event_id,
terminal,
sealed,
final_response_json,
diagnostic_json,
turn_json,
created_at,
updated_at
)
SELECT
trace_id,
COALESCE(session_id, trace_id),
trace_id,
NULL,
projection_status,
last_projected_seq,
last_agentrun_seq,
trace_id || ':' || last_agentrun_seq::text,
projection_status IN ('caught_up', 'terminal'),
projection_status = 'terminal',
'null',
COALESCE(NULLIF(projection_json, ''), '{}'),
COALESCE(NULLIF(projection_json, ''), '{}'),
COALESCE(created_at, updated_at, CURRENT_TIMESTAMP::text),
COALESCE(updated_at, created_at, CURRENT_TIMESTAMP::text)
FROM workbench_projection_state
WHERE trace_id IS NOT NULL
ON CONFLICT (turn_id) DO NOTHING;
INSERT INTO workbench_projection_checkpoints (
trace_id,
session_id,
turn_id,
run_id,
command_id,
projected_seq,
source_seq,
source_event_id,
projection_status,
projection_health,
terminal,
sealed,
diagnostic_json,
checkpoint_json,
created_at,
updated_at
)
SELECT
trace_id,
session_id,
trace_id,
run_id,
command_id,
last_projected_seq,
last_agentrun_seq,
trace_id || ':' || last_agentrun_seq::text,
projection_status,
projection_health,
projection_status IN ('caught_up', 'terminal'),
projection_status = 'terminal',
COALESCE(NULLIF(projection_json, ''), '{}'),
COALESCE(NULLIF(projection_json, ''), '{}'),
COALESCE(created_at, updated_at, CURRENT_TIMESTAMP::text),
COALESCE(updated_at, created_at, CURRENT_TIMESTAMP::text)
FROM workbench_projection_state
WHERE trace_id IS NOT NULL
ON CONFLICT (trace_id) DO NOTHING;
CREATE TABLE IF NOT EXISTS evidence_records (
id TEXT PRIMARY KEY,
project_id TEXT,
operation_id TEXT,
evidence_type TEXT NOT NULL,
uri TEXT NOT NULL DEFAULT '',
metadata_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS hwlab_schema_migrations (
id TEXT PRIMARY KEY,
schema_version TEXT NOT NULL,
applied_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
migration_json TEXT NOT NULL DEFAULT '{}'
);
INSERT INTO hwlab_schema_migrations (id, schema_version, applied_at,
migration_json)
VALUES (
'0001_cloud_core_skeleton',
'runtime-durable-postgres-v7',
CURRENT_TIMESTAMP,
'{"path":"internal/db/migrations/0001_cloud_core_skeleton.sql","runtime":"cloud-api"}'
)
ON CONFLICT (id) DO UPDATE SET
schema_version = EXCLUDED.schema_version,
migration_json = EXCLUDED.migration_json;
- apiVersion: v1
kind: Service
metadata:
name: hwlab-v03-postgres
namespace: hwlab-v03
labels:
app.kubernetes.io/name: hwlab-v03-postgres
app.kubernetes.io/part-of: hwlab
hwlab.pikastech.local/environment: v03
hwlab.pikastech.local/gitops-target: v03
hwlab.pikastech.local/profile: v03
hwlab.pikastech.local/source-commit: a2c42faec2b85dbe1115156b76b7d67f205cf07a
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: hwlab-v03-postgres
ports:
- name: postgres
port: 5432
targetPort: postgres
- apiVersion: apps/v1
kind: StatefulSet
metadata:
name: hwlab-v03-postgres
namespace: hwlab-v03
labels:
app.kubernetes.io/name: hwlab-v03-postgres
app.kubernetes.io/part-of: hwlab
hwlab.pikastech.local/environment: v03
hwlab.pikastech.local/gitops-target: v03
hwlab.pikastech.local/profile: v03
hwlab.pikastech.local/source-commit: a2c42faec2b85dbe1115156b76b7d67f205cf07a
spec:
serviceName: hwlab-v03-postgres
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: hwlab-v03-postgres
template:
metadata:
labels:
app.kubernetes.io/name: hwlab-v03-postgres
app.kubernetes.io/part-of: hwlab
hwlab.pikastech.local/environment: v03
hwlab.pikastech.local/gitops-target: v03
hwlab.pikastech.local/profile: v03
hwlab.pikastech.local/migration-sha256: 880f77326c6dd41a
annotations:
hwlab.pikastech.local/migration-sha256: 880f77326c6dd41a994931567da1d0372af0b3c3f8aef1e2f69e3d5ed4343274
spec:
containers:
- name: postgres
image: 127.0.0.1:5000/hwlab/postgres:16-alpine
imagePullPolicy: IfNotPresent
env:
- name: POSTGRES_DB
value: hwlab_v03
- name: POSTGRES_USER
value: hwlab_v03
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: hwlab-v03-postgres
key: POSTGRES_PASSWORD
ports:
- name: postgres
containerPort: 5432
readinessProbe:
tcpSocket:
port: postgres
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: postgres
initialDelaySeconds: 30
periodSeconds: 20
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
- name: init
mountPath: /docker-entrypoint-initdb.d
readOnly: true
volumes:
- name: init
configMap:
name: hwlab-v03-postgres-init
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 8Gi