🚀 Inspiration

Every sneaker drop, limited merch release, or flash sale has the same nightmare — overselling. We've all seen it: a product shows "1 left", five people buy it, and then five people get cancellation emails. Trust breaks. Brands lose credibility. Customers feel cheated.

I asked myself — what if this problem was solved at the database level, not the application level?

That's how DropRush was born.


⚡ What I Built

DropRush is a full-stack flash sale platform where brands can launch limited-stock drops and shoppers can claim them the moment they go live — with a mathematical guarantee of zero oversells.

Two interfaces:

  • / — Public storefront with live countdown timers, real-time stock bars, and a claim button
  • /admin — Brand dashboard with drop creation, live stats, and inventory tracking

🔬 How I Built It

The core insight was simple: don't solve race conditions in code — solve them in the database.

I used AWS DynamoDB's atomic UpdateItem with a ConditionExpression:

UpdateItem({
  UpdateExpression: "SET remainingStock = remainingStock - :one",
  ConditionExpression: "remainingStock > :zero"
})

This single operation is atomic at the DynamoDB level. If 1000 users hit claim simultaneously, DynamoDB serializes the writes internally — and stops exactly when stock hits zero. No locks. No queues. No application-level logic needed.

DynamoDB Single-Table Design:

Entity PK SK
Drop metadata DROP#<id> META
Claim record DROP#<id> CLAIM#<userId>

GSI1 powers the live drop feed sorted by launch time:

  • GSI1PK = STATUS#active
  • GSI1SK = <startTimeISO>#<dropId>

The frontend was scaffolded using Vercel v0, deployed on Vercel, and connected to DynamoDB via AWS SDK v3.


🧗 Challenges I Faced

1. The hydration problem Next.js renders on the server first — but Date.now() returns different values on server vs client. This caused React hydration errors on countdown timers. I fixed it by initializing timer state as null and only calculating on the client after mount.

2. Credentials in scripts vs Next.js .env.local is automatically loaded by Next.js dev server — but not by raw node scripts/... commands. I had to manually set environment variables for setup scripts, and document this clearly.

3. Making the race condition visible The atomic guarantee is invisible unless you can show it failing gracefully. I solved this by using 2 different browsers (Chrome, Edge) to simulate concurrent users — each with a different localStorage identity — and demonstrating live stock depletion in real time.


📚 What I Learned

  • DynamoDB single-table design is powerful but requires upfront planning of access patterns
  • ConditionExpression in DynamoDB is the right tool for inventory management at scale
  • Vercel v0 dramatically accelerates UI scaffolding — what took hours now takes minutes
  • The gap between "it works locally" and "it works at scale" is bridged by choosing the right database primitive

🏆 What's Next

  • Stripe integration for real payments per drop
  • Email/SMS notifications when a drop goes live
  • Waitlist system for sold-out drops
  • Multi-region Aurora DSQL for globally distributed drops

Built With

Share this project:

Updates