back

work · closeby

CloseBy

AI-assisted hyperlocal marketplace for neighborhood shops

Solo: design, frontend, backend, AI layer · 2026

Next.js 15TypeScriptSupabase PostgresClerkClaude APIRazorpayApache JMeter
CloseBy: AI-assisted hyperlocal marketplace for neighborhood shops

Problem

Neighborhood shop owners have no time to type a catalog, and buyers can't see what a shop near them has in stock. CloseBy lets owners import stock from a shelf photo or voice list, and lets buyers order and pay online from shops nearby.

In short

  • -Two-sided marketplace: geohash radius search, role-based dashboards, live order updates (Supabase Realtime) and in-order chat.
  • -Every AI call passes one gateway: auth, rate limit, kill switch, daily spend cap, input cleaning, tool loop, cost logging. Under load, the spend cap blocked 100% of over-cap calls before any model call.
  • -AI only drafts (stock imports, restock ideas, chat replies); the owner approves before anything is saved.
  • -Load-tested checkout with JMeter: 50 buyers racing for the last 5 units made exactly 5 orders, 0 oversells in 4/4 runs (row locks in one transaction).
  • -Razorpay flow holds stock until payment is confirmed and auto-refunds rejected orders.
  • -27 eval cases covering Hindi aliases, misspellings and gibberish input.

Architecture

A Next.js app with a single server-side AI gateway. The model never writes to the database directly; it returns Zod-validated drafts that the owner approves.

System designOne Next.js app; every model call goes through the AI gateway, every order through the state machine.
CLIENTSNEXT.JS 15 · VERCELMANAGED SERVICESHTTPSHTTPSAIhelpersactionstool looptools ·cost logsSQLcheckout ·webhookssessionBuyersearch · order · pay ·trackShop ownercatalogue · orders ·approves AI draftsNext.js appApp Router · server actions· role-gated dashboardsAI gatewayrate limit · kill switch ·spend cap · input cleaningOrder service7-state machine · integerpaiseClaude / OpenAItool loop · switchableproviderSupabasePostgres · Realtime ·Storage · RLSClerksessions · buyer / ownerrolesRazorpaycheckout · webhooks ·refunds
  • user
  • client
  • guard
  • service
  • ai
  • data
  • external
  • call
  • logical link
  • ← scroll →
  1. 01Owner uploads a shelf photo or voice list
  2. 02Gateway: auth → rate limit → kill switch → spend cap → input cleaning
  3. 03Claude tool loop returns a structured draft (validated with Zod)
  4. 04Owner reviews and approves the draft
  5. 05Approved items saved to Supabase Postgres; cost logged per call

Decisions

+ One gateway for every model call- Calling the model from each feature directly  Rate limits, spend caps and logging live in one place, so a new AI feature can't skip them.
+ Human approval before any write- Letting the model save stock automatically  A wrong price or quantity costs a real shop money; a review step is cheap.
+ Integer paise and a seven-state order machine- Float rupees and free-form status strings  No rounding errors, and illegal status jumps are rejected at the boundary.

Failure handling

Model returns malformed or partial output

Zod validation fails closed; the owner sees an error, nothing is saved.

Daily AI spend exceeds the cap

Gateway refuses new calls until the next day; manual entry still works.

Prompt injection in uploaded text

Input cleaning plus tool-only output; the model can't trigger writes.

Numbers

0

Oversells, last-stock race

50 buyers · 5 units · 4/4 runs

800

Concurrent orders, 0 errors

~160 orders/s

153 ms

Search p95 at 50 users

27

Eval cases

Load tests

JMeter 5.6.3 against a production build (1 Node process, 5-connection DB pool) with local Postgres, mock Claude and stubbed Clerk users.

Last-stock race

50 buyers at the same instant, 5 units left (×4 runs)

Exactly 5 orders, 45 clean rejections, stock 0: 0 oversells in 4/4 runs

Checkout load

100 buyers × 8 COD orders

800/800 OK, 0 stock mismatches, ~160 orders/s, p95 697 ms

Nearby search

50 users, 30 s

10,529 requests, 0 errors, ~350 req/s, p95 153 ms

Nearby search

200 users, 60 s

21,690 requests, 0 errors, ~360 req/s, p95 620 ms

AI rate limit

1 user, 30 rapid calls

15 allowed, 15 rejected with 429

AI spend cap

User over the daily cap, 20 calls

20/20 blocked, 0 model calls made

AI gateway load

50 users × 5 calls

250/250 OK

Forged Razorpay webhooks

100 bad signatures

100/100 rejected with 401

Next

  • ○ Grow the eval set to ~100 hard cases
  • ○ Record a 90-second demo video
  • ○ Stock substitution suggestions