-- Backfilled primary leases use the same 90s TTL as -- server/internal/tenant/app/desktop_presence.go:desktopClientPresenceTTL. -- Keep these values aligned; desktop heartbeat interval must be < TTL/2 so -- a single missed heartbeat does not let another client steal primary. CREATE TABLE IF NOT EXISTS desktop_client_primary_leases ( tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, workspace_id BIGINT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE, primary_client_id UUID NOT NULL REFERENCES desktop_clients(id) ON DELETE CASCADE, lease_expires_at TIMESTAMPTZ NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (tenant_id, workspace_id) ); CREATE INDEX IF NOT EXISTS idx_desktop_client_primary_leases_primary_client ON desktop_client_primary_leases (primary_client_id); CREATE INDEX IF NOT EXISTS idx_desktop_clients_tenant_workspace_seen_active ON desktop_clients (tenant_id, workspace_id, last_seen_at DESC, created_at DESC, id DESC) WHERE revoked_at IS NULL; CREATE INDEX IF NOT EXISTS idx_desktop_clients_tenant_workspace_user_seen_active ON desktop_clients (tenant_id, workspace_id, user_id, last_seen_at DESC, created_at DESC, id DESC) WHERE revoked_at IS NULL; INSERT INTO desktop_client_primary_leases ( tenant_id, workspace_id, primary_client_id, lease_expires_at ) SELECT tenant_id, workspace_id, id, COALESCE(last_seen_at, created_at) + INTERVAL '90 seconds' FROM ( SELECT dc.id, dc.tenant_id, dc.workspace_id, dc.created_at, dc.last_seen_at, ROW_NUMBER() OVER ( PARTITION BY dc.tenant_id, dc.workspace_id ORDER BY dc.last_seen_at DESC NULLS LAST, dc.created_at DESC, dc.id DESC ) AS rn FROM desktop_clients dc WHERE dc.revoked_at IS NULL ) ranked_clients WHERE rn = 1 ON CONFLICT (tenant_id, workspace_id) DO NOTHING;