-
-
-
Dual-DB: Aurora DSQL = strongly-consistent multi-region seat ledger (source of truth), Aurora PostgreSQL = PostGIS + pgvector discovery.
-
Landing — "Run a sold-out on-sale without the disasters." On-sale infrastructure for event businesses (artists, brands, ticket sellers).
-
Organizer console — live sell-through, seat map, on-sale health (0 double-sold), read live from the strongly-consistent Aurora DSQL ledger.
-
Discovery on Aurora PostgreSQL — PostGIS radius (ST_DWithin) + pgvector ranking. live open-seat counts merged from the Aurora DSQL ledger.
-
Seat selection on Aurora DSQL — row-per-seat versioned conditional update: the seat you pick is yours, never oversold, never double-booked.
-
Live Aurora DSQL cross-region proof (dsql-setup.mjs): 24 buyers, 1 seat, us-east-1 + us-east-2 = 1 winner, 23 OC000, 0 oversold.
💡 Inspiration
Every few weeks the same headline runs: a major on-sale melts down. The same seat sells to two people, a refund war starts, bots scoop the inventory, and the site falls over at the exact moment demand peaks. The fans lose, and the organizer — the artist, the brand, the promoter — eats the cost and the reputation hit.
We kept asking why this still happens in 2026, and the answer was always the same: there is no single source of truth for a seat. Most ticketing stacks either run a single-region database (a global audience hammering one region) or they scale out with asynchronous replication — which means two regions can believe the same seat is free at the same instant. The oversell isn't a bug in the checkout code; it's baked into the data layer.
So we flipped the question. Instead of "how do we patch oversell," we asked "what database makes oversell structurally impossible?" That question led us straight to Amazon Aurora DSQL, and OpenSlot is what we built on top of it.
🎟️ What it does
OpenSlot is on-sale infrastructure for event businesses — the engine an organizer runs a worldwide drop on without the disasters.
- Zero oversell, by design. Every seat is a row in a strongly-consistent, multi-region ledger. A seat is granted exactly once, even with the whole planet racing for the last one.
- Provably fair. Allocation order is projected from the ledger itself, so an organizer can show fans and regulators exactly who got each seat and why — no bot or insider lane.
- Bound to a real person. Tickets are identity- and device-bound, with a gate code that rotates every 30 seconds, so a screenshot is worthless to a scalper.
- Discovery that understands intent. Fans find drops near them, ranked by meaning, not just keywords.
The organizer console is the product: live sell-through, a real-time seat map,
revenue protected, and an on-sale health panel reading 0 double-sold ·
0 failed checkouts · bots blocked · fair allocation verified.
🛠️ How we built it
Two databases, one job each — because no single engine does both.
1) The seat ledger — Amazon Aurora DSQL.
DSQL gives us active-active writes across us-east-1 and us-east-2, with a
us-west-2 witness for quorum, exposed as one logical, strongly-consistent
database. We model inventory as one row per seat and claim with a
versioned conditional update: probe a claimable seat, check its version,
update only if it is still open. We randomize probing across claimable seats
to spread writes across the key range instead of funneling demand into one
counter row, then handle OC000 conflicts with bounded exponential backoff and
jitter. Because DSQL gives a single global commit order, competing claims
resolve to exactly one winner and the rest surface as OC000. The result is not
lock-based ticketing; it is OCC-aware seat settlement — one final seat can
have many competing buyers, but only one commit wins, so oversell stays 0 as a
structural property of the ledger, not a best-effort checkout policy.
2) Discovery — Amazon Aurora PostgreSQL. Discovery needs PostGIS (geo-radius search) and pgvector (semantic ranking) — extensions DSQL can't host. So a second database is required, not a luxury. Aurora PostgreSQL ranks the top-K events by meaning and distance, then the app performs a bounded top-K merge with live availability from the DSQL ledger. PostgreSQL is a discovery hint layer; DSQL is the source of truth for final availability and claims — so a "sold out" is read live from the ledger, never cached in Postgres.
Frontend / edge. Next.js 15 (App Router) on Vercel — the storefront, the
organizer console, the buyer claim flow, and the /demo proof console. API routes
talk to Aurora DSQL over the Postgres wire with IAM-token auth, and to Aurora
PostgreSQL for discovery.
The honest tradeoff. Strong multi-region consistency isn't free — cross-region
commits pay roughly two inter-region round-trips, visible in the us-east-2 p95.
We keep two latency numbers clearly separate: the /demo UI shows modeled OCC
commit latency for the 2,000-buyer stampede, while a separate live Aurora DSQL
proof script measures real cross-region commit confirmation on the final-seat
contention case. Model projection for the UI stress demo; live DSQL latency for the
infrastructure proof.
📚 What we learned
- Pick the database for the invariant, not the feature list. "Zero oversell" is a consistency invariant, so the consistency model — not the ORM or the framework — is the real design decision.
- Design for conflict, not against it. Under OCC, the winning pattern is small transactions, row-per-seat fan-out, randomized probing across claimable seats, and bounded retries with backoff + jitter — not locks.
- Constraints are documentation. DSQL's missing features each taught us the right shape: no foreign keys → explicit app-level authorization; no partial indexes → reuse released-seat slots instead; transaction limits → chunked work.
- Two databases can be the honest answer. "Strongly-consistent concurrent writes" and "geo + vector discovery" genuinely cannot live in one engine today, and saying so is more credible than forcing one DB to fake both.
🧗 Challenges we faced
- Optimistic concurrency under stampede conditions. The
/demoUI runs a deterministic OCC stampede model up to 2,000 buyers against 100 seats: 100 granted, 0 oversold, conflicts retried, never double-sold. Separately, a live Aurora DSQL cross-region proof script targets the worst case — one final contested seat, concurrent transactions from both active regions (us-east-1+us-east-2): exactly one winner,OC000for the rest, zero double-sell. We keep the modeled demo numbers and the live-infra numbers distinct. - Asynchronous secondary indexes. DSQL builds indexes with
CREATE INDEX ASYNC; a unique constraint isn't enforced until the index isACTIVE. We pollsys.jobsand only open the sale once the index is live — otherwise uniqueness is a lie during the build window. - No foreign keys → IDOR by default. Without FK-enforced integrity, every cross-entity access needs explicit app-level authorization. We hardened the claim and ticket paths so one buyer can never read or grab another's seat.
- Hard transaction limits. DSQL caps a write transaction at 3,000 changed rows / 10 MiB / 5 minutes. Pre-generating seats and re-releases had to be chunked to stay under the row limit, with an idempotent one-time seed.
- Connection lifecycle. Connections live at most 60 minutes and auth is via short-lived IAM tokens, so the data layer had to reconnect and re-sign transparently under sustained load.
- Multi-region pairing reality. DSQL multi-region clusters live within a
single region set (no cross-continent pairs), so we anchored on the canonical
us-east-1 + us-east-2 + witness us-west-2topology and kept a single-region fallback gate for safety.
OpenSlot is the result: sell out — without the disasters.
Built With
- amazon-web-services
- dsql
- next.js
- postgresql
- typescript
- vercel
Log in or sign up for Devpost to join the conversation.