Overview
PlayNice is a popular bag business in the Philippines that used to run entirely through Instagram DMs — customers messaged to order, and orders were tracked by hand in a spreadsheet. I designed and built the site that replaced that workflow end to end: customers now browse, order, pay, and track their order themselves, while the owners manage everything from an admin dashboard. I was the sole developer — design, frontend, backend, database, and deployment — and the whole thing runs for roughly the cost of a domain name a year. It's deployed and live, with final polish ongoing.
The Problem
- Orders and payments were tracked by hand in DMs, slow, and easy to get wrong.
- The costliest issue: people would reserve a bag in chat and then never pay, locking up stock indefinitely.
- No card processing — customers pay via GCash or bank transfer, so every payment needs manual verification.
- The business needed to run on close to nothing. Most "free tier" infrastructure has a catch (commercial-use restrictions, databases that pause when idle), so the stack had to be chosen carefully, not defaulted to.
What I Built
For customers: a mobile-first catalogue with zoomable product photos, a cart, and a checkout that calculates shipping from a real Philippine province/city/barangay address lookup. After ordering, each customer gets a private tracker link — no account needed — showing order status, payment instructions, and a one-step screenshot upload to confirm payment.
For the owners: an admin dashboard behind Google sign-in, with an order queue that surfaces what needs attention first, payment-proof review, product management, and editable shop settings (pricing, shipping fees, the announcement banner) so they never need to ask me to change a number. A dashboard tracks revenue, best sellers, and cart-to-order conversion.
Engineering decisions worth calling out:
- Stock reserves itself, then releases itself. Placing an order locks the stock for a window; if payment never arrives, a scheduled job (running every 10 minutes) cancels the order and frees the stock automatically. This directly fixed the original "reserved and never paid for" problem.
- Overselling is prevented by the database, not by hope. Stock decrements happen in a single batched write guarded by a
CHECK (stock >= 0)constraint — if a decrement would go negative, the whole write aborts. No race condition can oversell a bag. - The client is never trusted. The cart only ever holds product IDs and quantities; prices, shipping, and totals are recalculated server-side on every request, so nothing a customer's browser says is taken at face value.
- Tracking without accounts. A single unguessable order code is the only credential needed to check status — no login, no password, no stored personal data on the tracker page itself.
Working with Claude
I built this with Claude as a working partner, and I think it's worth being upfront about how, because directing it well was its own skill.
I kept a project-level context file — the stack, decisions already made, schema, conventions, and gotchas I'd hit — so every new session started with real context instead of me re-explaining the project or Claude re-deriving it from the codebase. I noticed the more specific my ask (which file, which behavior, which constraint), the better and cheaper the answer; vague prompts got vague, speculative code back.
I was new to the Next.js App Router, Drizzle, and Cloudflare's stack, so I made every change come with an explanation of how and why — not just working code. That's what let me actually debug it myself and defend every decision later, instead of shipping something I couldn't explain.
Claude is noticeably weaker at design and UX judgment than at implementation — left alone, its first instinct for the admin's stock editor was a plain number input, where every e-commerce admin uses plus/minus steppers. I made that call and the rest of the product decisions myself, and treated its output as a first draft to review, not a final answer. I also never gave it access to secrets or production — API keys and OAuth tokens stayed in env files and the host's own secret store, and staging was kept fully separate from production so any mistake, mine or the model's, had a small blast radius.
Status & What I Learned
The site is deployed and live, with final polish and testing ongoing before full launch — so there's no order volume or revenue to report yet. The real learning was in the constraints: designing around free-tier infrastructure instead of reaching for heavier tools, keeping Server and Client Components cleanly separated, and treating money and concurrency as first-class problems rather than details to patch later.


