Skip to content
Back to skills

Cross Cutting

ASecurity

Keeps technical concerns out of business code in a ddd-ts-kit project. Logging, metrics, tracing, error reporting, the audit trail, retry, timeout, circuit breaker, caching and rate limiting are applied from outside the use cases (the composition root, bus middlewares, adapters), on the standard interfaces of the kernel. Use when adding logs, metrics, traces, an error tracker, an audit log, resilience or a cache, when choosing a logger, when code needs a correlation id, the tenant or the sess...

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 16, 2026
ai-agentsgobash

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned October 16, 2026

npx -y skills add gbourgeat/ddd-ts-kit --skill cross-cutting --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cross Cutting?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Cross Cutting
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/gbourgeat-cross-cutting/badge)](https://www.skillsdirectory.com/skills/gbourgeat-cross-cutting)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cross-cutting
description: >-
  Keeps technical concerns out of business code in a ddd-ts-kit project. Logging, metrics,
  tracing, error reporting, the audit trail, retry, timeout, circuit breaker, caching and
  rate limiting are applied from outside the use cases (the composition root, bus
  middlewares, adapters), on the standard interfaces of the kernel. Use when adding logs,
  metrics, traces, an error tracker, an audit log, resilience or a cache, when choosing a
  logger, when code needs a correlation id, the tenant or the session, when about to
  declare a home-made Logger, UserContext or paginated result, or when aspects/*,
  standard/* or a tracing or audit import in domain or application is reported.
allowed-tools:
  - Read
  - Edit
  - Bash(npx ddd-ts-kit generate *)
  - Bash(npx ddd-ts-kit check *)
  - Bash(npx ddd-ts-kit explain *)
---

# Cross-cutting concerns

A handler that logs, measures, retries, reports and audits is five concerns hiding one use
case. Business code states the business; everything else is attached from outside, in
`src/platform/` and in adapters. `@ddd-ts-kit/aspects`, `audit`, `redis` and `tracing` are
refused in `domain/` and `application/` even when an allow-list names them, and tracing is
imported by the platform, `main.ts` and `apps/` only (`tracing/platform-only`).

## Where each concern goes

| Need | Put it | With |
|---|---|---|
| log and measure every use case | bus middlewares, `src/platform/buses/` | `loggingMiddleware`, `metricsMiddleware` |
| the logger itself | `src/platform/observability/create-logger.ts` | the kernel `Logger` port; `stack.logger` chooses the adapter: `stdout` (default), `pino` or `winston` |
| trace the application | `src/platform/tracing.ts`, first import of `main.ts`, and the instrumentation given to the kernel module | [tracing.md](tracing.md) |
| report unexpected failures | the boundaries, never a use case | the kernel `ErrorReporter` port; `stack.errors: sentry` wires `@ddd-ts-kit/sentry` (Sentry or GlitchTip) in `src/platform/errors.ts` |
| who did what | around the use cases, in `src/platform/audit/` | [audit-trail.md](audit-trail.md) |
| retry, timeout, circuit breaker on an outside call | the adapter's declaration or binding; defaults in `src/platform/resilience/` | `@Adapter(Port, { kind, aspects })`, or `.with(retry(...), timeout(...))` in an explicit module |
| the same, when the policy is part of what the adapter is | the adapter class, in `infrastructure/` only | `@Retry`, `@Timeout` of `@ddd-ts-kit/aspects/decorators` (`aspects/outside-in`) |
| cache a read of another system or context | the gateway or external adapter | `cached({...})`; never a repository of aggregates |
| keep the answers of a read in the browser or a shared cache (Varnish, a CDN) | `cache` of the controller or its route group, never in the use case | a cache policy of `@ddd-ts-kit/http` (`private` with `etag` for a caller, `public` with `tags` only for what is the same for everybody); `stack.httpCache: varnish` puts Varnish in front. A `public` answer of a route that knows its caller names `Authorization`, `Cookie` or the tenant header in `vary`, and Cloudflare or Bunny ignore `Vary`. Never a decision of authorization shared across actors: the HTTP caching concept page |
| purge the answers a change made stale | a `before-commit` handler of the domain event | `CacheInvalidation.invalidate([cacheTag('calendar', id)])` of the kernel (`platform.cacheInvalidation` when wired by hand), from every event that changes what a kept answer shows, its version included: purged after the commit, through the outbox; never `CachePurger` in a use case |
| rate limit | in front of the HTTP layer | the kernel `RateLimiter` port |

`npx ddd-ts-kit generate adapter <ctx> <Port> [--kind external|gateway] [--decorators]`
writes an adapter with its policy attached (`retry` then `timeout`). Order when composing,
outermost first: logging and metrics, then retry, then circuit breaker, then timeout. Each
attempt then counts for the breaker and has its own time limit, and an open circuit ends
the retries at once.

## What may be recorded

By a log, a span, a metric, an error report: class, method, context, duration, error code,
correlation and trace identifiers, the actor's identifier. Never arguments, results, error
messages or full URLs: they carry personal data and secrets.

## Error reporting

An unexpected failure is reported once, by the first boundary that sees it: a 5xx response,
a command failing on something that is not a business refusal, an integration event buried
after its retries, a failed job, a crash of the process. A `DomainError` is an answer, not an
incident: it is mapped to a status and never reported. Handlers throw; they never call the
reporter, and never catch to log.

## Standard interfaces

Before declaring a type for one of these, use the kernel's (`standard/no-parallel-interface`):

| Concept | Kernel | Extend through |
|---|---|---|
| who acts, how they authenticated | `Actor`, `Session` | `ActorExtensions`, `SessionExtensions` |
| correlation, causation, tenant, origin | `ExecutionContext` in the `ExecutionScope` | `ExecutionContextExtensions` |
| logs, metrics, cache, lock, rate limit, jobs, errors, HTTP purges | `Logger`, `Metrics`, `Cache`, `Lock`, `RateLimiter`, `JobScheduler`, `ErrorReporter`, `CacheInvalidation`, `CachePurger` | an adapter of the port |
| lists | `Page`, `PageRequest` | generics |
| audit columns, tenant column | `AuditStamp`, `TenantScoped` | |

Extension is declaration merging in one file of `src/platform/`
(`declare module '@ddd-ts-kit/kernel' { interface SessionExtensions { ... } }`). A second
`UserContext`, `ILogger` or `PaginatedResult` is a defect.

## Who may read the execution scope

Infrastructure and the platform: audit columns, tenant scoping, log fields, the correlation
id and the tenant on published events. A key of a shared store (cache, rate limit, lock) in a
multi-tenant project is confined with `tenantCacheKey` or `tenantKey`; a job states
`tenancy: 'global'` or `'per-tenant'`; platform staff read across tenants through
`acrossTenants`, audited, never through a role. Use cases receive what they need as data of the command or query
(skill `ddd-ts-kit:access-control`). The domain sees none of it.

## Tests

The test application exposes in-memory implementations: `logger.entries`, `metrics.samples`,
`errors.reports`, `cache`, `clock`. A resilience policy is tested once, on the adapter, with
a fake that fails on demand; use cases are tested without it.

Files in this skill

  • SKILL.md6.4 KB
  • audit-trail.md2.3 KB
  • tracing.md2.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.