Files
PiCloud/crates/manager-core/migrations/0021_topics.sql
MechaCat02 fcbcc576a2 feat(v1.1.6): realtime channels + v1.1.5 follow-ups + version bumps
Server-side realtime SSE on per-app pub/sub topics, plus the three
v1.1.5 follow-ups and the version bumps.

Realtime:
- topics registry (0021) + admin endpoints + Capability::AppTopicManage
  (-> app:admin; no new scope).
- GET /realtime/topics/{topic} SSE endpoint (orchestrator-core data
  plane): Host -> app, RealtimeAuthority gate (404 missing/internal,
  401 bad/absent token), broadcast::Receiver stream + heartbeat.
- RealtimeBroadcaster / RealtimeEvent / RealtimeAuthority traits
  (picloud-shared); InProcessBroadcaster + GC (orchestrator-core);
  DB-backed RealtimeAuthorityImpl (manager-core). Publish path fans out
  to in-process subscribers after the durable outbox commit (best-effort,
  panic-isolated).
- HMAC subscriber tokens (subscriber_token.rs) + app_secrets table (0022)
  + pubsub::subscriber_token SDK (schema 1.6 -> 1.7). TTL clamp + env
  overrides.
- Dashboard Topics tab (register/list/edit/delete, prominent external
  badge, flip confirmation).

v1.1.5 follow-ups:
- Empty blobs accepted (NewFile/FileUpdate::validate) + round-trip test.
- Orphan *.tmp.* sweeper (spawn_files_orphan_sweep).
- Dispatcher e2e tests, one per trigger kind (DATABASE_URL-gated).

Versions: workspace 1.1.6, SDK 1.7, dashboard 0.12.0. Schema-snapshot
golden re-blessed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:18:50 +02:00

32 lines
1.5 KiB
SQL

-- v1.1.6: Explicit registration for externally-subscribable topics.
--
-- Internal-only topics remain implicit per the §5 design-notes
-- decision: anyone can publish_durable("any.topic", msg) and triggers
-- can subscribe without a row here. This table only holds topics that
-- have been explicitly externalized — external SSE subscribers can
-- only subscribe to topics with a row here AND external_subscribable
-- = TRUE.
--
-- The publish path (v1.1.5's publish_durable) does NOT consult this
-- table: publishing to a topic with no row still fans out to triggers
-- and to any in-process external subscribers (none exist for an
-- unregistered topic, since external subscribers can't subscribe to
-- one). The topics table is read by the SSE subscribe path only.
--
-- auth_mode values: 'public' + 'token' in v1.1.6. 'session' arrives in
-- v1.1.8 (users-SDK); 'script' arrives in v1.2 (script-mediated auth).
-- The CHECK constraint extends in those releases.
CREATE TABLE topics (
app_id UUID NOT NULL REFERENCES apps(id) ON DELETE CASCADE,
name TEXT NOT NULL,
external_subscribable BOOL NOT NULL DEFAULT FALSE,
auth_mode TEXT NOT NULL DEFAULT 'public'
CHECK (auth_mode IN ('public', 'token')),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (app_id, name)
);
-- Hot lookup: "is topic T in app X externally subscribable?" The PK
-- (app_id, name) already covers this; an explicit index is redundant.