From 9840a4e26aba4c2e3ba74cec282a836c5725a972 Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Sat, 9 May 2026 00:47:12 +0200 Subject: [PATCH] docs(claude): realtime generator + R0/R1/R2 conventions --- CLAUDE.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 681f006..f640cb4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,6 +11,7 @@ pnpm turbo boundaries # Validate workspace dependency graph pnpm turbo gen feature # Scaffold a new feature package (see docs/guides/scaffolding-a-feature.md) pnpm turbo gen event # Scaffold an event contract (publish) or handler (consume) pnpm turbo gen job # Scaffold a background job +pnpm turbo gen realtime # Scaffold a realtime channel or inbound handler docker compose up -d # Start PostgreSQL ``` @@ -37,6 +38,7 @@ Turborepo + pnpm monorepo organized by vertical features. Each feature (`auth`, - `docs/guides/scaffolding-a-feature.md` — `turbo gen feature` reference (fast path; prefer this over the manual walkthrough) - `docs/guides/adding-a-feature.md` — End-to-end new feature walkthrough (manual path; for cases the generator's Phase-1 scope doesn't cover) - `docs/guides/events-and-jobs.md` — publish/consume/schedule cookbook (cross-feature events + background jobs) +- `docs/guides/realtime.md` — Socket.IO channels, broadcasts, handlers ## Key Conventions @@ -64,6 +66,9 @@ Turborepo + pnpm monorepo organized by vertical features. Each feature (`auth`, - **Cross-feature events go through `IEventBus` (E0)** — In-feature reactions are direct use-case calls, not bus publishes. The bus is for *crossing* feature boundaries (e.g. `auth` → `marketing-pages` welcome email) - **Event contracts are public; handlers are private (E1)** — Publisher's `events/.event.ts` is exported from the feature root barrel. Consumer's `events/handlers/on--.handler.ts` is never re-exported (ESLint-enforced via `core-eslint/rules/no-handler-reexport`) - **Jobs are for *deferred* work, not abstraction (J0)** — Synchronous code stays synchronous. A job exists only when something must run off the request path (latency, retries, cron). Feature packages enqueue via `IJobQueue` only — direct `payload.jobs.queue()` is ESLint-blocked outside `core-shared/jobs/` +- **Realtime is for state delivery, not for replacing tRPC (R0)** — Persistent request/response operations belong on tRPC procedures. Use realtime when the server needs to push without a request or the data is too high-frequency for HTTP +- **Realtime channel descriptors are exported; handlers are private (R1)** — A feature's `realtime/.channel.ts` is re-exported from the root barrel; `realtime/handlers/*.handler.ts` is wired only in bind-* files and never re-exported (ESLint-enforced via `no-realtime-handler-reexport`) +- **`socket.io` lives in `@repo/core-realtime` only (R2)** — Feature packages MUST NOT import `socket.io` or `socket.io-client`. ESLint rule `no-direct-socket-io` enforces this; allowlist covers `core-realtime/src/socket-io-*.ts` and `apps/*/server.ts` ## MCP Servers