The problem
At a three-day exhibition, booth visitors scan a QR code and go through SMS verification, a guide, an O/X quiz, a survey, a prize draw, a winning text and staff pickup — one mobile flow, under real crowds.
Decisions
- The prize draw is guarded three ways — advisory lock, row-lock fallback and a quantity CHECK constraint — so on-site concurrency can never overpay.
- The code staff compare by eye is kept separate from the URL token.
- Big changes — a new draw engine, coupons — shipped to production early behind data gates: an empty value falls back to the old behavior. The draw is weighted by remaining stock and closes the day when stock runs out.
What broke — and the fix
- Confirmed client changes were missing in production while code, commits and deploy logs looked fine: another session’s main deploy had overwritten this branch’s build. Found by measuring live, then merged, redeployed and guarded.
- On iOS only, the screen slid sideways after the result popup: overflow-x: hidden had become a hidden scroll container, and focus dragged it. Fixed with overflow-x: clip.
Results
- 961 participants · 960 finished · 922 prizes collected
- 961 survey responses (100%) · satisfaction 4.79/5 · topic understanding 4.78/5
- 0 SMS delivery errors; prizes fully given out over three days
- Concurrency test, 200 requests: 0 over-stock, 0 double awards, idempotent 12/12
- Eight-step participant flow plus a pickup screen