Initial commit
This commit is contained in:
87
docs/library-decisions/2026-05-14-@opentelemetry/api-logs.md
Normal file
87
docs/library-decisions/2026-05-14-@opentelemetry/api-logs.md
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@opentelemetry/api-logs"
|
||||
version: "^0.55.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-017
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @opentelemetry/api-logs license
|
||||
- npm view @opentelemetry/api-logs version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view @opentelemetry/api-logs license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@opentelemetry/api-logs` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the OpenTelemetry community under the CNCF as part of the unified OTel JS repository. Versioned alongside the SDK packages; the 0.55.x line is current and aligns with the SDK release cycle.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-017 §4 designates `@opentelemetry/api-logs` as the Logs API for `OtelLogger` in `core-shared/instrumentation/`. Feature packages interact with logging only via the `ILogger` interface (ADR-014 R34); they do not import this package directly.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@opentelemetry/api-logs` is the only OTel Logs API in the workspace. It complements `@opentelemetry/api` (traces) and `@opentelemetry/sdk-metrics` (metrics) to form the complete three-signal OTel pipeline. No competing logging API is present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@opentelemetry/api-logs` is a pure API package with no network communication or data transmission. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@opentelemetry/api-logs` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/otel/otel-logger.ts` implements `ILogger` using `@opentelemetry/api-logs` to emit log records via the OTel Logs API (ADR-017 §4). `packages/core-audit` also depends on it for structured audit log emission.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
`OtelLogger` replaces the former `SentryLogger` which called Sentry SDK methods directly. `@opentelemetry/api-logs` provides the vendor-neutral log emission surface so that the downstream exporter (Sentry via `@sentry/opentelemetry`) can be swapped without touching logger code.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. `@opentelemetry/api-logs` is called in every `OtelLogger` log-emission path in `core-shared`. Moving to a different logs API (e.g., a custom abstraction) would require rewriting both the logger implementation and the OTel SDK initialization. The `ILogger` interface boundary (ADR-014) limits blast radius to `core-shared`.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Winston / Pino as the log API** — Considered before ADR-017. Rejected because a separate log library alongside OTel would create a split-pipeline problem: traces and logs would travel through different channels, losing correlation.
|
||||
2. **Sentry SDK breadcrumb API directly** — Rejected in ADR-017: direct Sentry coupling prevents vendor swap without code changes.
|
||||
|
||||
See ADR-017 for the full decision rationale.
|
||||
87
docs/library-decisions/2026-05-14-@opentelemetry/api.md
Normal file
87
docs/library-decisions/2026-05-14-@opentelemetry/api.md
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@opentelemetry/api"
|
||||
version: "^1.9.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-017
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @opentelemetry/api license
|
||||
- npm view @opentelemetry/api version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view @opentelemetry/api license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@opentelemetry/api` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the OpenTelemetry community under the CNCF. The 1.x stable API line receives regular releases; the project is a CNCF incubating project with broad industry backing.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-017 §8 explicitly permits `@opentelemetry/api` for use within `core-shared/instrumentation/` without restriction. Feature packages use it via the `ITracer`/`ILogger` interfaces only; they do not import this package directly (ESLint boundary rules, ADR-010).
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@opentelemetry/api` is the CNCF-standard instrumentation API. No competing tracing API is present in the workspace. The API package is the stable, zero-dependency interface layer intentionally kept separate from SDK implementations.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@opentelemetry/api` is a pure instrumentation API with no network communication, telemetry transmission, or data storage. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@opentelemetry/api` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/` consumes `@opentelemetry/api` to implement `OtelTracer` and `OtelLogger` (ADR-017). `packages/core-audit` also depends on it for span context propagation in audit records.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Prior to ADR-017, `core-shared` used Sentry SDK methods directly in `SentryTracer` and `SentryLogger`. `@opentelemetry/api` replaces direct Sentry SDK calls as the instrumentation substrate, allowing vendor swaps via exporter configuration rather than code rewrites.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. `@opentelemetry/api` is the instrumentation interface called throughout `core-shared/instrumentation/`. Migrating away means replacing all span creation, context propagation, and log emission with a different API. The interfaces (`ITracer`, `ILogger`, `IMetrics`) in ADR-014 isolate feature packages, but the core instrumentation layer itself is deeply coupled to the OTel API shape.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Sentry SDK directly** — Rejected in ADR-017: couples the impl to Sentry forever; vendor swap requires rewriting every `*Tracer`/`*Logger` pair.
|
||||
2. **OpenCensus** — CNCF predecessor to OpenTelemetry; reached end-of-life and merged into OpenTelemetry. Not viable.
|
||||
|
||||
See ADR-017 for the full decision rationale.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@opentelemetry/context-async-hooks"
|
||||
version: "^1.28.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-017
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @opentelemetry/context-async-hooks license
|
||||
- npm view @opentelemetry/context-async-hooks version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view @opentelemetry/context-async-hooks license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@opentelemetry/context-async-hooks` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the OpenTelemetry community. Versioned with the OTel JS SDK at 1.x; the package tracks Node.js async_hooks API stability and receives updates alongside the SDK.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-017 mandates OTel as the instrumentation substrate. `@opentelemetry/context-async-hooks` provides the Node.js `AsyncLocalStorage`-based context manager required for automatic span propagation across async boundaries. It lives exclusively in `core-shared/instrumentation/otel/` and `core-audit` init paths.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@opentelemetry/context-async-hooks` is the standard OTel context manager for Node.js. No competing context propagation mechanism is present in the workspace.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@opentelemetry/context-async-hooks` is a pure context propagation adapter with no network communication or data transmission. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@opentelemetry/context-async-hooks` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/otel/` registers `AsyncLocalStorageContextManager` from this package during OTel SDK init to enable automatic trace context propagation across Node.js async operations. `packages/core-audit` depends on it for span context in audit records.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Replaces the manual context threading that would otherwise be required to pass span context through async call chains. Without this package, every async function would need to explicitly forward a context argument — defeating the automatic propagation guarantee of OTel.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. `@opentelemetry/context-async-hooks` is registered in one place during OTel SDK initialization. Swapping to a different context manager (e.g., `@opentelemetry/context-zone` for browser) is a one-line change in the SDK init file.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **`@opentelemetry/context-zone`** — Zone.js-based context manager designed for Angular/browser environments. Not applicable for a Node.js server; `async_hooks` is the correct primitive for server-side async context.
|
||||
2. **Manual context passing** — Thread context explicitly through every function signature. Rejected: error-prone at scale and defeats the auto-instrumentation value of the OTel SDK.
|
||||
|
||||
See ADR-017 for the full decision rationale.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@opentelemetry/instrumentation-http"
|
||||
version: "^0.55.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-017
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @opentelemetry/instrumentation-http license
|
||||
- npm view @opentelemetry/instrumentation-http version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view @opentelemetry/instrumentation-http license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@opentelemetry/instrumentation-http` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the OpenTelemetry community as the first-party HTTP instrumentation plugin. The 0.55.x line is current and tracks the OTel SDK release cycle.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-017 §11 explicitly enables HTTP auto-instrumentation in `initOtelServerNode`. The plugin is configured with query-string stripping on `http.url.path` and a path ignore list (`/_health`, `/_otel-export`) to prevent noise and PII leakage. Restricted to `core-shared/instrumentation/otel/` init paths.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@opentelemetry/instrumentation-http` is the standard OTel HTTP auto-instrumentation. No competing HTTP span emitter is present in the workspace.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@opentelemetry/instrumentation-http` is a pure instrumentation plugin with no independent data transmission. Spans it emits are routed through the configured OTel exporter (Sentry via `@sentry/opentelemetry`). EU residency is governed by the exporter configuration.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@opentelemetry/instrumentation-http` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/otel/init-otel-server-node.ts` registers `HttpInstrumentation` with query-string redaction and path ignore rules (ADR-017 §11). This eliminates manual span creation for every incoming HTTP request and outgoing HTTP call.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Manual `tracer.startSpan()` / `tracer.endSpan()` wrapping around every `http.IncomingMessage` handler and `http.request()` call site. The auto-instrumentation patches Node.js core `http` and `https` modules to emit spans automatically.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. `HttpInstrumentation` is registered in one init file. Removing it means disabling the plugin registration and optionally adding manual spans at HTTP boundaries — localized to the SDK init and any call sites that relied on automatic context propagation.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Manual HTTP spans** — No plugin needed, but requires wrapping every `http.request` and route handler explicitly. Rejected: high boilerplate, easy to miss call sites, loses automatic context propagation headers.
|
||||
2. **`dd-trace` HTTP plugin** — Datadog-specific. Rejected in ADR-017: vendor lock-in; OTel plugin achieves the same coverage with vendor-neutral output.
|
||||
|
||||
See ADR-017 for the full decision rationale.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@opentelemetry/instrumentation-pg"
|
||||
version: "^0.50.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-017
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @opentelemetry/instrumentation-pg license
|
||||
- npm view @opentelemetry/instrumentation-pg version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view @opentelemetry/instrumentation-pg license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@opentelemetry/instrumentation-pg` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the OpenTelemetry community as the first-party PostgreSQL (`pg`) instrumentation plugin. The 0.50.x line is current and tracks the OTel SDK release cycle.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-017 §11 explicitly enables pg auto-instrumentation in `initOtelServerNode` with `enhancedDatabaseReporting: false` to prevent SQL statement capture (PII protection for WHERE clauses). Restricted to `core-shared/instrumentation/otel/` init paths.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@opentelemetry/instrumentation-pg` is the standard OTel PostgreSQL auto-instrumentation. No competing database span emitter is present in the workspace.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@opentelemetry/instrumentation-pg` is a pure instrumentation plugin with no independent data transmission. Spans are routed through the configured OTel exporter. EU residency is governed by the exporter configuration.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@opentelemetry/instrumentation-pg` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/otel/init-otel-server-node.ts` registers `PgInstrumentation` with `enhancedDatabaseReporting: false` (ADR-017 §11, R32). This emits database spans for every Payload CMS PostgreSQL query without capturing full SQL text that may contain PII.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Manual database span wrapping around every `pg` query call site. The auto-instrumentation patches the `pg` module to emit spans automatically, including connection pooling and query timing data.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. `PgInstrumentation` is registered in one init file. Removing it means disabling the plugin and optionally adding manual spans at `pg` query call sites — localized to the SDK init.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Manual pg spans** — No plugin needed, but requires wrapping every Payload CMS / pg query explicitly. Rejected: Payload's query layer abstracts away direct `pg` calls, making manual wrapping impractical without forking Payload internals.
|
||||
2. **`pg-monitor` or query logging middleware** — Log-based approach with no OTel integration. Rejected: produces log entries outside the trace pipeline, losing span correlation.
|
||||
|
||||
See ADR-017 for the full decision rationale.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@opentelemetry/instrumentation-undici"
|
||||
version: "^0.10.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-017
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @opentelemetry/instrumentation-undici license
|
||||
- npm view @opentelemetry/instrumentation-undici version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view @opentelemetry/instrumentation-undici license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@opentelemetry/instrumentation-undici` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the OpenTelemetry community. The 0.10.x line is current and tracks the OTel SDK release cycle. Undici is the HTTP client used by Node.js `fetch` and Next.js server-side requests.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-017 §11 explicitly enables undici auto-instrumentation in `initOtelServerNode`. Undici is the underlying client for Node.js `fetch()` calls including Next.js server components and API route fetch calls. Restricted to `core-shared/instrumentation/otel/` init paths.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@opentelemetry/instrumentation-undici` is the standard OTel undici auto-instrumentation. No competing undici span emitter is present in the workspace. It complements `instrumentation-http` (Node.js http module) for full outbound request coverage.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@opentelemetry/instrumentation-undici` is a pure instrumentation plugin with no independent data transmission. Spans are routed through the configured OTel exporter. EU residency is governed by the exporter configuration.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@opentelemetry/instrumentation-undici` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/otel/init-otel-server-node.ts` registers `UndiciInstrumentation` (ADR-017 §11). This captures outbound fetch calls from Next.js server components and API routes without manual span wrapping.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Manual span wrapping around `fetch()` and undici `request()` calls. Since Node.js 18+, `fetch` is built on undici, meaning `instrumentation-http` alone would miss `fetch`-based outbound calls. This plugin fills the gap.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. `UndiciInstrumentation` is registered in one init file. Removing it means disabling the plugin; outbound `fetch` calls would lose automatic spans but no code outside the init file would change.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **`instrumentation-http` alone** — Sufficient for direct `http.request()` calls but misses `fetch()`/undici calls in Next.js server components. Rejected as incomplete coverage.
|
||||
2. **Manual fetch wrapper** — Wrapping every `fetch` call with span creation. Rejected: Next.js makes fetch calls internally (e.g., during RSC rendering), making exhaustive wrapping impractical.
|
||||
|
||||
See ADR-017 for the full decision rationale.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@opentelemetry/instrumentation"
|
||||
version: "^0.55.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-017
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @opentelemetry/instrumentation license
|
||||
- npm view @opentelemetry/instrumentation version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view @opentelemetry/instrumentation license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@opentelemetry/instrumentation` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the OpenTelemetry community as the base package for auto-instrumentation plugins. The 0.55.x line is current and tracks the SDK release cycle.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-017 §11 enables auto-instrumentations (HTTP, undici, pg) in `initOtelServerNode`. `@opentelemetry/instrumentation` provides the base `InstrumentationBase` class and registration utilities required by all instrumentation plugins. It lives in `core-shared/instrumentation/otel/` init paths only.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@opentelemetry/instrumentation` is the standard OTel plugin infrastructure. No competing auto-instrumentation framework is present in the workspace.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@opentelemetry/instrumentation` is a pure instrumentation framework with no network communication or data transmission. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@opentelemetry/instrumentation` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/otel/init-otel-server-node.ts` uses `@opentelemetry/instrumentation` to register the HTTP, undici, and pg instrumentation plugins (ADR-017 §11). These auto-instrumentations eliminate manual span creation for common I/O operations.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Manual span wrapping around HTTP calls, database queries, and fetch operations. `@opentelemetry/instrumentation` enables the auto-instrumentation plugins that patch Node.js built-ins and popular libraries to emit spans automatically, replacing boilerplate `tracer.startSpan()` calls.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. `@opentelemetry/instrumentation` is used only at SDK init time to register plugin instances. Removing it requires unregistering the auto-instrumentation plugins and optionally adding manual spans at call sites — a localized change in the init file.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Manual span instrumentation only** — No auto-instrumentation base package needed, but every HTTP call and DB query would require explicit span wrapping. Rejected: high boilerplate cost, easy to miss call sites.
|
||||
2. **DD-trace or other APM SDK** — Vendor-specific auto-instrumentation agents. Rejected in ADR-017: vendor lock-in; OTel auto-instrumentations achieve the same coverage with vendor-neutral output.
|
||||
|
||||
See ADR-017 for the full decision rationale.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@opentelemetry/resources"
|
||||
version: "^1.27.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-017
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @opentelemetry/resources license
|
||||
- npm view @opentelemetry/resources version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view @opentelemetry/resources license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@opentelemetry/resources` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the OpenTelemetry community. The 1.27.x line is on the stable 1.x track and receives regular releases. Stable versioning reflects the maturity of the resources specification.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-017 §8 restricts `@opentelemetry/resources` to `**/instrumentation/otel/**` and app init paths. The `Resource` class is used in `initOtelServerNode` to attach service name, version, and environment attributes to all telemetry signals. Feature packages never import it directly.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@opentelemetry/resources` is the standard OTel resource detection package. No competing resource attribution mechanism is present in the workspace.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@opentelemetry/resources` is a pure configuration package that attaches static metadata to telemetry signals. It has no network communication or data transmission. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@opentelemetry/resources` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/otel/init-otel-server-node.ts` uses `Resource` to tag all OTel signals with `service.name`, `service.version`, and `deployment.environment` attributes, enabling filtering by service in Sentry and future backends.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Manual tag propagation that would otherwise require attaching service metadata to every span and log record individually. `Resource` is set once at SDK init time and propagates to all signals automatically.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. `@opentelemetry/resources` is used in one SDK init file. Removing it means losing automatic service metadata on signals — signals would still be emitted but lose `service.name` attribution unless manually added to each span.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Manual span attributes** — Set `service.name` on every `startSpan()` call. Rejected: error-prone at scale; resources are a first-class OTel concept designed for this exact purpose.
|
||||
2. **Sentry release/environment config** — Sentry SDK accepts `release` and `environment` directly. Rejected: Sentry-specific; OTel Resource is the vendor-neutral mechanism that works with any exporter.
|
||||
|
||||
See ADR-017 for the full decision rationale.
|
||||
87
docs/library-decisions/2026-05-14-@opentelemetry/sdk-logs.md
Normal file
87
docs/library-decisions/2026-05-14-@opentelemetry/sdk-logs.md
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@opentelemetry/sdk-logs"
|
||||
version: "^0.55.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-017
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @opentelemetry/sdk-logs license
|
||||
- npm view @opentelemetry/sdk-logs version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view @opentelemetry/sdk-logs license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@opentelemetry/sdk-logs` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the OpenTelemetry community. The 0.55.x line is current and tracks the OTel JS SDK release cycle. The Logs signal is in active specification development within CNCF.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-017 §8 restricts `@opentelemetry/sdk-logs` to `**/instrumentation/otel/**` and app init paths. `LoggerProvider` and `SimpleLogRecordProcessor` / `BatchLogRecordProcessor` are configured exclusively in `core-shared/instrumentation/otel/init-otel-server-node.ts`. Feature packages use only `@opentelemetry/api-logs` (the stable API), never the SDK directly.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@opentelemetry/sdk-logs` is the OTel Logs SDK implementation. No competing log pipeline SDK is present in the workspace.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@opentelemetry/sdk-logs` is the log pipeline infrastructure with no independent data transmission. All log records it processes are forwarded through the configured exporter (Sentry via `@sentry/opentelemetry`). EU residency is governed by the exporter's DSN configuration.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@opentelemetry/sdk-logs` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/otel/init-otel-server-node.ts` instantiates `LoggerProvider` and registers `PiiScrubLogRecordProcessor` followed by `SentryLogRecordProcessor` from `@sentry/opentelemetry`. The PII scrub processor runs before the Sentry exporter (ADR-017 §7).
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
The former `SentryLogger` which called Sentry SDK's `captureException` and breadcrumb APIs directly. `@opentelemetry/sdk-logs` provides the pipeline infrastructure that decouples log emission from the backend exporter.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. `@opentelemetry/sdk-logs` is the log pipeline backbone. Removing it requires replacing the entire log processing chain — provider, processors, and exporter wiring — in `core-shared`. The `ILogger` boundary (ADR-014) isolates feature packages, but the core log pipeline is non-trivially coupled to the OTel SDK.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Winston + transport** — A well-established Node.js logger with pluggable transports. Rejected in ADR-017: separate pipeline from traces means no automatic span-log correlation; correlation requires manual trace ID injection into every log message.
|
||||
2. **Pino** — High-performance JSON logger. Same rejection reason as Winston: separate pipeline, no automatic context propagation from OTel spans.
|
||||
|
||||
See ADR-017 for the full decision rationale.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@opentelemetry/sdk-metrics"
|
||||
version: "^1.27.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-017
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @opentelemetry/sdk-metrics license
|
||||
- npm view @opentelemetry/sdk-metrics version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view @opentelemetry/sdk-metrics license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@opentelemetry/sdk-metrics` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the OpenTelemetry community. The 1.27.x line is on the stable 1.x track; the metrics specification is stable within CNCF.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-017 §8 restricts `@opentelemetry/sdk-metrics` to `**/instrumentation/otel/**` and app init paths. `MeterProvider` is configured in `core-shared/instrumentation/otel/init-otel-server-node.ts`. Feature packages use only `@opentelemetry/api`'s `metrics` API (indirectly via `IMetrics`), never the SDK directly.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@opentelemetry/sdk-metrics` is the OTel metrics SDK implementation. No competing metrics SDK is present in the workspace. The `IMetrics` interface (ADR-017 §10) is backed exclusively by this package.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@opentelemetry/sdk-metrics` is the metrics pipeline infrastructure with no independent data transmission. All metrics are forwarded through the configured exporter. EU residency is governed by the exporter's DSN configuration.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@opentelemetry/sdk-metrics` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/otel/init-otel-server-node.ts` instantiates `MeterProvider` and backs the `OtelMetrics` implementation of `IMetrics` (ADR-017 §10). The three `IMetrics` methods (`counter`, `histogram`, `gauge`) map to OTel counter, histogram, and UpDownCounter instruments.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
ADR-014 had no `IMetrics` signal. `@opentelemetry/sdk-metrics` introduces the metrics signal as the SDK backing for the new `IMetrics` interface (ADR-017 §10). It supersedes any ad-hoc counter increment patterns that would otherwise have been added without a unified metrics pipeline.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. `@opentelemetry/sdk-metrics` backs the `OtelMetrics` implementation used throughout `core-shared`. Replacing it requires implementing the three `IMetrics` instruments with a different metrics SDK and re-registering with the OTel SDK. The `IMetrics` interface (ADR-017 §10) isolates feature packages from the SDK details.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Prometheus client (`prom-client`)** — Popular Node.js metrics library. Rejected in ADR-017: separate pipeline from traces/logs; no automatic span context on metrics; would require a second init path alongside OTel.
|
||||
2. **Statsd / DogStatsD** — Rejected: requires a separate collector sidecar; UDP-based with no context propagation; vendor-coupling concern for DogStatsD.
|
||||
|
||||
See ADR-017 for the full decision rationale.
|
||||
87
docs/library-decisions/2026-05-14-@opentelemetry/sdk-node.md
Normal file
87
docs/library-decisions/2026-05-14-@opentelemetry/sdk-node.md
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@opentelemetry/sdk-node"
|
||||
version: "^0.55.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-017
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @opentelemetry/sdk-node license
|
||||
- npm view @opentelemetry/sdk-node version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view @opentelemetry/sdk-node license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@opentelemetry/sdk-node` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the OpenTelemetry community. The 0.55.x line is current and tracks the OTel JS SDK release cycle. `sdk-node` is the meta-package that wires together the trace, log, metric, and auto-instrumentation subsystems for Node.js.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-017 §8 restricts `@opentelemetry/sdk-node` to `**/instrumentation/otel/**` and app init paths. `NodeSDK` is instantiated once in `core-shared/instrumentation/otel/init-otel-server-node.ts`. Feature packages never instantiate or import it directly.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@opentelemetry/sdk-node` is the standard Node.js OTel SDK meta-package. No competing OTel SDK bootstrapper is present in the workspace.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@opentelemetry/sdk-node` is the SDK bootstrapper with no independent data transmission. All signals it routes pass through the configured exporters. EU residency is governed by the exporter DSN configuration.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@opentelemetry/sdk-node` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/otel/init-otel-server-node.ts` uses `NodeSDK` to bootstrap the full OTel pipeline: resource detection, context propagation, trace/log/metric providers, `SentrySpanProcessor`, `PiiScrubSpanProcessor`, and all auto-instrumentation plugins (ADR-017).
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
The former `initSentryServerNode` function which called Sentry SDK init methods directly. `NodeSDK` from `sdk-node` provides the unified bootstrapper that wires the complete OTel pipeline in a single `sdk.start()` call, replacing the need to manually construct and register each provider.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. `NodeSDK` is the single init entry point for the entire OTel server pipeline. Replacing it requires manually constructing and registering trace provider, log provider, metric provider, context manager, propagator, and all instrumentation plugins — essentially reimplementing what `NodeSDK` provides. The `ITracer`/`ILogger`/`IMetrics` boundaries (ADR-014/017) isolate feature code but the init layer itself is deeply coupled.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Manual SDK assembly** — Constructing `TracerProvider`, `LoggerProvider`, `MeterProvider` individually without `NodeSDK`. Rejected: high boilerplate; `NodeSDK` handles shutdown hooks, context manager registration, and propagator setup automatically.
|
||||
2. **`@opentelemetry/auto-instrumentations-node`** — A higher-level meta-package that bundles many plugins. Rejected: includes instrumentations the workspace doesn't need; ADR-017 §11 specifies exactly which plugins to enable (http, undici, pg) for minimal scope.
|
||||
|
||||
See ADR-017 for the full decision rationale.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@opentelemetry/sdk-trace-base"
|
||||
version: "^1.27.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-017
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @opentelemetry/sdk-trace-base license
|
||||
- npm view @opentelemetry/sdk-trace-base version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view @opentelemetry/sdk-trace-base license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@opentelemetry/sdk-trace-base` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the OpenTelemetry community on the stable 1.x track. The 1.27.x line is current; the tracing specification is stable within CNCF.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-017 §8 restricts `@opentelemetry/sdk-trace-base` to `**/instrumentation/otel/**` and app init paths. `SpanProcessor` and `ReadableSpan` types from this package are used to implement `PiiScrubSpanProcessor` in `core-shared`. `packages/core-audit` also uses `ReadableSpan` for span context in audit records.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@opentelemetry/sdk-trace-base` is the OTel trace SDK foundation. No competing trace SDK is present in the workspace.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@opentelemetry/sdk-trace-base` is the tracing SDK infrastructure with no independent data transmission. Spans are forwarded through configured processors and exporters. EU residency is governed by the exporter DSN configuration.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@opentelemetry/sdk-trace-base` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/otel/pii-scrub-span-processor.ts` implements `SpanProcessor` from `@opentelemetry/sdk-trace-base` to scrub PII attributes before spans reach the Sentry exporter (ADR-017 §7). `packages/core-audit` uses `ReadableSpan` for audit record correlation.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
The former `SentryTracer` which called Sentry SDK span methods directly. `@opentelemetry/sdk-trace-base` provides the `SpanProcessor` extension point that enables the `PiiScrubSpanProcessor` — a vendor-neutral, pre-export PII scrubbing layer.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. `@opentelemetry/sdk-trace-base` types (`SpanProcessor`, `ReadableSpan`) are used in both `core-shared` PII scrub implementation and `core-audit`. Replacing it means adopting a different span processing abstraction and rewriting both the processor and audit span-context integration.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Sentry `beforeSendTransaction` hook** — Sentry-native PII scrubbing hook. Rejected in ADR-017 §7: runs inside Sentry after OTel conversion; the OTel processor layer runs earlier and is vendor-agnostic, so any future exporter also sees clean data.
|
||||
2. **No span processor, rely on Sentry scrubbing rules** — Rejected: Sentry-specific configuration; future exporter additions would need their own scrubbing configured separately.
|
||||
|
||||
See ADR-017 for the full decision rationale.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@opentelemetry/semantic-conventions"
|
||||
version: "^1.27.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-017
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @opentelemetry/semantic-conventions license
|
||||
- npm view @opentelemetry/semantic-conventions version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view @opentelemetry/semantic-conventions license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@opentelemetry/semantic-conventions` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the OpenTelemetry community. The 1.27.x line is on the stable 1.x track. Semantic conventions are a CNCF specification that evolves across OTel SDK releases.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-017 §8 restricts `@opentelemetry/semantic-conventions` to `**/instrumentation/otel/**` and app init paths. Attribute name constants from this package are used in `core-shared/instrumentation/otel/` to label span attributes consistently (e.g., `SEMATTRS_DB_SYSTEM`, `SEMATTRS_HTTP_METHOD`). Feature packages never import it directly.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@opentelemetry/semantic-conventions` is the canonical OTel attribute name registry. No competing attribute-naming package is present in the workspace. Using this package prevents hard-coded string attribute names that diverge from the OTel spec.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@opentelemetry/semantic-conventions` is a pure constants package with no network communication or data transmission. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@opentelemetry/semantic-conventions` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/otel/` uses semantic convention constants to name span attributes on HTTP instrumentation config, pg instrumentation config, and custom spans. Consistent attribute naming enables Sentry and any future backend to parse spans correctly.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Hard-coded string attribute names (e.g., `"http.method"`, `"db.system"`) that would otherwise be scattered across instrumentation code without a canonical reference. Semantic conventions provide typed, versioned constants with IDE autocompletion and forwards-compatibility guarantees.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. `@opentelemetry/semantic-conventions` is a constants-only package. Removing it means replacing constant references with hard-coded strings in `core-shared` instrumentation code — a mechanical change with no behavioral impact.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Hard-coded string constants** — Define attribute names as local `const` values. Rejected: diverges from the OTel specification over time as attributes are renamed or deprecated; loses IDE-navigable documentation links.
|
||||
2. **No attribute naming standard** — Each developer picks attribute names ad-hoc. Rejected: breaks Sentry query grouping, dashboard filters, and any backend that relies on spec-compliant attribute names for parsing.
|
||||
|
||||
See ADR-017 for the full decision rationale.
|
||||
85
docs/library-decisions/2026-05-14-@payloadcms/db-postgres.md
Normal file
85
docs/library-decisions/2026-05-14-@payloadcms/db-postgres.md
Normal file
@@ -0,0 +1,85 @@
|
||||
---
|
||||
package: "@payloadcms/db-postgres"
|
||||
version: "^3.14.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: self-hostable
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @payloadcms/db-postgres license
|
||||
- npm view @payloadcms/db-postgres version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view @payloadcms/db-postgres license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@payloadcms/db-postgres` is part of the Payload CMS monorepo, authored in TypeScript, and ships its own `.d.ts` declaration files.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Maintained as part of the Payload CMS project. Versioned and released together with the `payload` core package; receives the same release cadence.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@payloadcms/db-postgres` is the PostgreSQL database adapter for Payload CMS, used exclusively in `@repo/core-cms` to configure the Payload instance. Feature packages do not reference this package directly. This is the correct placement for a CMS-layer infrastructure adapter.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@payloadcms/db-postgres` is the sole database adapter in the workspace. No competing Payload database adapter (MongoDB, SQLite, etc.) is present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: self-hostable -->
|
||||
|
||||
`@payloadcms/db-postgres` connects to a self-hosted PostgreSQL instance (configured via `DATABASE_URI`). No data is transmitted to Payload-controlled or third-party-controlled endpoints. EU residency is determined by the PostgreSQL host deployment environment.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@payloadcms/db-postgres` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@repo/core-cms` uses `@payloadcms/db-postgres` as the database adapter in the Payload configuration. Named, non-hypothetical consumer exists today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
`@payloadcms/db-postgres` replaces the need for a separate ORM (Prisma, Drizzle, etc.) alongside Payload — Payload's built-in adapter unifies the data access layer and admin UI schema in one package.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. The PostgreSQL adapter is tightly coupled to the Payload schema definitions in `core-cms`. Migrating to a different adapter (e.g., MongoDB) would require reshaping all collection definitions and potentially the database migration history. The Payload interface boundary limits exposure to `core-cms` only.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **`@payloadcms/db-mongodb`** — Not applicable for this deployment target; the infrastructure uses PostgreSQL (ADR-015 references the database stack).
|
||||
2. **Prisma + separate Payload adapter** — Rejected: Payload's integrated adapter eliminates the N+1 problem of maintaining two data access layers for the same database.
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
package: "@payloadcms/richtext-lexical"
|
||||
version: "^3.14.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @payloadcms/richtext-lexical license
|
||||
- npm view @payloadcms/richtext-lexical version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view @payloadcms/richtext-lexical license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@payloadcms/richtext-lexical` is part of the Payload CMS monorepo, authored in TypeScript, and ships its own `.d.ts` declaration files.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Maintained as part of the Payload CMS project. Versioned and released together with the `payload` core package; receives the same release cadence.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@payloadcms/richtext-lexical` is the rich-text field plugin for Payload CMS, used exclusively in `@repo/core-cms` to configure rich-text fields in Payload collections. Feature packages access rich-text content as plain data through repository interfaces. This is the correct placement for a CMS-layer content plugin.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@payloadcms/richtext-lexical` is the sole rich-text editor plugin in the workspace. The alternative Payload rich-text plugin (`@payloadcms/richtext-slate`) is not present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@payloadcms/richtext-lexical` is a server-side content plugin with no network communication to vendor-controlled endpoints. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@payloadcms/richtext-lexical` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@repo/core-cms` uses `@payloadcms/richtext-lexical` to define the rich-text editor for content fields in the blog and other content collections. Named, non-hypothetical consumer exists today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
`@payloadcms/richtext-lexical` replaces `@payloadcms/richtext-slate`, which was deprecated in Payload 3.x. Lexical is the recommended and actively maintained rich-text engine in the Payload 3.x ecosystem.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Moderate. Rich-text data stored via Lexical is serialized in Lexical's internal JSON format. Migrating to a different rich-text engine would require a data migration for all existing rich-text content. The plugin is confined to `core-cms`, limiting the surface area.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **`@payloadcms/richtext-slate`** — Deprecated in Payload 3.x; Lexical is the recommended successor.
|
||||
2. **Plain textarea fields** — Rejected: insufficient for content that requires formatting, links, and embedded media (blog articles, marketing pages).
|
||||
88
docs/library-decisions/2026-05-14-@sentry/nextjs.md
Normal file
88
docs/library-decisions/2026-05-14-@sentry/nextjs.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
package: "@sentry/nextjs"
|
||||
version: "^10.51.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-014
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: ok
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @sentry/nextjs license
|
||||
- npm view @sentry/nextjs version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view @sentry/nextjs license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@sentry/nextjs` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by Sentry Inc. The 10.x line sees regular releases tracking Next.js releases. Used by thousands of production Next.js apps; issue tracker shows prompt engagement.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-014 designates Sentry as the error-capture and tracing backend. The ESLint `no-restricted-imports` rule (ADR-014 §6) allowlists `@sentry/*` only within `core-shared/instrumentation/sentry/**`, the apps' `instrumentation*.{ts,mjs}` / `next.config.{mjs}` entry points, and the `core-testing/setup/no-sentry.ts` mock. Feature packages MUST NOT import `@sentry/*` directly — they consume only the vendor-neutral `ITracer`/`ILogger` interfaces.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@sentry/nextjs` is the sole Next.js error-monitoring SDK in the workspace. No competing APM or crash-reporter library (Datadog, New Relic, Rollbar, Bugsnag) is present or proposed.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: ok -->
|
||||
|
||||
Sentry offers EU-region data residency (hosted at `de.sentry.io`). The workspace's `WEB_NEXT_SENTRY_DSN` can point to an EU-hosted project; the SDK routes all payloads to the DSN host. PII scrubbing at the OTel processor layer (ADR-017, ADR-014 §4) ensures only scrubbed data leaves the process.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@sentry/nextjs` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/sentry/` holds the Sentry adapter pair (`SentryTracer`, `SentryLogger`). `apps/web-next/instrumentation.ts` and `apps/web-next/next.config.mjs` are the concrete Next.js-side consumers. Both are named, non-hypothetical consumers.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
No prior error monitoring or distributed tracing library was in place. `@sentry/nextjs` replaces ad-hoc `console.error` logging that provided no stack context, no distributed trace correlation, and no session replay for diagnosing reproduction steps.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Moderate. The interface boundary (ADR-014 §1) limits feature-package blast radius to zero — feature code never imports `@sentry/nextjs`. Removal would require swapping the `SentryTracer`/`SentryLogger` adapter pair in `core-shared/instrumentation/sentry/` for a new adapter, updating `apps/web-next/instrumentation.ts` and `next.config.mjs`, and dropping the `WEB_NEXT_SENTRY_DSN` env var. The scope is bounded and mechanical.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Datadog APM** — Stronger distributed tracing primitives, but higher cost, heavier SDK footprint, and no built-in session replay. Evaluated and deferred.
|
||||
2. **New Relic** — Enterprise-grade but requires a New Relic account and agent; no native Next.js SDK at the time of evaluation.
|
||||
3. **Direct OpenTelemetry export** — Deferred to ADR-017 for the OTel migration layer; Sentry remains the exporter via `@sentry/opentelemetry` bridge.
|
||||
|
||||
See ADR-014 for the full decision rationale.
|
||||
87
docs/library-decisions/2026-05-14-@sentry/node.md
Normal file
87
docs/library-decisions/2026-05-14-@sentry/node.md
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@sentry/node"
|
||||
version: "^10.51.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-014
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: ok
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @sentry/node license
|
||||
- npm view @sentry/node version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view @sentry/node license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@sentry/node` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by Sentry Inc. The 10.x line is the current major. Regular releases track Node.js LTS versions and fix security issues promptly.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-014 designates Sentry as the error-capture and tracing backend for Node.js server processes. `@sentry/node` is an optional peer dependency of `core-shared` — it is consumed exclusively within `core-shared/instrumentation/sentry/init-server-node.ts` and the CMS app's `instrumentation.ts`. Feature packages MUST NOT import `@sentry/node` directly (ESLint `no-restricted-imports`, ADR-014 §6).
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@sentry/node` is the sole Node.js server error-monitoring SDK in the workspace. No competing APM agent or crash reporter is present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: ok -->
|
||||
|
||||
Sentry offers EU-region data residency (`de.sentry.io`). The `CMS_SENTRY_DSN` environment variable can point to an EU-hosted project; all payloads route to the DSN host. PII scrubbing at the OTel processor layer (ADR-017, ADR-014 §4) ensures only scrubbed data is exported.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@sentry/node` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared` lists `@sentry/node` as an optional peer dependency. `apps/cms/src/instrumentation.ts` is the concrete consumer, initializing the Node SDK for the Payload CMS process. A named, non-hypothetical consumer exists today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
No prior server-side error monitoring was in place for the CMS process. `@sentry/node` replaces unstructured `console.error` calls that left CMS mutation failures undetected in production.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. `@sentry/node` is used only in `core-shared/instrumentation/sentry/init-server-node.ts` and the CMS app's `instrumentation.ts`. The interface boundary (ADR-014 §1) means no feature package references it. Replacement requires swapping the initialization file and updating the `CMS_SENTRY_DSN` env var.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **`@sentry/nextjs` for CMS** — Rejected: the Payload CMS process is a plain Node server, not a Next.js app. `@sentry/node` is the correct SDK for non-Next processes.
|
||||
2. **OpenTelemetry OTLP exporter only** — Considered but deferred; Sentry's session grouping and alert routing add value beyond raw OTLP. The bridge via `@sentry/opentelemetry` preserves OTel portability.
|
||||
|
||||
See ADR-014 for the full decision rationale.
|
||||
87
docs/library-decisions/2026-05-14-@sentry/opentelemetry.md
Normal file
87
docs/library-decisions/2026-05-14-@sentry/opentelemetry.md
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
package: "@sentry/opentelemetry"
|
||||
version: "^10.51.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-014
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: ok
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @sentry/opentelemetry license
|
||||
- npm view @sentry/opentelemetry version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view @sentry/opentelemetry license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@sentry/opentelemetry` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by Sentry Inc. as the official bridge between the Sentry SDK and the OpenTelemetry SDK. Versions track the `@sentry/*` SDK family; the 10.x line is current.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-014 designates Sentry as the error-capture backend, and ADR-017 mandates OpenTelemetry as the instrumentation substrate. `@sentry/opentelemetry` is the bridge that wires Sentry as an OTel exporter — it belongs exclusively in `core-shared/instrumentation/sentry/` alongside the adapter pair. Feature packages MUST NOT import it directly (ESLint `no-restricted-imports`, ADR-014 §6).
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@sentry/opentelemetry` is the only OTel-to-Sentry bridge in the workspace. No competing exporter bridge (e.g., manual `@opentelemetry/exporter-*` wired to Sentry) is present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: ok -->
|
||||
|
||||
`@sentry/opentelemetry` is a pure instrumentation adapter with no independent data transmission. All spans and log records it emits are forwarded through the Sentry SDK, which routes to the DSN host (EU-hosted if configured). EU residency is governed by the DSN setting, not this package.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@sentry/opentelemetry` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared/src/instrumentation/sentry/` is the sole consumer. It registers `@sentry/opentelemetry`'s `SentrySpanProcessor` and `SentryPropagator` during OTel SDK initialization so that all OTel spans are also captured as Sentry transactions.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Prior to ADR-017, the workspace had no OTel substrate. `@sentry/opentelemetry` replaces the need to configure two independent pipelines (a direct Sentry SDK pipeline and a raw OTel SDK pipeline) by letting a single OTel pipeline export to Sentry via the bridge.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. `@sentry/opentelemetry` is used in one file in `core-shared/instrumentation/sentry/`. Replacing Sentry as the exporter means swapping this bridge for a different `SpanExporter` in that single file. The OTel substrate (ADR-017) remains untouched.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Direct Sentry SDK without OTel bridge** — Rejected in ADR-017: coupling feature packages to `@sentry/*` APIs directly would violate vendor isolation. The OTel-first approach keeps instrumentation portable.
|
||||
2. **`@opentelemetry/exporter-zipkin` / Jaeger** — Open-source trace backends considered but lack Sentry's session replay, error deduplication, and release tracking. Sentry via bridge offers a superset.
|
||||
|
||||
See ADR-014 and ADR-017 for the full decision rationale.
|
||||
88
docs/library-decisions/2026-05-14-@sentry/react.md
Normal file
88
docs/library-decisions/2026-05-14-@sentry/react.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
package: "@sentry/react"
|
||||
version: "^10.51.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-014
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: ok
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @sentry/react license
|
||||
- npm view @sentry/react version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view @sentry/react license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@sentry/react` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by Sentry Inc. The 10.x line is current. Regular releases track React minor versions and address browser compatibility issues.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-014 designates Sentry as the error-capture and session-replay backend for browser clients. `@sentry/react` is consumed exclusively in `core-shared/instrumentation/sentry/init-client-react.ts` and the web apps' client-side `instrumentation-client.ts` entry points. Feature packages MUST NOT import `@sentry/react` directly (ESLint `no-restricted-imports`, ADR-014 §6).
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@sentry/react` is the sole React browser error-monitoring SDK in the workspace. No competing session-replay or crash-reporter library is present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: ok -->
|
||||
|
||||
Sentry offers EU-region data residency (`de.sentry.io`). The `NEXT_PUBLIC_WEB_NEXT_SENTRY_DSN` environment variable can point to an EU-hosted project. Session replay default-masks all text/inputs/media (allowlist empty by default, ADR-014 §4 R34) and `setUser` accepts only `{ id }`, minimising PII exposure at source.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@sentry/react` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`packages/core-shared` lists `@sentry/react` as an optional peer dependency. `apps/web-next/src/instrumentation-client.ts` is the concrete consumer, initializing the React SDK with session replay for the Next.js browser bundle. A named, non-hypothetical consumer exists today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
No prior browser error monitoring or session replay was in place. `@sentry/react` replaces unstructured `window.onerror` / uncaught promise rejections that surfaced only in browser dev-tools — invisible to the engineering team in production.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. `@sentry/react` is initialized in one file per app (`instrumentation-client.ts`). The vendor-neutral `ITracer`/`ILogger` interfaces (ADR-014 §1) ensure feature packages have zero references to it. Removal means replacing the client initialization file and dropping the browser DSN env var.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **`@sentry/nextjs` on the client** — `@sentry/nextjs` wraps `@sentry/react` for Next.js server-side use. For browser-only client initialization, `@sentry/react` is the more targeted SDK with a smaller bundle size.
|
||||
2. **LogRocket / FullStory for replay** — Separate replay vendors would add a second SDK with its own PII risk surface. Sentry's built-in replay with default-masking satisfies the requirement with one SDK.
|
||||
3. **No session replay** — Insufficient for diagnosing hard-to-reproduce user-facing bugs. Replay is opt-in per error event (deferred load), so the cost is bounded to errored sessions.
|
||||
|
||||
See ADR-014 for the full decision rationale.
|
||||
85
docs/library-decisions/2026-05-14-@tanstack/react-query.md
Normal file
85
docs/library-decisions/2026-05-14-@tanstack/react-query.md
Normal file
@@ -0,0 +1,85 @@
|
||||
---
|
||||
package: "@tanstack/react-query"
|
||||
version: "^5.59.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @tanstack/react-query license
|
||||
- npm view @tanstack/react-query version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view @tanstack/react-query license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@tanstack/react-query` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the TanStack team. The 5.x line is the current stable major. Regular releases; strong community adoption alongside tRPC.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@tanstack/react-query` is listed as a runtime dependency of `@repo/core-testing` to provide the `QueryClient` and `QueryClientProvider` needed when rendering components that use TanStack Query hooks in tests. The production apps consume it through their framework layer. No boundary rule restricts React Query to a specific tier.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@tanstack/react-query` is the sole server-state management library in the workspace. No competing library (SWR, Apollo Client, RTK Query, etc.) is present for the same purpose.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@tanstack/react-query` is a pure client-side state management library with no network communication to vendor-controlled endpoints. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@tanstack/react-query` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@repo/core-testing` uses `@tanstack/react-query` to set up `QueryClient` wrappers for component tests. The Next.js app uses TanStack Query for client-side data fetching with tRPC. Named, non-hypothetical consumers exist today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
`@tanstack/react-query` replaces manual `useEffect` + `useState` patterns for server-state caching, deduplication, and background refetching. It is the standard companion to tRPC's React adapter.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. TanStack Query's `useQuery` / `useMutation` hooks are used in feature UI components across the Next.js app. The cache key structure (`trpc.*` query keys) is tightly coupled to tRPC's query key format. Migrating out requires replacing all data-fetching hooks and the cache invalidation strategy.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **SWR** — Similar feature set but less integration with tRPC's query key format; TanStack Query's devtools and cache invalidation API are more expressive.
|
||||
2. **Apollo Client** — GraphQL-centric; incompatible with tRPC's RPC model.
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
package: "@testing-library/jest-dom"
|
||||
version: "^6.5.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @testing-library/jest-dom license
|
||||
- npm view @testing-library/jest-dom version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view @testing-library/jest-dom license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@testing-library/jest-dom` ships its own TypeScript declaration files that extend the vitest/jest `expect` matchers. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the Testing Library organization. The 6.x line is the current major. Regular releases tracking vitest and jest compatibility.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@testing-library/jest-dom` is a dependency of `@repo/core-testing`, which is the workspace's shared testing infrastructure package. Custom DOM matchers (`toBeInTheDocument`, `toHaveTextContent`, etc.) are set up in `core-testing`'s setup file and available to all feature test suites via the `core-testing` dependency. This is the correct placement.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@testing-library/jest-dom` is the sole custom DOM matcher extension in the workspace. No competing matcher library is present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@testing-library/jest-dom` is a test utility library with no network communication. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@testing-library/jest-dom` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@repo/core-testing` uses `@testing-library/jest-dom` to set up custom DOM assertion matchers. Feature packages that render React components in tests use these matchers via `core-testing`. Named, non-hypothetical consumer exists today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
`@testing-library/jest-dom` extends vitest's `expect` with semantic DOM matchers, replacing brittle assertion patterns like `expect(el.innerHTML).toContain('text')` with `expect(el).toHaveTextContent('text')`.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. `@testing-library/jest-dom` is configured in one setup file in `@repo/core-testing`. Removing it requires updating that setup and replacing any DOM-specific matchers in test files with lower-level assertions.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Plain vitest `expect` matchers only** — Viable but produces less readable test assertions for DOM state; `toBeInTheDocument()` is significantly clearer than checking element existence manually.
|
||||
2. **`@vitest/ui` accessibility assertions** — Narrower scope; `@testing-library/jest-dom` covers the full semantic DOM assertion surface.
|
||||
85
docs/library-decisions/2026-05-14-@testing-library/react.md
Normal file
85
docs/library-decisions/2026-05-14-@testing-library/react.md
Normal file
@@ -0,0 +1,85 @@
|
||||
---
|
||||
package: "@testing-library/react"
|
||||
version: "^16.0.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @testing-library/react license
|
||||
- npm view @testing-library/react version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view @testing-library/react license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@testing-library/react` ships its own TypeScript declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the Testing Library organization. The 16.x line targets React 19. Regular releases; strong community and ecosystem adoption.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@testing-library/react` is a dependency of `@repo/core-testing`, the workspace's shared testing infrastructure. It provides `render`, `screen`, `fireEvent`, and related utilities for component tests. Feature packages that test UI components use these utilities via `core-testing`. This is the correct placement for shared test infrastructure.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@testing-library/react` is the sole React component testing utility in the workspace. No competing library (Enzyme, React Test Renderer) is present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@testing-library/react` is a test utility library with no network communication. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@testing-library/react` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@repo/core-testing` uses `@testing-library/react` to provide the `render` utility and `screen` query API for component tests. Feature packages with UI components use these via `core-testing`. Named, non-hypothetical consumer exists today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
`@testing-library/react` replaces Enzyme and React Test Renderer. Testing Library's philosophy of testing from the user's perspective (querying by role, label, text) produces more resilient tests than implementation-detail-aware approaches.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. `render`, `screen`, `fireEvent`, and `userEvent` APIs from Testing Library are used in all component tests. Migrating to a different testing approach requires rewriting all component tests and changing the query strategy (from accessibility-tree queries to DOM selectors or component internals).
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Enzyme** — Deprecated and no longer maintained for React 18+; Testing Library is the ecosystem standard.
|
||||
2. **`react-dom/test-utils`** — Lower-level API without the accessibility-query helpers; more verbose and less idiomatic for testing user behavior.
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
package: "@testing-library/user-event"
|
||||
version: "^14.5.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @testing-library/user-event license
|
||||
- npm view @testing-library/user-event version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view @testing-library/user-event license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@testing-library/user-event` ships its own TypeScript declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the Testing Library organization. The 14.x line is the current major. Regular releases.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@testing-library/user-event` is a dependency of `@repo/core-testing`, the workspace's shared testing infrastructure. It provides realistic user interaction simulation (`userEvent.click`, `userEvent.type`, etc.) that more accurately models browser behavior than `fireEvent`. This is the correct placement for shared test infrastructure.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@testing-library/user-event` is the sole user interaction simulation library in the workspace. No competing library is present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@testing-library/user-event` is a test utility library with no network communication. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@testing-library/user-event` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@repo/core-testing` uses `@testing-library/user-event` to provide realistic interaction utilities for component tests. Feature packages with interactive UI components use these via `core-testing`. Named, non-hypothetical consumer exists today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
`@testing-library/user-event` replaces `@testing-library/dom`'s `fireEvent` for interaction tests. `userEvent` simulates the full browser event sequence (pointerdown → mousedown → focus → click → pointerup → mouseup) rather than dispatching a single synthetic event, producing more faithful integration tests.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. `@testing-library/user-event` is used in component tests alongside `@testing-library/react`. Removing it requires downgrading interaction tests to `fireEvent` calls — a mechanical change but a loss of test fidelity.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **`fireEvent` only** — Simpler but fires only one synthetic event per interaction; misses focus/blur and keyboard event sequences that real browsers emit.
|
||||
2. **Playwright component testing** — Full browser testing is reserved for e2e (`pnpm test:e2e`); `userEvent` is the right tool for unit/integration component tests.
|
||||
85
docs/library-decisions/2026-05-14-@trpc/client.md
Normal file
85
docs/library-decisions/2026-05-14-@trpc/client.md
Normal file
@@ -0,0 +1,85 @@
|
||||
---
|
||||
package: "@trpc/client"
|
||||
version: "^11.0.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @trpc/client license
|
||||
- npm view @trpc/client version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view @trpc/client license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@trpc/client` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained alongside `@trpc/server` by the tRPC team. Versioned and released together with the server package.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@trpc/client` is used in `@repo/core-testing` to provide a mock tRPC client for test setups. This is the correct tier for test infrastructure utilities. No boundary rule restricts `@trpc/client` usage here.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@trpc/client` is the sole tRPC client implementation in the workspace. No competing client adapter is present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@trpc/client` is a pure client-side RPC library with no vendor-controlled network endpoints. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@trpc/client` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@repo/core-testing` uses `@trpc/client` to build the mock tRPC client used in integration test setups. Named, non-hypothetical consumer exists today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
`@trpc/client` is the natural companion to `@trpc/server`; no alternative client approach was evaluated separately. Using `@trpc/client` ensures the test setup mirrors the production client configuration.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. `@trpc/client` is confined to `@repo/core-testing`'s test utilities. Migrating out requires updating the mock client setup in one package. Feature packages reference tRPC types from `@trpc/server`, not `@trpc/client`.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Direct HTTP fetch in tests** — Rejected: bypasses tRPC middleware and type inference, making tests less representative of real client behavior.
|
||||
2. **`@trpc/server` `createCaller` (server-side calling)** — Valid alternative for pure unit tests; `@trpc/client` is used where the test needs to exercise the actual HTTP transport or client link chain.
|
||||
69
docs/library-decisions/2026-05-14-@trpc/react-query.md
Normal file
69
docs/library-decisions/2026-05-14-@trpc/react-query.md
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
package: "@trpc/react-query"
|
||||
version: "^11.0.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [scaffolded]
|
||||
adr: null
|
||||
is-sub-processor: false
|
||||
processes-pii: false
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: skip
|
||||
verification-commands:
|
||||
- pnpm audit --audit-level=moderate
|
||||
- npm view @trpc/react-query license
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
MIT — on the workspace allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
Ships first-party TypeScript types; deeply integrated with tRPC's type inference.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
Active. Maintained by the tRPC team alongside `@trpc/server` and `@trpc/client`.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
Core package. The React Query integration bridge belongs in `core-trpc` alongside its sibling tRPC packages. No boundary rule violation.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
No other tRPC–React Query bridge in the workspace. No shadow.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
Client-side integration adapter; no vendor data transmission. n/a.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
No advisories at adoption time.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
`core-trpc` re-exports `@trpc/react-query` hooks for use in Next.js feature pages.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Nothing — this is the initial tRPC scaffold.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard: hooks are tRPC-procedure-typed; migrating away requires replacing all call sites.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
This package is the canonical integration point between `@trpc/client` and `@tanstack/react-query`. No viable alternative exists.
|
||||
86
docs/library-decisions/2026-05-14-@trpc/server.md
Normal file
86
docs/library-decisions/2026-05-14-@trpc/server.md
Normal file
@@ -0,0 +1,86 @@
|
||||
---
|
||||
package: "@trpc/server"
|
||||
version: "^11.0.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view @trpc/server license
|
||||
- npm view @trpc/server version
|
||||
- pnpm audit --audit-level=moderate
|
||||
lastRevalidated: 2026-05-19
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view @trpc/server license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`@trpc/server` is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the tRPC team. The 11.x line is the current major. Regular releases; strong community adoption in the Next.js ecosystem.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@trpc/server` is the workspace-standard RPC layer for type-safe client-server communication (ADR-019 references tRPC as the transport for use-case exposure). Feature packages export their tRPC routers; `core-api` aggregates them; apps mount the root router. Feature packages own their error middleware (`integrations/api/procedures.ts`). No boundary rule restricts `@trpc/server` to a specific tier.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@trpc/server` is the sole RPC framework in the workspace. No competing API layer (REST, GraphQL, gRPC) is present for the same purpose.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`@trpc/server` is a pure server-side routing library with no network communication to vendor-controlled endpoints. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `@trpc/server` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
All five feature packages export a tRPC router that uses `@trpc/server`. `@repo/core-api` aggregates these routers. `@repo/core-shared` provides the tRPC base instance and error middleware utilities. `@repo/core-dsr` exposes the `dsrRouter` via `createDsrRouter`. Named, non-hypothetical consumers exist today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
`@trpc/server` replaces a hypothetical hand-written REST API layer. tRPC enables end-to-end type safety between the server use cases and the Next.js client without a separate OpenAPI spec or code generation step.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. tRPC router types propagate from the server to the client via TypeScript inference. Every feature package's tRPC router, the root `AppRouter` type in `core-api`, and every client-side query in the apps reference `@trpc/server` types. Migrating to REST would require replacing all router definitions, regenerating types (e.g., via OpenAPI), and updating all client call sites.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **GraphQL (Apollo/Pothos)** — More complex schema layer required; the resolver pattern does not map cleanly onto the factory-function use-case pattern mandated by CLAUDE.md.
|
||||
2. **OpenAPI + Zodios** — Requires a separate schema definition step and code generation; tRPC's type inference is more direct for a monorepo where client and server share the same TypeScript project.
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
package: "@trpc/tanstack-react-query"
|
||||
version: "^11.1.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [scaffolded]
|
||||
adr: null
|
||||
is-sub-processor: false
|
||||
processes-pii: false
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: skip
|
||||
verification-commands:
|
||||
- pnpm audit --audit-level=moderate
|
||||
- npm view @trpc/tanstack-react-query license
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
MIT — on the workspace allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
Ships first-party TypeScript types; part of the tRPC v11 adapter suite.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
Active. Maintained by the tRPC team as part of the v11 TanStack Start integration.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
Core package. Required for the TanStack Start provider (`core-trpc/tanstack`). No boundary rule violation.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
No duplicate TanStack adapter in the workspace. No shadow.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
Client-side integration adapter; no vendor data transmission. n/a.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
No advisories at adoption time.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
`core-trpc` exposes a TanStack Start provider via `@trpc/tanstack-react-query` for `apps/web-tanstack`.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Nothing — this is the initial tRPC scaffold.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard: the TanStack provider is shaped around this adapter's API; replacing requires re-implementing the provider.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
This is the official tRPC adapter for TanStack Start. No viable alternative exists.
|
||||
69
docs/library-decisions/2026-05-14-clsx.md
Normal file
69
docs/library-decisions/2026-05-14-clsx.md
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
package: clsx
|
||||
version: "^2.1.1"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [scaffolded]
|
||||
adr: null
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- pnpm audit --audit-level=moderate
|
||||
- npm view clsx license
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
MIT — on the workspace allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
Ships first-party TypeScript types in its distribution.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
Active. Maintained by Luke Edwards; stable, minimal API.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
Core UI package. `clsx` is a utility for constructing `className` strings; appropriate for `core-ui`. No boundary rule violation.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
No competing className utility in the workspace. No shadow.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
Pure compute; no network calls or vendor data transmission. n/a.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
No advisories at adoption time.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
`core-ui` uses `clsx` in the `cn()` utility (combined with `tailwind-merge`) for conditional class composition.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Nothing — this is the initial UI scaffold.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Mechanical: replace `clsx()` calls with template literals or equivalent. Minimal API surface.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **classnames** — the older predecessor; `clsx` is smaller and faster.
|
||||
2. **Template literals** — verbose; no conditional logic support.
|
||||
`clsx` is the de-facto standard lightweight className utility.
|
||||
88
docs/library-decisions/2026-05-14-globals.md
Normal file
88
docs/library-decisions/2026-05-14-globals.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
package: globals
|
||||
version: "^17.6.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
lastRevalidated: null
|
||||
is-sub-processor: false
|
||||
processes-pii: false
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view globals license
|
||||
- npm view globals version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view globals license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`globals` ships its own TypeScript declaration files. No separate `@types/globals` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Maintained by the Sindre Sorhus ecosystem. Regularly updated to track ECMAScript specification changes and new browser/Node.js globals. Last release < 18 months.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`globals` is a dependency of `@repo/core-eslint`, the shared ESLint configuration package. It provides the global variable definitions consumed by ESLint's `languageOptions.globals` configuration. This is the correct placement for a configuration-layer utility.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`globals` is the de-facto standard globals catalog for ESLint configurations. No competing globals package is present in the workspace.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`globals` is a static data package (JSON + TypeScript types) with no network communication. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `globals` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@repo/core-eslint` uses `globals` in its ESLint flat-config exports to declare browser and Node.js global environments. Named, non-hypothetical consumer exists today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
`globals` replaces the deprecated `env` configuration approach in ESLint's legacy config format. In the flat config system, `languageOptions.globals` with the `globals` package is the recommended approach.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Mechanical. `globals` is used in one configuration file (`@repo/core-eslint`). Migrating to a different globals source requires updating that file only.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Inline global declarations** — Verbose and maintenance-heavy; the `globals` package is the ESLint ecosystem standard for this purpose.
|
||||
2. **`@types/node` globals only** — Insufficient for browser environments; `globals` covers both environments cleanly.
|
||||
90
docs/library-decisions/2026-05-14-inversify.md
Normal file
90
docs/library-decisions/2026-05-14-inversify.md
Normal file
@@ -0,0 +1,90 @@
|
||||
---
|
||||
package: inversify
|
||||
version: "^6.2.0"
|
||||
tier: feature
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-002
|
||||
lastRevalidated: null
|
||||
is-sub-processor: false
|
||||
processes-pii: false
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view inversify license
|
||||
- npm view inversify version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view inversify license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
inversify is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/inversify` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained; the 6.x line has seen recent releases addressing TypeScript compatibility improvements. Last release < 18 months, issue tracker shows ongoing engagement.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
ADR-002 explicitly mandates InversifyJS as the DI framework for all feature packages. The ESLint boundary rules (ADR-010) do not restrict inversify to any specific path — feature packages are the declared consumers.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
inversify is the workspace-locked DI container per ADR-002. No parallel DI framework (tsyringe, awilix, etc.) is present or proposed.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
inversify is a pure runtime library with no network communication, telemetry, or data transmission. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against inversify at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
All five feature packages — `@repo/auth`, `@repo/blog`, `@repo/media`, `@repo/marketing-pages`, `@repo/navigation` — depend on inversify for their per-feature DI containers (ADR-008). Concrete named consumers exist today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Manual composition root patterns considered during initial architecture setup. InversifyJS replaces ad-hoc factory chaining that would not scale beyond three or four services per feature. No parallel approach is running.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. InversifyJS container bindings, symbols, and decorator usage are scattered across every feature package's `di/` layer. Migrating out would require replacing all `@injectable()` / `@inject()` decorators, SYMBOLS definitions, and container bind calls across five feature packages simultaneously. The interface boundaries (ADR-002) reduce the surface, but the volume of changes is substantial. The per-feature container pattern (ADR-008) limits blast radius to one package at a time.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **tsyringe** (Microsoft) — lighter API but fewer lifecycle options and weaker TypeScript inference at the time of evaluation.
|
||||
2. **Manual composition root** — zero dependency but does not scale past ~5 services without significant boilerplate and loses automatic dependency chain resolution.
|
||||
|
||||
See ADR-002 for the full decision rationale.
|
||||
88
docs/library-decisions/2026-05-14-payload.md
Normal file
88
docs/library-decisions/2026-05-14-payload.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
package: payload
|
||||
version: "^3.14.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
lastRevalidated: null
|
||||
is-sub-processor: false
|
||||
processes-pii: true
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: self-hostable
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view payload license
|
||||
- npm view payload version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view payload license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
Payload CMS is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/payload` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the Payload CMS team. The 3.x line is the current major and receives regular releases. Last release < 18 months, active issue tracker.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
Payload CMS is the workspace CMS and repository backend. Feature packages (`@repo/auth`, `@repo/blog`, etc.) use Payload as the data layer via the repository pattern (ADR-002). `core-cms` and `core-shared` use Payload directly. ESLint boundary rules restrict direct Payload queries to repository implementations only — feature packages MUST NOT call `payload.*` outside their repository files.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
Payload is the sole CMS and ORM-like data layer in the workspace. No competing headless CMS or database abstraction (Strapi, Sanity, Prisma, etc.) is present or proposed.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: self-hostable -->
|
||||
|
||||
Payload CMS is a fully self-hosted solution. No data is transmitted to Payload-controlled endpoints at runtime. EU residency is inherent; the deployment environment controls data location.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `payload` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
All five feature packages (`@repo/auth`, `@repo/blog`, `@repo/media`, `@repo/marketing-pages`, `@repo/navigation`) use Payload for repository access. `@repo/core-cms` configures the Payload instance. `@repo/core-shared` receives Payload config at constructor time. `@repo/core-dsr` uses Payload for GDPR DSR operations (data export, deletion, rectification, processing restriction). Named, non-hypothetical consumers exist today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Payload CMS replaces hand-rolled REST API + ORM patterns that would require maintaining a separate data layer, schema migrations, and admin UI from scratch. No parallel CMS is running.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. Payload is the data store for all content (articles, users, media, navigation). Migrating out requires replacing every repository implementation across five feature packages, the CMS configuration in `core-cms`, the admin UI, and all database schema definitions. The repository interface boundary (ADR-002) limits the feature-layer surface to repository implementations only, reducing blast radius, but the volume and data-format dependencies make migration substantial.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Strapi** — Evaluated but rejected; weaker TypeScript support at the time and less flexible content modeling for mixed structured + rich-text content.
|
||||
2. **Sanity** — SaaS-first model raises EU residency concerns without a self-hosted plan; Payload's self-hosted model is a better fit for the compliance profile.
|
||||
88
docs/library-decisions/2026-05-14-react-dom.md
Normal file
88
docs/library-decisions/2026-05-14-react-dom.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
package: react-dom
|
||||
version: "^19.0.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
lastRevalidated: null
|
||||
is-sub-processor: false
|
||||
processes-pii: false
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view react-dom license
|
||||
- npm view react-dom version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view react-dom license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
`react-dom` ships its own TypeScript declaration files in React 19. No separate `@types/react-dom` package is required at runtime.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by Meta alongside `react`. Versioned and released together with the React core package.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`react-dom` is a dependency of `@repo/core-testing` to enable DOM-based React component rendering via `@testing-library/react`. No boundary rule restricts `react-dom` usage in the testing tier.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`react-dom` is the sole React DOM renderer in the workspace. No competing renderer (react-native, react-three-fiber, etc.) targets the same DOM environment.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`react-dom` is a pure runtime library for DOM rendering with no network communication. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `react-dom` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@repo/core-testing` uses `react-dom` as a peer dependency for `@testing-library/react` DOM rendering. Named, non-hypothetical consumer exists today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
`react-dom` is the mandatory companion to `react` for web rendering; no alternative was evaluated separately.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Impossible. `react-dom` is the DOM rendering layer for all React components in the workspace. Replacing it would require migrating to a different renderer or framework simultaneously with React.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **`react-dom/server` only** — Insufficient: the testing layer requires the full DOM renderer for `@testing-library/react`.
|
||||
2. **No alternatives applicable** — `react-dom` is the only DOM renderer for React; the choice is inherent to the React framework selection.
|
||||
88
docs/library-decisions/2026-05-14-react.md
Normal file
88
docs/library-decisions/2026-05-14-react.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
package: react
|
||||
version: "^19.0.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
lastRevalidated: null
|
||||
is-sub-processor: false
|
||||
processes-pii: false
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view react license
|
||||
- npm view react version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view react license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
React 19 ships its own TypeScript declaration files bundled in the package. No separate `@types/react` package is required at runtime (though `@types/react` is still used as a devDependency for type-checking in some packages).
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by Meta. React 19 is the current stable major release. Long-term support commitment from Meta; used in production by millions of applications.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`react` is a dependency of `@repo/core-testing` to support React component rendering in test environments via `@testing-library/react`. The Next.js and TanStack Start apps consume React through their framework packages. No boundary rule restricts React usage in the testing tier.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
React is the sole UI rendering library in the workspace. No competing component library (Vue, Svelte, Solid, etc.) is present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`react` is a pure runtime library for UI rendering with no network communication to vendor-controlled endpoints. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `react` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@repo/core-testing` uses `react` as a peer for `@testing-library/react`. The Next.js and TanStack Start apps consume React through their framework layers. Named, non-hypothetical consumers exist today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
React replaces no prior UI framework — it is the founding choice for the web layer of this monorepo.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Impossible. React's component model and JSX syntax are used throughout both frontend apps and the testing layer. Replacing React would require rewriting all UI components, routing layers, and testing utilities across two apps.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Vue** — Different component model; incompatible with the Next.js and tRPC ecosystem choices made at project inception.
|
||||
2. **Solid** — Excellent performance characteristics but smaller ecosystem; Next.js and the established tRPC/React Query integration made React the pragmatic choice.
|
||||
88
docs/library-decisions/2026-05-14-reflect-metadata.md
Normal file
88
docs/library-decisions/2026-05-14-reflect-metadata.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
package: reflect-metadata
|
||||
version: "^0.2.2"
|
||||
tier: feature
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: adr-002
|
||||
lastRevalidated: null
|
||||
is-sub-processor: false
|
||||
processes-pii: false
|
||||
filter-results:
|
||||
license: Apache-2.0
|
||||
types: native
|
||||
maintenance: dormant
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view reflect-metadata license
|
||||
- npm view reflect-metadata version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: Apache-2.0 -->
|
||||
|
||||
`npm view reflect-metadata license` returns `Apache-2.0`. Apache-2.0 is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
reflect-metadata ships its own `.d.ts` declaration files. Types are bundled with the package.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: dormant -->
|
||||
|
||||
reflect-metadata implements the TC39 Metadata Reflection API proposal polyfill. The library is intentionally stable; new releases are rare because the spec is frozen pending TC39 progress. `dormant` is the accurate classification for a finished polyfill — this is not a concern for a library at this maturity level.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
reflect-metadata is a required peer of InversifyJS (ADR-002). Feature packages importing inversify are expected to also import `reflect-metadata` once at the entry point of each feature's DI layer. No boundary rule restricts it.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
reflect-metadata is the only metadata polyfill in the workspace. It is explicitly paired with inversify per ADR-002 and has no competing alternative present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
reflect-metadata is a pure runtime polyfill with no network communication, telemetry, or data transmission. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against reflect-metadata at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
All five feature packages — `@repo/auth`, `@repo/blog`, `@repo/media`, `@repo/marketing-pages`, `@repo/navigation` — list reflect-metadata as a runtime dependency. It is imported at each feature's DI entry point to activate the metadata polyfill required by inversify decorators.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
No prior metadata polyfill was in use. reflect-metadata is a direct requirement of InversifyJS's decorator-based binding — there is no alternative polyfill to retire.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Mechanical, but coupled to inversify removal. If InversifyJS is ever replaced with a DI approach that does not rely on the Reflect API (e.g., a factory-only approach), reflect-metadata can be removed by deleting one import per feature entry point. The removal is straightforward once the parent dependency (inversify) is gone.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **No polyfill / TC39 native** — The TC39 Metadata Reflection API is not yet at Stage 4; native support is not available in target runtimes. Not viable.
|
||||
2. **`core-js` reflect subset** — Does not provide the complete `Reflect.metadata` API surface required by inversify. Not a functional alternative.
|
||||
88
docs/library-decisions/2026-05-14-superjson.md
Normal file
88
docs/library-decisions/2026-05-14-superjson.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
package: superjson
|
||||
version: "^2.2.1"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
lastRevalidated: null
|
||||
is-sub-processor: false
|
||||
processes-pii: false
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view superjson license
|
||||
- npm view superjson version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view superjson license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
superjson is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/superjson` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained. Last release < 18 months. Used widely in the tRPC and Next.js ecosystem.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
superjson is the serialization transformer used by the tRPC layer (`@repo/core-shared`) to handle non-JSON-serializable types (Dates, Maps, Sets) over the wire. `core-testing` uses it for mock tRPC client setup. No boundary rules restrict superjson to a specific tier.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
superjson is the sole tRPC-compatible serialization transformer in the workspace. No competing serializer (devalue, msgpackr, etc.) is present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
superjson is a pure serialization library with no network communication, telemetry, or data transmission. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `superjson` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@repo/core-shared` uses superjson as the tRPC transformer. `@repo/core-testing` uses superjson for mock tRPC client configuration. Named, non-hypothetical consumers exist today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
superjson replaces the default JSON-only serialization in tRPC, which would fail silently when Date objects or other non-JSON types are passed through procedure calls.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Low. superjson is used as the `transformer` option in the tRPC router and client configuration — two call sites in `core-shared`. Replacing it requires swapping the transformer and ensuring the replacement handles the same non-JSON types. No feature package references superjson directly.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **devalue** — Supports more types but is less mature in the tRPC ecosystem; superjson is the de-facto tRPC transformer standard.
|
||||
2. **JSON-only (no transformer)** — Rejected because it silently loses type fidelity for Dates and breaks any use case that returns or receives a `Date` value.
|
||||
69
docs/library-decisions/2026-05-14-tailwind-merge.md
Normal file
69
docs/library-decisions/2026-05-14-tailwind-merge.md
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
package: tailwind-merge
|
||||
version: "^3.0.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [scaffolded]
|
||||
adr: null
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- pnpm audit --audit-level=moderate
|
||||
- npm view tailwind-merge license
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
MIT — on the workspace allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
Ships first-party TypeScript types in its distribution.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
Active. Maintained by dcastil; v3 is the current stable major.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
Core UI package. `tailwind-merge` deduplicates conflicting Tailwind classes; appropriate for `core-ui`. No boundary rule violation.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
No competing Tailwind class-merging utility in the workspace. No shadow.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
Pure compute; no network calls or vendor data transmission. n/a.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
No advisories at adoption time.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
`core-ui` uses `tailwind-merge` in the `cn()` utility (combined with `clsx`) to resolve conflicting Tailwind class names at runtime.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Nothing — this is the initial UI scaffold.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Mechanical: replace `twMerge()` calls in the `cn()` utility; update any call sites. Narrow API surface.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Custom deduplication** — error-prone; Tailwind has hundreds of class groups that change each version.
|
||||
2. **tw-join** — does not merge conflicts; only concatenates.
|
||||
`tailwind-merge` is the de-facto standard for conflict-free Tailwind class composition.
|
||||
88
docs/library-decisions/2026-05-14-vitest.md
Normal file
88
docs/library-decisions/2026-05-14-vitest.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
package: vitest
|
||||
version: "^3.0.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
lastRevalidated: null
|
||||
is-sub-processor: false
|
||||
processes-pii: false
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view vitest license
|
||||
- npm view vitest version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view vitest license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
vitest is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/vitest` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained by the Vite / Vitest team. The 3.x line is the current major. Regular releases with strong community momentum in the Vite ecosystem.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
vitest is listed as a runtime dependency of `@repo/core-testing` because it provides the test runner APIs (`describe`, `it`, `expect`, `vi`) that `core-testing` re-exports or uses in its test utilities. All feature packages declare `vitest` as a devDependency. This is the correct placement for a testing infrastructure package.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
vitest is the sole test runner in the workspace. No competing runner (Jest, Jasmine, Mocha) is present.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
vitest is a local test runner with no network communication to vendor-controlled endpoints. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `vitest` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`@repo/core-testing` lists vitest as a runtime dependency. Every feature package uses vitest as a devDependency for running tests. Named, non-hypothetical consumers exist today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
vitest replaces Jest as the test runner. The Vite-based transformation pipeline eliminates the need for Babel transforms and provides native ES module support, reducing test suite configuration complexity.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. vitest's `describe` / `it` / `expect` / `vi.fn()` APIs are used in every test file across all packages. Migrating to Jest or another runner requires updating all test files (largely mechanical API renames) and reconfiguring the coverage pipeline (ADR-020 L0 thresholds, `@vitest/coverage-v8`).
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Jest** — Mature but requires additional Babel/ESM configuration in a Vite-based monorepo; vitest provides native compatibility.
|
||||
2. **Node.js `node:test`** — Lightweight but lacks the ecosystem integrations (coverage, snapshot, mocking) that vitest provides out of the box.
|
||||
88
docs/library-decisions/2026-05-14-zod.md
Normal file
88
docs/library-decisions/2026-05-14-zod.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
package: zod
|
||||
version: "^3.24.0"
|
||||
tier: core
|
||||
decision: approved
|
||||
date: 2026-05-14
|
||||
deciders: [Danijel Martinek]
|
||||
adr: null
|
||||
lastRevalidated: 2026-05-19
|
||||
is-sub-processor: false
|
||||
processes-pii: false
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: native
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- npm view zod license
|
||||
- npm view zod version
|
||||
- pnpm audit --audit-level=moderate
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm view zod license` returns `MIT`. MIT is on the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native -->
|
||||
|
||||
Zod is authored in TypeScript and ships its own `.d.ts` declaration files. No separate `@types/zod` package is needed.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Actively maintained. The 3.x line is the current stable major. Regular releases; the zod 4.x release is in active development. Strong community and ecosystem.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
Zod is the workspace-standard schema validation library. Every use case exports `xInputSchema` and `xOutputSchema` as `z.ZodObject` instances (CLAUDE.md Key Conventions). Feature packages, core packages, and the tRPC layer all use Zod for input validation and output parsing. No boundary rules restrict Zod to a specific tier.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
Zod is the sole schema validation library in the workspace. No competing validator (Valibot, Yup, Joi, etc.) is present or proposed. The `shadow-check` filter from `_template.md` explicitly names Zod as a workspace-locked library.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
Zod is a pure runtime validation library with no network communication, telemetry, or data transmission. EU residency does not apply.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` reports no advisories against `zod` at the time of this trace.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
All five feature packages use Zod for use-case input/output schemas. `core-shared` uses Zod for tRPC input validation and error schemas. `core-audit` uses Zod for audit event schemas. `core-dsr` uses Zod for `dsrRouter` procedure input schemas. Named, non-hypothetical consumers exist today.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
Zod replaces ad-hoc manual validation (`typeof x === "string"`) that would not scale to the use-case schema pattern mandated by CLAUDE.md. No prior schema library was in the workspace.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
Hard. Zod's `z.ZodObject` types are woven into the public API surface of every use case (`xInputSchema`, `xOutputSchema`, `IXUseCase`). The tRPC router layer reads Zod schemas directly. Migrating out would require replacing schema definitions across all feature packages, updating the tRPC integration, and touching the conformance ESLint rules that reference Zod types.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **Valibot** — Smaller bundle size but at the time of adoption had less mature TypeScript inference for the factory-function use-case pattern.
|
||||
2. **Manual `typeof` / JSON Schema** — Zero dependency but does not produce TypeScript types automatically; incompatible with the `xInputSchema`/`xOutputSchema` contract pattern.
|
||||
110
docs/library-decisions/2026-05-19-jest-axe.md
Normal file
110
docs/library-decisions/2026-05-19-jest-axe.md
Normal file
@@ -0,0 +1,110 @@
|
||||
---
|
||||
package: jest-axe
|
||||
version: "^10.0.0"
|
||||
tier: feature
|
||||
decision: approved
|
||||
date: 2026-05-19
|
||||
deciders: [implementer-agent]
|
||||
adr: null
|
||||
lastRevalidated: null
|
||||
is-sub-processor: false
|
||||
processes-pii: false
|
||||
filter-results:
|
||||
license: MIT
|
||||
types: "@types/jest-axe"
|
||||
maintenance: active
|
||||
boundary-fit: pass
|
||||
shadow-check: pass
|
||||
eu-residency: n/a
|
||||
cve-scan: clean
|
||||
named-consumer: pass
|
||||
socketRisk: clean
|
||||
verification-commands:
|
||||
- "npm info jest-axe license"
|
||||
- "ls node_modules/jest-axe/index.d.ts 2>/dev/null && echo native || npm info @types/jest-axe version"
|
||||
- 'cat package.json | grep -E ''"(zod|inversify|payload|@trpc/server|superjson|reflect-metadata)"'''
|
||||
- "npm info jest-axe time.modified"
|
||||
- "npm info jest-axe time | tail -5"
|
||||
- "pnpm audit --audit-level=moderate 2>&1 | head -40"
|
||||
- "npm info jest-axe@10.0.0 dependencies"
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: MIT -->
|
||||
|
||||
`npm info jest-axe license` returns `MIT`. Within the allowlist.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: @types/jest-axe -->
|
||||
|
||||
`@types/jest-axe@3.5.9` is available on the npm registry. Community types confirmed present.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`jest-axe` is an accessibility testing wrapper around `axe-core`. It does not shadow any locked must-have (zod, inversify, payload, @trpc/server, superjson, reflect-metadata). Pass.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
`jest-axe` is a devDependency targeting `packages/core-ui`. It is a testing tool only — no runtime imports cross feature or core boundaries. ADR-006, ADR-010, ADR-017 all unaffected. Pass.
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active -->
|
||||
|
||||
Last publish: `2025-03-03T21:15:23.625Z` (v10.0.0). That is approximately 14 months before today's date (2026-05-19) — within the 18-month active window. Release cadence shows v9.0.0 in 2024-06-07, v10.0.0 in 2025-03-03. Active.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: n/a -->
|
||||
|
||||
`jest-axe` is a pure in-process testing library. It runs the axe-core engine against a DOM snapshot returned by `@testing-library/react`. No network calls, no vendor-controlled endpoints, no telemetry. EU residency check is not applicable.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`pnpm audit --audit-level=moderate` surfaces two pre-existing high-severity advisories (`drizzle-orm` SQL injection via `@payloadcms/db-postgres`, `next` DoS via `@payloadcms/ui`). Neither advisory is related to `jest-axe`. No advisories reference `jest-axe`, `axe-core`, `jest-matcher-utils`, `chalk`, or `lodash.merge`. Clean relative to this package.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass -->
|
||||
|
||||
Concrete call site: `packages/core-ui/src/cookie-consent-banner/cookie-consent-banner.test.tsx`. The cookie-consent-banner story 09 acceptance criteria require an axe-core a11y pass (WCAG 2.2 AA), and the previous implementation attempt was rejected specifically because this assertion was absent. The consumer exists today and is blocked on this adoption.
|
||||
|
||||
## Filter: socketRisk
|
||||
|
||||
<!-- Result: clean -->
|
||||
|
||||
`socket-cli` is unavailable in this sandbox environment (deprecated package, `@socket.dev/cli` not on the registry). Manual dependency audit performed instead:
|
||||
|
||||
`jest-axe@10.0.0` dependencies:
|
||||
|
||||
- `axe-core@4.10.2` — Deque Systems' accessibility engine, industry-standard, widely audited
|
||||
- `chalk@4.1.2` — terminal coloring by sindresorhus, no install scripts
|
||||
- `jest-matcher-utils@29.2.2` — Jest core team package, part of facebook/jest
|
||||
- `lodash.merge@4.6.2` — single lodash function, no network activity
|
||||
|
||||
No install scripts, no network calls, no obfuscation. Supply-chain risk assessed as clean.
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
No existing a11y testing infrastructure is being retired. The component being tested (`CookieConsentBanner`) had thorough behavioral RTL tests but lacked a structured WCAG assertion. `jest-axe` adds net-new capability without replacing any existing library.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
**Mechanical.** `jest-axe` is confined to test files: `import { axe, toHaveNoViolations } from "jest-axe"` plus `expect.extend(toHaveNoViolations)`. Removing it requires deleting one devDependency, the `expect.extend` setup, and the `expect(results).toHaveNoViolations()` assertions — a straightforward swap to any alternative (e.g., `vitest-axe`). No data-format dependencies, no runtime coupling.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
1. **`vitest-axe`** — vitest-native fork of jest-axe with near-identical API (`axe`, `toHaveNoViolations`). Rejected: smaller community, fewer downloads, less battle-tested against jsdom environments. `jest-axe` v10 explicitly supports vitest.
|
||||
|
||||
2. **`@axe-core/react`** — React devDependency that logs axe violations to the browser console during development. Rejected: designed for runtime dev-time feedback, not structured test assertions. Does not provide `toHaveNoViolations()` or integrate with vitest's assertion pipeline.
|
||||
|
||||
3. **`@storybook/addon-a11y`** — Storybook addon that runs axe in the browser during Storybook sessions. Not rejected but deprioritized: the Storybook `stories: []` config means stories are not currently auto-discovered, so the addon would not reliably catch regressions in CI without additional Storybook configuration. `jest-axe` in vitest is CI-gated deterministically.
|
||||
141
docs/library-decisions/_template.md
Normal file
141
docs/library-decisions/_template.md
Normal file
@@ -0,0 +1,141 @@
|
||||
---
|
||||
package: <name>
|
||||
version: "<semver range>"
|
||||
tier: app | feature | core
|
||||
decision: approved | rejected
|
||||
date: <YYYY-MM-DD>
|
||||
deciders: [<author>, ...]
|
||||
adr: adr-NNN | null
|
||||
lastRevalidated: null
|
||||
is-sub-processor: false
|
||||
processes-pii: false
|
||||
# include the block below only when is-sub-processor: true
|
||||
# data-sent: "<description>"
|
||||
# region: "<eu | eu-west-1 | ...>"
|
||||
# dpa-signed: false
|
||||
# sccs-required: false
|
||||
# contact: "<url or email>"
|
||||
filter-results:
|
||||
license: <SPDX id>
|
||||
types: native | "@types/<x>" | none
|
||||
maintenance: active | dormant | abandoned
|
||||
boundary-fit: pass | fail
|
||||
shadow-check: pass | fail | "shadows <x>"
|
||||
eu-residency: ok | n/a | self-hostable | fail
|
||||
cve-scan: clean | "<advisory-id>" | fail
|
||||
named-consumer: pass | fail
|
||||
socketRisk: clean | flagged | <arbitrary-string>
|
||||
verification-commands:
|
||||
- <literal command that produced each filter result>
|
||||
accepted-cves: []
|
||||
---
|
||||
|
||||
## Filter: license
|
||||
|
||||
<!-- Result: <SPDX id> -->
|
||||
|
||||
Allowed licences: MIT, Apache-2.0, BSD-\*, ISC, MPL-2.0. Record the SPDX
|
||||
identifier from `package.json` or `npx license-checker`. Anything outside the
|
||||
allowlist is an automatic reject.
|
||||
|
||||
## Filter: types
|
||||
|
||||
<!-- Result: native | @types/<x> | none -->
|
||||
|
||||
Confirm TypeScript types are available (`native` = ships its own `.d.ts`;
|
||||
`@types/<x>` = community types package exists; `none` = no types → auto-reject).
|
||||
|
||||
## Filter: maintenance
|
||||
|
||||
<!-- Result: active | dormant | abandoned -->
|
||||
|
||||
Check last release date and recent PR/issue activity. `active` = last release
|
||||
< 18 months AND activity < 12 months. `dormant` = stable but not actively
|
||||
developed (acceptable for finished libraries). `abandoned` = auto-reject.
|
||||
|
||||
## Filter: boundary-fit
|
||||
|
||||
<!-- Result: pass | fail -->
|
||||
|
||||
Confirm the dependency does not violate ESLint boundary-tag rules for the
|
||||
target tier (ADR-006, ADR-010, ADR-017). E.g., a Sentry SDK added to a feature
|
||||
package is an auto-reject because ADR-017 §4 reserves vendor SDKs for core.
|
||||
|
||||
## Filter: shadow-check
|
||||
|
||||
<!-- Result: pass | fail | "shadows <x>" -->
|
||||
|
||||
Check whether this library duplicates a must-have already locked in the
|
||||
workspace (e.g., proposing `valibot` when `zod` is locked, `tsyringe` when
|
||||
Inversify is locked by ADR-002). A parallel adoption is `shadows <x>` and an
|
||||
auto-reject; a replacement requires a dedicated ADR.
|
||||
|
||||
## Filter: eu-residency
|
||||
|
||||
<!-- Result: ok | n/a | self-hostable | fail -->
|
||||
|
||||
If the library transmits user data, telemetry, or business state to a
|
||||
vendor-controlled endpoint by default, the vendor must offer an EU data region.
|
||||
Self-hostable packages and build-time-only tools are `n/a`.
|
||||
|
||||
## Filter: cve-scan
|
||||
|
||||
<!-- Result: clean | "<advisory-id>" | fail -->
|
||||
|
||||
Run `pnpm audit --audit-level=moderate`. `clean` = no advisories at adoption
|
||||
time. Record any accepted advisory IDs in the `accepted-cves` frontmatter field
|
||||
and explain the risk acceptance here.
|
||||
|
||||
## Filter: named-consumer
|
||||
|
||||
<!-- Result: pass | fail -->
|
||||
|
||||
Answer: "Who calls this code path today, or who is blocked waiting for it?"
|
||||
Hypothetical future callers are not consumers. This filter is the direct
|
||||
response to the 2026-05-14 OpenAPI near-miss (ADR-022 §Context).
|
||||
|
||||
## Filter: socketRisk
|
||||
|
||||
<!-- Result: clean | flagged | <arbitrary-string> -->
|
||||
|
||||
Run `socket npm:report <package>` (or check socket.dev) for supply-chain
|
||||
risk signals. `clean` = no issues detected. `flagged` = one or more high- or
|
||||
critical-severity signals (requires explicit risk-acceptance note here before
|
||||
approval). An arbitrary string records the specific risk label returned by the
|
||||
Socket CLI (e.g. `"obfuscated-code"`, `"install-script"`). The `lastRevalidated`
|
||||
frontmatter field is set to the ISO date of the most recent re-run.
|
||||
|
||||
## Field: lastRevalidated
|
||||
|
||||
<!-- Value: YYYY-MM-DD | null -->
|
||||
|
||||
ISO 8601 date of the last time the Socket supply-chain scan (and any other
|
||||
time-sensitive filter) was re-run against the current installed version.
|
||||
`null` = never revalidated since initial adoption (acceptable for fresh traces).
|
||||
Updated automatically by the weekly revalidation cron (Story 05).
|
||||
|
||||
## Prompt: replaces
|
||||
|
||||
<!-- Required: answer in either direction with justification -->
|
||||
|
||||
What existing library or approach does this replace? New-and-old running in
|
||||
parallel is a smell — name the thing being retired and its retirement plan, or
|
||||
explain why parallel adoption is intentional and time-bounded.
|
||||
|
||||
## Prompt: migration-cost-out
|
||||
|
||||
<!-- Required: mechanical | hard | impossible + justification -->
|
||||
|
||||
What does ripping this back out look like 18 months from now? Is the removal
|
||||
mechanical (swap one package, update call sites), hard (scattered integration
|
||||
points, data format dependencies), or impossible (vendor lock-in, protocol
|
||||
coupling)? Higher migration cost raises the bar for adoption.
|
||||
|
||||
## Prompt: alternatives-considered
|
||||
|
||||
<!-- Required: minimum two named alternatives, or "none with explanation" -->
|
||||
|
||||
Name at least two alternatives evaluated before choosing this library. For
|
||||
`core`-tier adoptions, this section is also duplicated into the companion ADR.
|
||||
If no alternatives exist, explain why (e.g., the library is the de-facto
|
||||
standard with no viable substitutes).
|
||||
Reference in New Issue
Block a user