# Realtime

Quickback ships **two parallel realtime primitives**, both backed by Cloudflare Durable Objects:

- **`/broadcast/v1/*` — server fan-out.** One DO instance per subscription scope. Postgres-changes events from CRUD routes plus custom broadcast events flow out to every subscriber, with role filtering and per-role field masking applied. Best for "tell every client in this shared scope that something changed." The scope can be an organization, a specific user, or a compiler-resolved resource key like `events:evt_123`. Documented on this page.
- **`/realtime/<binding>/<room-id>` — bidirectional rooms.** One DO instance per room (per document, per interview, per game). Client↔client messages, presence, and CRDT-friendly state. Use these for collaborative editing. See [PartyServer rooms](/stack/realtime/partyserver-rooms).

Both share the same auth model and ride on the same compiled worker; they solve different problems.

## Architecture

```
┌──────────────────────────────────────────┐
│            Quickback Worker              │
│                                          │
│  ┌──────────┐    DO binding   ┌────────────────────┐
│  │ Hono API │ ──────────────► │ Broadcaster (DO)   │
│  │          │                 │ WebSocket manager   │
│  └──────────┘                 └─────────┬──────────┘
│                                         │
└─────────────────────────────────────────┼┘
                                          │ WebSocket
                                          │
                                 ┌────────▼─────────┐
                                 │  Browser Clients  │
                                 │   (CMS, Account,  │
                                 │    Admin, Custom)  │
                                 └──────────────────┘
```

The Broadcaster Durable Object runs **inline** in your main Quickback worker — no separate worker deployment needed. The API calls the DO directly via its binding (in-process, no network hop).

1. **Quickback Worker** — Your compiled API with the Broadcaster DO class exported from the same worker.
2. **Broadcaster (Durable Object)** — Manages WebSocket connections per subscription scope. One instance per `scopeKey`, organization, or user lane.
3. **Browser Clients** — CMS, Account, Admin, and custom frontends connect via WebSocket on the same origin.

## Key Features

| Feature | Description |
|---------|-------------|
| Scope-aware fan-out | Routes by `scopeKey`, `organizationId`, or `userId` |
| Role-based filtering | Only send events to users with matching roles |
| Per-role masking | Different users see different field values based on their role |
| User-specific targeting | Send events to a specific user within an org |
| Resource-scoped tickets | Reuse authz relationship roles to mint scope-bound ws tickets |
| Custom broadcasts | Arbitrary events beyond CRUD |
| Custom namespaces | `defineRealtime()` for type-safe event helpers |
| Ticket-based auth | HMAC-signed tickets verified at WebSocket upgrade — no HTTP round-trip |

## Enabling Realtime

Add `realtime` to individual table definitions:

```typescript
export default defineTable(applications, {
  firewall: [{ field: 'organizationId', equals: 'ctx.activeOrgId' }],
  realtime: {
    enabled: true,
    onInsert: true,
    onUpdate: true,
    onDelete: true,
    requiredRoles: ["recruiter", "hiring-manager"],
    fields: ["id", "candidateId", "stage"],
  },
});
```

And enable the realtime binding in your database config. The compiler generates the Durable Object class, helper functions, and wrangler bindings — all within your main worker.

```typescript
providers: {
  database: defineDatabase("cloudflare-d1", {
    realtime: {
      wsTicket: {
        role: "attendee",
        requestField: "eventId",
        scopeTable: "events",
      },
    },
  }),
}
```

With that config, `/broadcast/v1/ws-ticket` can authenticate the caller, verify the declared authz relationship role against `body.eventId`, and mint a short-lived ticket scoped to the resolved `events:<id>` channel.

## Pages

- **[Durable Objects Setup](/stack/realtime/durable-objects)** — Broadcaster configuration, wrangler bindings, event formats, masking, and custom namespaces
- **[Using Realtime](/stack/realtime/using-realtime)** — Subscribing to `/broadcast/v1/*`: WebSocket connection, ticket auth, client-side handling
- **[PartyServer Rooms](/stack/realtime/partyserver-rooms)** — Per-room collab via `/realtime/<binding>/<room-id>`: presence, live notes, room IDs
