Skip to content

Schema decisions are meaning-carrying

The schema is where the system remembers things. What it remembers, and in what shape, decides what questions can be asked of it later. A schema with a charge_attempts table can answer which charges failed and why. A schema without one cannot — the question simply has no place to land. The shape of the data is the shape of the questions the system can answer.

The schema is not the same as the domain model — the conceptual entities the system reasons about (a Subscription, a Charge Attempt, a Customer, a Plan, a Cycle) and the rules that govern them. The domain model is the thinking; the schema is one way of storing the result of that thinking. Senior engineers shape both, and the chain depends on both being honest about what the brief witnessed.

text
┌─ subscriptions ───────────────────┐   ┌─ charge_attempts ──────────────────┐
│  id                  uuid    PK   │   │  id                  uuid    PK    │
│  customer_id         uuid    FK   │   │  subscription_id     uuid    FK    │
│  plan_id             uuid    FK   │   │  idempotency_key     text    U     │
│  status              enum         │   │  status              enum          │
│  next_billing_at     timestamp    │   │  failure_category    text          │
│                                   │   │  cardcom_response    jsonb         │
└───────────────────────────────────┘   └────────────────────────────────────┘

Two columns deserve a moment. idempotency_key is unique per attempt — the same key on a retry tells Cardcom this is the same charge, not a new one, so the customer isn't billed twice. (Idempotency is the property of an operation that can be repeated without changing the outcome beyond the first time; it's foundational in distributed systems and worth knowing if you don't already.) failure_category is an enumerated reason: rate_limited, stale_plan_ref, card_expired, provider_error. The categories are not arbitrary — they are derived from observation of the seven months Uri has been reconciling. The schema records what the brief witnessed.

Next — API contracts written before code →

200apps · How We Work · NWIRE