Skip to content

External systems

An external system is a dependency or participant outside the generated application’s operational boundary. Model the contract the product depends on, not a vendor SDK copied into domain logic.

An external-system definition can capture:

  • direction: inbound, outbound, or both;
  • kind: payment, identity, tax, messaging, logistics, or generic;
  • transport: HTTP, gRPC, AMQP, SQS, Kafka, or custom;
  • authentication method;
  • synchronous capabilities and typed errors;
  • asynchronous callbacks and signature requirements;
  • rate limits and provider documentation;
  • the environment-variable names used for endpoints and credentials.

This gives the generator enough information to create an adapter boundary while keeping secrets outside the model.

A capability is a synchronous operation exposed by the external system. Define typed inputs, output shape, and error codes.

PaymentProvider.authorize(amount, currency, paymentMethodToken)
→ authorizationId, status
errors: declined, timeout, invalid_token

The product model decides what each outcome means. The adapter translates vendor-specific responses into the declared contract.

A callback is an asynchronous message the provider sends to the application. Declare payload shape and signature method. Bind it to an event or system-initiated action so retries and idempotency have an explicit target.

Treat callbacks as untrusted input: verify signatures, reject replay where required, and record provider identifiers used for deduplication.

Configuration changes are not product changes

Section titled “Configuration changes are not product changes”

If a provider changes its endpoint or rotates a credential while the contract remains the same, update the add-on or runtime configuration. No application regeneration is normally required.

If the provider changes behavior or payload shape, update the integration contract or generator adapter, regenerate, test, and deliver a new release.

Model what the product does when a dependency is slow, unavailable, or returns an uncertain outcome:

  • retry with bounded backoff;
  • queue work for later;
  • open a circuit and degrade gracefully;
  • mark the operation pending reconciliation;
  • compensate through a separate action;
  • require operator review.

Never model “retry forever.” Every async path needs observability and a terminal or inspectable state.

An integration can be recorded as planned without inventing a fake endpoint or pretending it is wired. Planned ports preserve roadmap intent while keeping the generated release honest.

See Configuration and secrets and Incidents for runtime response.