Files
geo/server/migrations/20260424130000_add_desktop_primary_leases.up.sql
T
root 0823e47d46
Desktop Client Build / Resolve Build Metadata (push) Successful in 43s
Frontend CI / Frontend (push) Successful in 3m46s
Backend CI / Backend (push) Failing after 7m52s
Desktop Client Build / Build Desktop Client (push) Successful in 27m13s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 59s
feat: tighten desktop presence loop and refine admin-web UX
- Shrink desktop presence TTL to 30s and heartbeat to 15s so unexpected
  client exits surface within one TTL even if the explicit offline call
  is missed; keep migration default aligned.
- Trust a known presence miss in resolveDesktopClientOnline instead of
  falling back to the recent-heartbeat heuristic, so a still-cached
  LastSeenAt cannot mask an offline client.
- Release the runtime session before clearing renderer desktop sessions
  on shutdown to avoid leaving stale leases behind.
- Auto-refresh the MediaView account list every 5s and revamp card
  layout (inline platform badge, status tags, UID row, meta box).
- Let the brand-question AI wizard accept multiple seed topics via a
  tag-style input; candidates from each topic are merged and deduped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 19:36:24 +08:00

53 lines
2.0 KiB
SQL

-- Backfilled primary leases use the same 30s TTL as
-- server/internal/tenant/app/desktop_presence.go:desktopClientPresenceTTL.
-- Keep these values aligned; desktop heartbeat interval is TTL/2 so unexpected
-- client exits are reflected within one TTL even if explicit offline is missed.
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 '30 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;