Places client-specific aggregation, caching, and release coupling in a BFF layer while domain services stay client-agnostic, with explicit rules for what may not leak across the boundary.
Package status: AI-assisted reference package. Static package validation has passed; implementation scenarios remain not run and human domain review is required before stable adoption.
Decision
Introduce a Backend-for-Frontend (BFF) per client family when aggregation, payload shaping, or release cadence differs across web, mobile, or partner surfaces. Domain services expose stable, client-neutral capabilities; BFFs own client coupling and may evolve independently within documented limits.
Scope
- BFF responsibilities versus domain service responsibilities.
- Allowed aggregation, caching, authentication termination, and pagination adaptation.
- Forbidden leakage of client-specific concerns into domain APIs.
- Timeout budgets, degradation behavior, and independent deployment rules.
Outside this block
- General microservice decomposition strategy.
- CDN and static asset delivery design.
- Full API versioning policy (see API versioning reference block).
Contract
- Domain services do not expose client-specific field names, UI concepts, or transport optimizations tied to one client.
- Each aggregate documents upstream endpoints, max_upstream_calls, and component criticality (
required,optional, orsensitive) inaggregate_upstream_map; tests assert call fan-out and failure behavior against that map. - BFFs perform response shaping and may cache with TTL documented per aggregate; domain services remain cache-agnostic unless shared cache is explicitly designed.
- Each BFF documents its upstream call budget. An optional component may return a structured partial response when its budget is exhausted; a required or sensitive component fails the aggregate closed with a structured whole-request error.
- Authentication may terminate at the BFF, but domain services do not trust client-supplied identity without validated service-to-service credentials.
- BFF releases may ship without domain deployment when changes are limited to shaping listed in the BFF manifest.
- Pagination and filtering adaptations live in the BFF contract; domain pagination defaults remain stable.
Implementation guidance
- Generate BFF OpenAPI or GraphQL schemas per client; forbid importing client types into domain modules.
- Use architecture tests to detect forbidden imports or DTO fields in domain packages.
- Instrument upstream call counts per BFF endpoint to catch N+1 aggregation regressions.
- Review aggregate criticality as part of the API contract; do not infer it dynamically from whether an upstream happens to respond.
- Document aggregates in
example.yamland keep them versioned with the BFF.
Failure handling and safeguards
- When an optional upstream component fails, the BFF may return partial data with explicit error entries rather than synthetic defaults. Failure of a required or sensitive component returns a structured whole-request error and no misleading partial aggregate.
- Circuit-break repeated upstream failures per aggregate to protect domain services.
- Do not embed business rules in BFF that belong in domain services merely to ship faster.
Verification and operations
- Track BFF upstream latency, error rates, and call fan-out per endpoint.
- Review quarterly whether new client logic still belongs in BFF versus domain.
- Test independent deployment by releasing a BFF-only change in staging.
The executable-looking examples in this package are fixtures and acceptance contracts. Validate package structure before adoption; then implement and execute the scenarios in the target repository.
Adoption assumptions
- Client names, aggregates, and timeout values in
example.yamlare profile choices for a dashboard product, not universal defaults. - Teams must map service identities and mTLS policies to their platform standards.
References
- No external normative source is required; this package defines a BFF boundary decision.