-- Bind each employee-facing AgentBus channel and ERP browser worker to one -- platform account. Historical AgentBus work remains deliberately unassigned: -- ownership cannot be inferred safely from an old channel key. ALTER TABLE users ADD COLUMN IF NOT EXISTS erp_account text; ALTER TABLE users DROP CONSTRAINT IF EXISTS users_erp_account_length_check; ALTER TABLE users ADD CONSTRAINT users_erp_account_length_check CHECK (erp_account IS NULL OR char_length(erp_account) BETWEEN 1 AND 200); ALTER TABLE users DROP CONSTRAINT IF EXISTS users_admin_erp_account_check; ALTER TABLE users ADD CONSTRAINT users_admin_erp_account_check CHECK (role <> 'admin' OR erp_account IS NULL); CREATE UNIQUE INDEX IF NOT EXISTS users_org_erp_account_unique_idx ON users (organization_id, lower(erp_account)) WHERE erp_account IS NOT NULL; ALTER TABLE user_channels ADD COLUMN IF NOT EXISTS owner_user_id uuid; ALTER TABLE user_channels DROP CONSTRAINT IF EXISTS user_channels_owner_scope_fkey; ALTER TABLE user_channels ADD CONSTRAINT user_channels_owner_scope_fkey FOREIGN KEY (organization_id, owner_user_id) REFERENCES users (organization_id, id); CREATE UNIQUE INDEX IF NOT EXISTS user_channels_owner_unique_idx ON user_channels (organization_id, owner_user_id) WHERE owner_user_id IS NOT NULL; CREATE INDEX IF NOT EXISTS user_channels_owner_status_idx ON user_channels (organization_id, owner_user_id, enabled, status); UPDATE user_channels SET enabled = false, status = 'error', last_error = '渠道尚未绑定员工平台账号,监听器不会启动。', updated_at = now() WHERE owner_user_id IS NULL AND enabled = true; ALTER TABLE tasks ADD COLUMN IF NOT EXISTS assigned_user_id uuid; ALTER TABLE tasks DROP CONSTRAINT IF EXISTS tasks_assignee_scope_fkey; ALTER TABLE tasks ADD CONSTRAINT tasks_assignee_scope_fkey FOREIGN KEY (organization_id, assigned_user_id) REFERENCES users (organization_id, id); UPDATE tasks SET assigned_user_id = created_by WHERE assigned_user_id IS NULL AND source = 'manual' AND created_by IS NOT NULL; CREATE INDEX IF NOT EXISTS tasks_assignee_visible_created_idx ON tasks (organization_id, assigned_user_id, created_at DESC, id DESC); CREATE INDEX IF NOT EXISTS tasks_assignee_queue_idx ON tasks (organization_id, assigned_user_id, status, created_at, id) WHERE archived_at IS NULL; ALTER TABLE browser_connections ADD COLUMN IF NOT EXISTS erp_account_verified boolean NOT NULL DEFAULT false, ADD COLUMN IF NOT EXISTS erp_account_fingerprint text; WITH ranked_connections AS ( SELECT id, row_number() OVER ( PARTITION BY organization_id, user_id ORDER BY last_seen_at DESC, id DESC ) AS worker_rank FROM browser_connections WHERE status = 'connected' ) UPDATE browser_connections connection SET status = 'superseded' FROM ranked_connections ranked WHERE connection.id = ranked.id AND ranked.worker_rank > 1; CREATE UNIQUE INDEX IF NOT EXISTS browser_connections_active_user_unique_idx ON browser_connections (organization_id, user_id) WHERE status = 'connected'; CREATE INDEX IF NOT EXISTS browser_connections_worker_freshness_idx ON browser_connections (organization_id, user_id, status, last_seen_at DESC);