# Plan: Real-Time & WebSockets

**Status**: Draft
**Author**: Prism Core Team
**Created**: 2026-02-06
**Updated**: 2026-02-06

## Overview

Add real-time capabilities to Prism-generated applications via WebSockets and Server-Sent Events (SSE). This breaks Prism out of the request/response paradigm and enables live dashboards, collaborative editing, instant notifications, and presence indicators — turning static CRUD apps into dynamic, interactive products.

## Goals

- Define real-time channels in spec (`realtime:` section)
- Auto-generate WebSocket server with authentication and channel authorization
- Generate React hooks (`useSubscription`, `usePresence`, `useLiveQuery`) for frontend
- Support model-level live queries (subscribe to changes on any model)
- Generate presence system for collaborative features (who's online, who's editing)
- Support both WebSocket and SSE transports (SSE as fallback)

## Non-Goals

- Full CRDT-based collaborative editing (e.g., Google Docs-style)
- WebRTC for audio/video
- Message queue integration (Kafka, RabbitMQ) — deferred to a separate plan
- Offline-first / conflict resolution

## Design

### Specification Extensions

```yaml
realtime:
  enabled: true
  transport: websocket     # websocket | sse | auto
  auth_required: true

  channels:
    - name: notifications
      description: "User notifications"
      auth: per_user        # per_user | per_role | public
      events:
        - name: new_notification
          payload_model: Notification
        - name: notification_read
          payload: { id: int }

    - name: model_changes
      description: "Live model updates"
      auto_models:           # Auto-subscribe to CRUD events
        - Order
        - Ticket
      events: [created, updated, deleted]

  presence:
    enabled: true
    channels:
      - name: editors
        track_fields: [user_id, display_name, cursor_position]
```

### Technical Approach

#### 1. WebSocket Server

- FastAPI WebSocket endpoints with connection manager
- JWT authentication on WebSocket handshake
- Channel-based pub/sub with in-process event bus (Redis pub/sub optional for multi-instance)
- Heartbeat/ping-pong for connection health
- Automatic reconnection handling

```python
# Generated WebSocket manager
class ConnectionManager:
    def __init__(self):
        self.channels: dict[str, set[WebSocket]] = {}
        self.user_connections: dict[int, set[WebSocket]] = {}

    async def subscribe(self, ws: WebSocket, channel: str, user: User):
        self.authorize(channel, user)
        self.channels.setdefault(channel, set()).add(ws)

    async def broadcast(self, channel: str, event: str, data: dict):
        for ws in self.channels.get(channel, []):
            await ws.send_json({"event": event, "data": data})
```

#### 2. Model Change Events (Auto-Generated)

For each model listed in `auto_models`, Prism generates event emission in services:

```python
# Generated in OrderService
class OrderService(BaseService):
    async def create(self, data: OrderCreate) -> Order:
        order = await super().create(data)
        await realtime.broadcast(
            "model_changes",
            "order.created",
            OrderSchema.from_orm(order).dict()
        )
        return order
```

#### 3. React Hooks (Frontend)

```typescript
// Generated hooks
function useSubscription<T>(channel: string, event: string): T | null
function useLiveQuery<T>(model: string): { data: T[], loading: boolean }
function usePresence(channel: string): PresenceState[]

// Usage in generated components
const orders = useLiveQuery<Order>("Order")
const onlineUsers = usePresence("editors")
```

#### 4. SSE Fallback

- `GET /api/events/stream` endpoint with event filtering
- Auto-detect: try WebSocket, fall back to SSE if blocked (corporate proxies)
- Same channel/event semantics as WebSocket

#### 5. Presence System

- Track connected users per channel with metadata (cursor, status, etc.)
- Automatic join/leave events on connect/disconnect
- Periodic state sync for stale connection cleanup
- Frontend `usePresence` hook returns list of present users with their state

### API Changes

- `ws://host/ws` — WebSocket endpoint
- `GET /api/events/stream` — SSE endpoint
- `GET /api/realtime/channels` — List available channels
- `GET /api/realtime/presence/:channel` — Current presence state

### Database Changes

- Optional: `realtime_events` table for event persistence/replay (audit log)
- Presence state is in-memory only (Redis for multi-instance)

## Implementation Steps

1. **Spec model** — Add `RealtimeConfig`, `ChannelSpec`, `PresenceConfig` to spec models
2. **WebSocket generator** — Connection manager, auth, channel routing
3. **Event emission** — Inject event broadcasting into generated CRUD services
4. **React hooks** — `useSubscription`, `useLiveQuery`, `usePresence` with reconnection
5. **SSE generator** — SSE endpoint as WebSocket fallback
6. **Presence** — Presence tracking, join/leave events, frontend hook
7. **CLI** — `prism realtime test` to simulate events locally
8. **Tests** — WebSocket connection tests, event delivery, presence sync

## Testing Strategy

- **Unit tests**: Connection manager, channel authorization, event serialization
- **Integration tests**: WebSocket connect → subscribe → receive event → disconnect
- **Load tests**: 1000+ concurrent WebSocket connections, broadcast latency
- **Frontend tests**: Hook behavior, reconnection logic, presence updates

## Rollout Plan

1. Core WebSocket server + model change events
2. React hooks + auto-reconnection
3. SSE fallback transport
4. Presence system

## Complexity & Effort

**Effort Estimate**: 5-6 weeks (1 senior full-stack developer)
**Complexity**: HIGH — new transport layer, stateful connections, frontend hooks

## Dependencies

- Enterprise Auth (P12) — complete, needed for WebSocket JWT auth
- Service Abstraction (P14) — helpful for clean event emission injection

## Risk Assessment

**High Risks**:
- WebSocket scalability with many concurrent connections (mitigated: connection limits, Redis pub/sub)
- Memory leaks from stale connections (mitigated: heartbeat + cleanup task)
- Corporate proxy/firewall blocking WebSockets (mitigated: SSE fallback)

**Adoption Risk**: LOW — opt-in via `realtime.enabled: true`, zero impact on existing projects.

## Open Questions

- Should event history be persisted for replay on reconnect (at-least-once delivery)?
- Should channels support wildcard subscriptions (e.g., `order.*`)?
- How should rate limiting work for high-frequency events (e.g., cursor position)?
