Inspiration

When a parent revokes consent or sets a spending cap for a child on a global platform, the change rarely takes effect everywhere at once. The platform writes to one region and the others reconcile later, and in that replication gap the child keeps playing, or keeps spending, somewhere else. There is also rarely verifiable proof of when the parent actually acted. Regulators are closing in on exactly this gap (the EU Digital Services Act, GDPR, the US COPPA rule, the UK Online Safety Act), and Amazon is retiring QLDB, the obvious tamper-evident-ledger primitive. We wanted to find out whether Aurora DSQL's strong consistency on commit could turn a parent's decision into a safety property with no vulnerable window, and rebuild the verifiable-ledger idea on top of it.

Custody is a neutral system of record for parental consent and minor spend control that gaming and social platforms can call. A parent grants or revokes consent and sets a spending cap for a minor, and the decision is strongly consistent across regions the moment it commits: a platform makes one gate call and gets an identical allow or deny from any region. Every consent and spend event is appended to a per-user SHA-256 hash chain, so the entire history is tamper-evident and independently verifiable, even outside the app. Four things work live on real data: cross-region consent revocation with a measured commit latency, a tamper-and-verify ledger, a real optimistic-concurrency contention burst, and an SD-JWT age-bracket proof that never discloses the date of birth. The interface is a dark control room where each capability is its own live, interactive panel, and the ledger verifies in the browser, so a judge can check the integrity claim without trusting us. It installs to a phone home screen as a PWA.

How we built it

The spine is Amazon Aurora DSQL, active-active across us-east-1 and us-east-2 with a us-west-2 witness for quorum. The data model is the part we are proudest of, and it is shaped entirely by DSQL. Event tables are append-only with a per-entity composite primary key, (user_id, seq) for consent and (minor_id, seq) for spend, that serializes each chain, so two concurrent appends collide on the key, surface SQLSTATE 40001 at commit, and exactly one retries through the withRetry OCC wrapper. Current state lives in per-entity projection rows updated in the same transaction, never a single global counter row (which would be a hot key). Every index is built with CREATE INDEX ASYNC; idempotency is an INSERT ON CONFLICT under a unique async index, so a replay is a no-op; money is integer minor units, never a float.

The front end is Next.js 16 on Vercel: Server Actions for mutations, Route Handlers, and per-region Server-Sent Events for the live cross-region view. There is no database password anywhere: Vercel issues an OIDC token, the app exchanges it for a short-lived, region-scoped DSQL token, and the public demo connects as a least-privilege role with no delete and no DDL. The audit chain is SHA-256 over deterministic canonical JSON (sorted keys, bigint-safe), verified in the browser with the Web Crypto API. The age proof is real SD-JWT selective disclosure (RFC 9901).

Challenges we ran into

Aurora DSQL is PostgreSQL-compatible, but it is not PostgreSQL, and getting the chain right under contention was the real work. A naive read-the-tip-then-insert lets two writers both commit and silently fork the chain because DSQL does not conflict-check plain reads. Serializing through the composite primary key, so the conflict surfaces at commit as 40001 and exactly one writer retries against the fresh tip, is what keeps the chain unforked. We proved it with an eight-way concurrent-append test: sequence numbers 1 through 8, one clean linked chain, zero forks.

The other discipline was honesty about consistency. The commit pays roughly two cross-region round trips and an OCC retry can add time, so we never call it instant. We call it strongly consistent on commit, with no vulnerable window.

Accomplishments that we're proud of

Everything in the submission is wired front to back to real Aurora DSQL and is judge-clickable: there is no mock data behind the demo, only synthetic operational inputs (no real minors, no biometrics). The headline is provable live: a revoke in one region is read from the other region's endpoint on commit, the contention burst resolves real 40001 conflicts into an unforked chain, and the ledger turns red from the first tampered block. We rebuilt the tamper-evident-ledger capability that QLDB is losing on a database that has no ledger feature.

The build is set up like production: credential-free OIDC, a least-privilege runtime role with no delete and no DDL, a fast and accessible front end, CI on every commit, 88 tests (83 unit, 5 live-DSQL integration).

What we learned

Strong consistency on commit is not only a performance feature, it is a safety feature: it lets a parent's revocation become the durable, everywhere-agreed state with no window where one region still treats the minor as unprotected. We learned to design for DSQL's commit-time conflict model rather than fight it, to make every write idempotent so a retry is a no-op, and to be precise in our claims, which a panel of database engineers respects more than a superlative.

We also learned where the honest line is: this demo needs selective disclosure of an age bracket, not a full zero-knowledge proof, so that is what we built and that is what we claim.

What's next for Custody

Wire SD-JWT issuance to a real age-assurance provider with holder key binding, add a parent-facing native mobile client (the bearer-token API and the portable TypeScript correctness core are already in place), expand the compliance mapping into per-jurisdiction evidence exports, and load-test the contention path toward the million-writer scale the architecture is designed for. The data model and the credential-free connection path are built to carry it.

Built With

Share this project:

Updates