101 lines
3.7 KiB
SQL
101 lines
3.7 KiB
SQL
-- Fixed-scope account roles, audit attribution, and reversible task archive.
|
|
-- Existing accounts remain administrators; no organization/tenant UI is added.
|
|
|
|
ALTER TABLE users
|
|
DROP CONSTRAINT IF EXISTS users_role_check;
|
|
|
|
ALTER TABLE users
|
|
ADD CONSTRAINT users_role_check CHECK (role IN ('admin', 'user'));
|
|
|
|
ALTER TABLE users
|
|
ADD COLUMN IF NOT EXISTS must_change_password boolean NOT NULL DEFAULT false,
|
|
ADD COLUMN IF NOT EXISTS password_changed_at timestamptz NOT NULL DEFAULT now();
|
|
|
|
-- User-supplied idempotency keys are account-scoped. System/AgentBus keys
|
|
-- remain deployment-scoped through the NULL actor partial index.
|
|
ALTER TABLE tasks
|
|
DROP CONSTRAINT IF EXISTS tasks_organization_id_idempotency_key_key;
|
|
|
|
ALTER TABLE idempotency_keys
|
|
DROP CONSTRAINT IF EXISTS idempotency_keys_organization_id_scope_idempotency_key_key;
|
|
|
|
ALTER TABLE idempotency_keys
|
|
ADD COLUMN IF NOT EXISTS actor_user_id uuid REFERENCES users(id);
|
|
|
|
UPDATE idempotency_keys i
|
|
SET actor_user_id = t.created_by
|
|
FROM tasks t
|
|
WHERE i.task_id = t.id
|
|
AND i.actor_user_id IS NULL
|
|
AND t.source = 'manual';
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idempotency_keys_actor_unique_idx
|
|
ON idempotency_keys (organization_id, scope, idempotency_key, actor_user_id)
|
|
WHERE actor_user_id IS NOT NULL;
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idempotency_keys_system_unique_idx
|
|
ON idempotency_keys (organization_id, scope, idempotency_key)
|
|
WHERE actor_user_id IS NULL;
|
|
|
|
ALTER TABLE agent_session_messages
|
|
ADD COLUMN IF NOT EXISTS actor_user_id uuid REFERENCES users(id),
|
|
ADD COLUMN IF NOT EXISTS input_source text;
|
|
|
|
ALTER TABLE agent_session_messages
|
|
DROP CONSTRAINT IF EXISTS agent_session_messages_input_source_check;
|
|
|
|
ALTER TABLE agent_session_messages
|
|
ADD CONSTRAINT agent_session_messages_input_source_check
|
|
CHECK (input_source IS NULL OR input_source IN ('manual', 'agentbus', 'reparse', 'system'));
|
|
|
|
-- Only the initial input has a provable historical platform actor. Do not
|
|
-- invent actors for later turns that predate explicit attribution.
|
|
UPDATE agent_session_messages m
|
|
SET actor_user_id = t.created_by,
|
|
input_source = CASE WHEN t.source = 'agentbus' THEN 'agentbus' ELSE 'manual' END
|
|
FROM tasks t
|
|
WHERE m.task_id = t.id
|
|
AND m.role = 'user'
|
|
AND m.turn_no = 1
|
|
AND (m.actor_user_id IS NULL OR m.input_source IS NULL);
|
|
|
|
ALTER TABLE task_input_attachments
|
|
ADD COLUMN IF NOT EXISTS created_by uuid REFERENCES users(id);
|
|
|
|
UPDATE task_input_attachments a
|
|
SET created_by = t.created_by
|
|
FROM tasks t
|
|
WHERE a.task_id = t.id
|
|
AND a.created_by IS NULL
|
|
AND a.source = 'manual';
|
|
|
|
ALTER TABLE tasks
|
|
ADD COLUMN IF NOT EXISTS archived_at timestamptz,
|
|
ADD COLUMN IF NOT EXISTS archived_by uuid REFERENCES users(id),
|
|
ADD COLUMN IF NOT EXISTS archive_reason text;
|
|
|
|
ALTER TABLE tasks
|
|
DROP CONSTRAINT IF EXISTS tasks_archive_reason_length_check;
|
|
|
|
ALTER TABLE tasks
|
|
ADD CONSTRAINT tasks_archive_reason_length_check
|
|
CHECK (archive_reason IS NULL OR char_length(archive_reason) <= 500);
|
|
|
|
CREATE INDEX IF NOT EXISTS users_org_role_active_idx
|
|
ON users (organization_id, role, is_active, username);
|
|
|
|
CREATE INDEX IF NOT EXISTS tasks_owner_visible_created_idx
|
|
ON tasks (organization_id, created_by, created_at DESC, id DESC)
|
|
WHERE archived_at IS NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS tasks_archive_created_idx
|
|
ON tasks (organization_id, archived_at DESC, created_at DESC, id DESC)
|
|
WHERE archived_at IS NOT NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS agent_session_messages_actor_idx
|
|
ON agent_session_messages (organization_id, actor_user_id, created_at DESC)
|
|
WHERE actor_user_id IS NOT NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS audit_events_actor_created_idx
|
|
ON audit_events (organization_id, actor_user_id, created_at DESC);
|