technical shaping — the adr
The ADR — choices the code must keep
An ADR captures one decision. Short — a single page is normal, two is plenty. The format names the context that forced the decision, the decision itself, the alternatives considered, and the consequences. An ADR is not documentation written after the fact. It is a promise the code must keep — written before the wireframes are finished, so the wireframes and the API and the schema can all reflect it.
ADR-014 · Billing
Idempotency keys for all Cardcom charge attempts
Context Cardcom rate-limits and intermittently 5xx's. Without idempotency, retries risk double-charging. Currently 993 charges/month silently drop because there is no retry.
Decision Every charge attempt sends a deterministic idempotency_key (subscription_id + cycle_id). Cardcom recognises repeats and returns the original response.
RejectedPer-request UUID: non-deterministic, retries become first attempts. Cardcom-generated key: our system can't recognise repeats locally.
Consequences Worker can retry safely. Reconciliation can group by key to detect duplicates. Schema requires unique constraint. Migration ordering matters.
The ADR is the answer to a future question that hasn't been asked yet. When a developer six months from now opens the worker code and wonders why charges have idempotency keys, ADR-014 is the answer. Without it, the reasoning has to be reconstructed from the code — and the reconstruction may reach a different conclusion.