docs: BindContext binder shape across architecture + per-feature AGENTS
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -693,8 +693,8 @@ Invoke the `superpowers:writing-plans` skill to produce a detailed, executable i
|
||||
|
||||
- `infrastructure/repositories/<entity>.repository.ts` — constructor takes `(config, tracer, logger)` with Noop defaults; every public method's body is wrapped in `tracer.startSpan(...)` and any `catch` block calls `logger.captureException(err, { tags: { feature, repo, method } })` before re-throwing.
|
||||
- `infrastructure/repositories/<entity>.repository.mock.ts` — same constructor/wrapping shape (no catch — mocks don't originate infra errors).
|
||||
- `di/bind-production.ts` — signature `(config, tracer, logger)`. Binds TRACER + LOGGER to the feature container; constructs the real repo with tracer/logger; wraps every use case + controller via `withSpan(withCapture(factory(deps)))` at bind time. `withSpan` is outermost so an errored span's timing reflects the capture-and-rethrow; `withCapture` honours the `__sentryReported` flag so a bubbled error from the repo isn't re-captured.
|
||||
- `di/bind-dev-seed.ts` — signature `(tracer, logger)`. Same wrapping as bind-production but with the populated mock.
|
||||
- `di/bind-production.ts` — signature `(ctx: BindProductionContext)` (from `@repo/core-shared/di`). Destructures `{ config, tracer, logger, bus, queue, realtime, realtimeRegistry }` from `ctx`. Binds TRACER + LOGGER to the feature container; constructs the real repo with tracer/logger; wraps every use case + controller via `withSpan(withCapture(factory(deps)))` at bind time. `withSpan` is outermost so an errored span's timing reflects the capture-and-rethrow; `withCapture` honours the `__sentryReported` flag so a bubbled error from the repo isn't re-captured. Optional fields (`bus`, `queue`, `realtime`, `realtimeRegistry`) are guarded with `?.` or cast to the full interface when the feature unconditionally requires them.
|
||||
- `di/bind-dev-seed.ts` — signature `(ctx: BindContext)` (no `config`). Same wrapping as bind-production but with the populated mock.
|
||||
|
||||
**Required exports (per feature root):** unchanged.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user