GitHub

Numbers that agree with each other.

Counts, badges and reports are built from one source, so they cannot show different answers.

Problems this prevents.

Dashboard counts that disagree with the page behind them.

Counts and lists use the same query.

Sale badges still showing after the sale has ended.

Badges check the sale dates when the page loads.

Products advertised in feeds that checkout would refuse to sell.

Feeds and checkout share one rule for what is buyable.

Refund totals drifting away from the payment records.

The database rejects any refund above the order total.

Rules the database enforces.

They hold even if the app has a bug.

capture+182.40
refund−24.00
correction+24.00

Money

4
  • Payment ledgers are append-only. A correction is a new row.
  • Refunds cannot add up past the order total.
  • Every order keeps the total in your own currency, as it was on the day.
  • Money can never go negative.
124+8=132

Stock

3
  • Stock movements are append-only.
  • Before plus change must equal after, and the change cannot be zero.
  • A movement only writes if it matches the row it is changing.
LINEN-01saved
linen-01rejected

Identity

3
  • Emails, SKUs, coupon codes and slugs are unique in the database.
  • Case does not create a second one.
  • Only one default channel can be active.

If a cached figure ever disagrees with the database, you get an alert.

Status is worked out, not stored.

Nothing has to remember to update itself, so nothing goes stale.

Stored against derived

Stored

A status column has to be updated by hand or by a job. When that misses, the screen is wrong.

Derived

Returns, reviews and payouts calculate their status from the events behind them. Always current, and nothing to maintain.

1,517 tests151 files25 architecture checks70 data models