docs: BindContext binder shape across architecture + per-feature AGENTS

This commit is contained in:
2026-05-09 12:49:55 +02:00
parent d5c965078c
commit 1e8b3f2364
9 changed files with 71 additions and 36 deletions

View File

@@ -115,7 +115,11 @@ apps/web-next/src/server/bind-production.ts (bindAll)
│ server.ts → SocketIORealtimeBroadcaster + RealtimeHandlerRegistry (passed in from server.ts)
│ page/test → InMemoryRealtimeBroadcaster + RealtimeHandlerRegistry (defaults)
│ ↓
├─ bindProductionBlog(config, tracer, logger, bus, queue, realtime, realtimeRegistry)
├─ build ctx: BindProductionContext = { config, tracer, logger, bus, queue, realtime, realtimeRegistry }
│ Required: tracer, logger, config (production only)
│ Optional: bus, queue, realtime, realtimeRegistry (guard with ?. when used)
│ ↓
├─ bindProductionBlog(ctx: BindProductionContext)
│ │
│ ├─ blogContainer.bind(TRACER).toConstantValue(tracer)
│ ├─ blogContainer.bind(LOGGER).toConstantValue(logger)
@@ -127,9 +131,23 @@ apps/web-next/src/server/bind-production.ts (bindAll)
│ ├─ // <gen:jobs> queue.register(...) in dev-seed; Payload task in prod
│ └─ // <gen:realtime-handlers> realtimeRegistry.register(...) (ADR-016, gen realtime handler)
└─ (same for auth, marketing-pages, navigation, media)
└─ (same for auth, marketing-pages, navigation, media — each receives the same ctx)
```
**`BindContext` shape (from `@repo/core-shared/di`):**
| Field | Type | Required | Notes |
|---|---|---|---|
| `tracer` | `ITracer` | always | Resolved by Rule 0 (Sentry vs Noop) |
| `logger` | `ILogger` | always | Resolved by Rule 0 |
| `config` | `SanitizedConfig` | production only | Present in `BindProductionContext`, absent in `BindContext` |
| `bus` | `EventBusProtocol?` | optional | `IEventBus` at the aggregator; protocol surface at binders |
| `queue` | `IJobQueue?` | optional | Present when `core-shared/jobs` is wired |
| `realtime` | `RealtimeBroadcasterProtocol?` | optional | `IRealtimeBroadcaster` at the aggregator |
| `realtimeRegistry` | `RealtimeRegistryProtocol?` | optional | `IRealtimeHandlerRegistry` at the aggregator |
Feature binders destructure `ctx` and use optional fields with `?.` or cast to the full interface when the feature unconditionally requires them (e.g. `bus as IEventBus` when a use case always needs the event bus).
**Why per-feature containers also get the binding:** lets internal DI-resolved code in a feature pull TRACER/LOGGER without going through the app dispatcher. In practice, only repository classes and feature-internal services would use this — controllers and use cases receive instrumentation via the bind-time wrapper.
**Why the shared container exists at all:** isolates Rule 0 resolution from feature containers. Feature containers don't need to know if Sentry is on or off — they just receive an `ITracer` instance.