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
- Order & payment automation – Webhooks drive a two-step Stripe flow (items → delivery) triggered by a custom
save_formsetoverride so exactly one payment record is created per order. - 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+.
- 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.
Log in or sign up for Devpost to join the conversation.