Skip to content
Role
Strategy · design · build · operations (solo)
Team
Solo
Period
2026.05 – 2026.09
Tools
Claude Code, Apps in Toss SDK, TDS, Supabase, Vercel

A subway car crowding mini-app

Kankan

Kankan live – crowding by car for two transfer legs from Nowon to Gangnam; change the hour and quiet, normal and crowded shift

Summary

The route is already known. The missing decision is which car to board. Enter where you get on and off, and one screen shows how crowded each car is at that hour and which car is closest to your transfer.

Passed · live
Apps in Toss review

shipped as a mini-app inside Toss

77
quick-transfer errors fixed by hand

measured; cross-checked across two sources

456
verified records bundled with the app

output; so no uncertain value goes out live

Personal project – strategy, UX, design, build, data, review and operations (solo, with Claude Code)

Overview

The route is already known. The missing decision is which car to board. Map apps stop at the fastest route, so the car with a seat is picked on instinct every time. It started with my own commute.

Kankan is a mini-app that runs inside Toss (Apps in Toss). I planned, designed, built, submitted and operate it on my own, and it passed review and shipped.

Live: kankan-eta.vercel.app

Problem

The problem fits in one sentence. Which car do I board to get a seat?

  • Finding a seat is guesswork – daily riders rely on instinct to decide where to stand.
  • Map apps don't look at cars – Naver and Kakao Maps show the shortest or best route, not crowding by car.
  • Who it's for – commuters and students who want a seat but have no information, and stand again today.

Key decisions

  1. 01Answer before the train arrives – one input, one result

    For someone deciding seconds before boarding, tabs, settings and onboarding all come too late.

    →A single-screen flow: enter two stations and the result appears. Station search works with Korean initial consonants.

  2. 02Finish the transfer on the same screen

    If the car with a seat and the car nearest the transfer differ, people end up opening another app.

    →Each leg shows crowding by car, and the transfer step shows the quick-transfer car number.

  3. 03Read it by colour, not numbers

    Someone waiting on a platform has no time to read, and no time to doubt the screen.

    →Crowding is coded green, yellow and red, with the percentage secondary. The recommended car is marked.

  4. 04Don't trust public data as it is

    Checking quick-transfer data station by station against an existing route app turned up missing and wrong entries. A wrong car number becomes a wrong move.

    →Cross-checked the Ministry of Land data against the Seoul Metro API. The 77 records where they disagreed were checked and corrected by hand (measured).

  5. 05A verified static bundle beats an uncertain live value

    The live API was unreliable in places. Not shipping a wrong car number mattered more than showing the newest value.

    →456 verified quick-transfer records ship with the app as static data (output). No live call is made for them.

Process

Designing within constraints

I mapped the platform, infrastructure and API limits early, and let each one shape a design or build decision.

  • Apps in Toss policy – no pop-up on entry, no pushing users to outside apps, no blocking the back action. The back button was removed in favour of the native gesture. The app passed review once those conditions were met.
  • WebView – built to the Apps in Toss SDK and web framework guide, entirely inside a WebView with no native code.
  • Free API limits – crowding doesn't change much, so it is collected in batches and cached in Supabase, keeping live calls within the 1,000-a-day limit. Running cost stays at zero.

Design

Toss Design System (TDS) components are used as they are, so the app feels native inside Toss.

The TDS components used
  • SearchBar – station search.
  • Badge – crowding, colour-coded.
  • CTAButton – "Recommend a car", the one action.
  • NavigationBar – logo and centred title.

Data

Sources and processing
  • Crowding and alighting ratio by car – Puzzle API (Geovision SK), in 30-minute steps, lines 1–8. Collected in batches, cached in Supabase and read by hour.
  • Quick-transfer car numbers – Ministry of Land CSV and the Seoul Metro API. Cross-checked, 77 errors fixed, 456 records bundled as static data.
  • Maintenance – a batch script refreshes crowding in Supabase; when station data changes, quick-transfer data is re-checked and replaced. API usage is watched in Vercel logs.

Results

Shipping is the result. It passed review and runs inside Toss. Usage is not measured yet.

Passed · live
Apps in Toss review
77
Data errors fixed by hand (measured)
₩0
Running cost

Where a person steps in

  • By itself – public data is cross-checked between two sources and baked into a cache.
  • By hand – the 77 places where the two disagreed were checked and corrected by a person, and where the live API is unreliable, 456 verified records ship as static data so the app never shows a wrong number in real time.

Reflection

What held up

  • The same data becomes a different service in a different context. The crowding data already existed; fitted to the moment before boarding, it became something else.
  • Choosing not to ship a wrong value. Verified records won over fresh ones. Coverage stops at lines 1–8, but no wrong car number reaches the screen.
  • Removing the cost was a design decision too. To keep a solo-built service open for long, it had to run at zero.

What failed

  • I assumed two public sources would agree. They disagreed on 77 records. Trusting one of them would have shipped wrong car numbers.
  • I assumed live values were always better. The live quick-transfer data did not match reality. Being right came before being current.

What I would test next

  • Whether the recommendation was right. There is no way yet to tell whether people got a seat in the car Kankan suggested.
  • Crowding is a 30-minute time-slot figure. How far it drifts from a given day's reality is unknown.
  • More lines – whether the same data quality exists beyond lines 1–8. Line 9 and the metropolitan express lines (GTX) are next.
  • Alerts – whether a push before departure beats deciding in the seconds before boarding is still unknown.