Bidangil – Bringing Korea’s Storefronts to the World

🚀 Inspiration

As a Korean-American living in the U.S., I constantly hit the same wall: Korean online stores insist on a local phone number + credit card and seldom ship abroad. Friends were my “human API,” placing orders on my behalf—an experience shared by thousands of immigrants and K-culture fans worldwide. Bidangil was born to remove that friction and keep people engaged through a built-in community hub while we bundle their orders into one low-cost shipment.

🛠️ What We Built

  • Full-stack web service:

    • Frontend – Next.js 14 (React 18) + Tailwind; real-time UX via WebSockets
    • Backend – Django 5.2, DRF, Django Channels, Celery, Redis, MySQL
  • Google Maps API integration: a static map snapshot appears inside a two-panel order form so shoppers instantly verify their delivery address as they type.

  • Cloud infra: GCP for object storage & global CDN, plus GitHub Actions CI/CD.

🏗️ How We Built It

  1. Order & payment automation – Webhooks drive a two-step Stripe flow (items → delivery) triggered by a custom save_formset override so exactly one payment record is created per order.
  2. Real-time pipeline – Long-running avatar generation off-loaded to Celery; when the image is ready the backend pushes it to the browser over Channels, cutting web-worker hold time from 30 s to 0.05 s and raising sustainable concurrency from 8 → 200+.
  3. Comment trees at scale – Optimized queries (select_related + prefetch_related) and an in-memory lookup table serialize nested comments in O(N) without extra DB hits.

📚 What We Learned

  • Maps ≠ maps – Even a tiny Static Maps thumbnail meaningfully boosts address-entry confidence and reduces checkout errors.
  • UX is compound interest – Micro-interactions (live nickname checks, sticky avatar quiz progress) translate directly into session length and conversion.
  • Back-pressure matters – Moving IO-bound tasks to Celery plus channel-layer pushes kept the API responsive under spike traffic.

🧩 Challenges & Solutions

Challenge Solution Impact
Serializing deep comment threads One bulk query + Python hash map rebuild 10× faster API, zero N+1 bugs
30 s AI image calls blocking workers Celery + Channels real-time push 25× more concurrent users
Preventing duplicate Stripe sessions Admin-side save_formset guard 66 % fewer API calls, simpler refunds
Competitive shipping rates Negotiated with multiple 3PLs; chose hybrid FedEx + EMS lane after weight-break analysis Saved users ≈ \$4/package

A quick math peek

We estimate delivery upfront with

$$ \text{Total Cost} = \left(\sum_{i=1}^{n} \text{KRW}i\right)\times r \;+\; w \cdot c{\text{kg}} $$

where $r$ is the live ₩→\$ rate and $w$ the consolidated weight. This transparent formula demystifies cross-border fees for first-time buyers.

🔭 What’s Next

  • Dynamic Place API look-ups to auto-suggest Korean store locations.
  • Regional fulfilment hubs to shrink $w$ in the equation above.
  • Open-sourcing our Django Channels patterns so other small shops can go global.

Bidangil turns “Can you order this for me?” into a single click experience and Google Maps made the last-mile feel as tangible online as it is on the street.

Share this project:

Updates