Four read shapes. One source history.
AllSource Query Service separates tenant-scoped HTTP queries, Phoenix realtime channels, analytics endpoints, and rebuildable projections over durable Core events.
Match read path to consumer
Tenant-Scoped HTTP Reads
Serve event queries, stream discovery, schemas, projection state, and replay jobs through authenticated request-response endpoints.
Rebuildable Read Models
Fold each tenant's Core stream into current-state projections. Rebuild them from durable history when projection logic changes.
Phoenix Realtime Channels
Subscribe at `/ws` to tenant-scoped event, entity, event-type, or projection topics. Push live updates without polling.
Analytics Endpoints
Expose frequency, summary, correlation, percentile, standard-deviation, sliding-window, and session-window reads with query quotas.
One Durable Core
Query Service does not become another database. Core retains events and metadata; Query Service caches and read models remain disposable.
Read-Plane Observability
Inspect HTTP performance, WebSocket connections, projection replay lag, analytics cache state, and backend health.
Three interfaces, one source
Query Service scopes every read to a tenant while Core remains source of truth
# 1. HTTP — request-response event query
curl -s "https://your-query-service.example.com/api/events/query?event_type=page_view&limit=100" \
-H "Authorization: Bearer $API_KEY" \
-H "Authorization: Bearer $API_KEY"
# 2. Analytics — cached, quota-aware aggregation
curl -s "https://your-query-service.example.com/api/analytics/summary" \
-H "Authorization: Bearer $API_KEY"
# 3. Realtime — Phoenix Channel at /ws
const socket = new Socket("wss://your-query-service.example.com/ws", {
params: { token: authToken }
});
socket.channel("events:all", {}).join();Choose read path, not another database
Use HTTP for request-response reads, Phoenix Channels for live delivery, analytics routes for aggregations, and projections for current state. Every path derives from Core.
