A conversation with Hy

What are you building?

Btaxi

A ride-hailing MVP for Cambodia, across rider, driver and admin.

I designed it and I built it: I wrote the spec and the business rules, ran the AI agent in Cursor that writes the code, worked with two contract developers and external QC, and shipped only what passed my tests.

Client UAT passed · launch on hold on the client's side

App screens from my Figma file, admin screens from the live build, all shown in English with demo names, places and prices. Map data © OpenStreetMap contributors.

How did I help
  • End-to-end build
  • Mobility · Cambodia
Role
Product designer & builder
Team
Me + an AI agent, 2 contract devs, external QC
Surfaces
Android, iOS, admin web
Year
2026
AI summary
Who's reading? I'll show what matters to you.
  • A ride-hailing MVP for Cambodia: a rider app, a driver app and a web admin, designed and built by me with an AI agent.
  • Drivers top up by bank transfer with admin approval, because ABA Bank integration wasn't legally possible at MVP stage.
  • 130 updates and 13 blocking bugs fixed in three months. Client UAT passed; the launch is on hold on the client's side.
View CV

The tour: No bank integration? → I build with an AI agent → Three bugs

Ask about this case
Three Btaxi screens in English: the rider choosing a tuk-tuk with a 50% coupon applied, the rider's trip card with the driver on the way, and the driver's ride offer with Decline and Accept

One market.
Three apps. Local constraints.

The brief

The product had to work for locals, expats and tourists at the same time, on a startup budget.

  • 01
    Three apps that must stay in syncRider, driver and admin all have to agree, or riders stop trusting the system.
  • 02
    No budget for custom infrastructureSo I reused an existing ride-booking and GPS platform, and spent design time on the parts that needed local thinking.
  • 03
    The payment people expect isn't availableABA Bank integration wasn't legally possible at MVP stage, even though it's how most people expect to pay in Cambodia.

The same ride,
seen from both seats.

Two apps, one trip

While the rider watches the driver come, the driver gets the rider's pickup and a button for each step of the trip.

The same trip in both Btaxi apps, in English, on a Phnom Penh map. Left, the rider app: your driver is on the way, with the driver Sokha and buttons to chat or call. Right, the driver app: your rider is waiting, with the rider Dara and a Go to pickup button.
Demo content

Rules first,
screens second.

Key decisions

Each of these started as a rule in the spec, then became the screen that makes the rule obvious.

The Btaxi ride choice in English, before and after the coupon BTAXI50: first the base fares (Tuktuk 21,000 KHR, Sedan 40,000 KHR, SUV 51,000 KHR), then the halved fares with the base fare crossed out under each and a green Coupon applied: 50% off message.
01 / 04 · Rider app

A coupon comes off the base fare

The discount applies to the base fare of the vehicle the rider picks, and the fare is fixed before booking.

  • The Btaxi ride choice in English, before and after the coupon BTAXI50: first the base fares (Tuktuk 21,000 KHR, Sedan 40,000 KHR, SUV 51,000 KHR), then the halved fares with the base fare crossed out under each and a green Coupon applied: 50% off message.
    01 / 04 · Rider app

    A coupon comes off the base fare.

    The discount applies to the base fare of the vehicle the rider picks, and the fare is fixed before booking.

  • The Btaxi rider home in English on a Phnom Penh map, with Where to? at the top and three vehicle types ringed: Tuktuk, Sedan and SUV
    02 / 04 · Rider app

    Tuk-tuk first. A tuk-tuk, a 4-seat sedan and a 7-seat SUV, each with a fixed price shown before booking. The tuk-tuk comes first, with its own icon, so the product reads as Cambodian, not a clone.

    The vehicle line-up and the local tuk-tuk icon.

  • The Btaxi driver wallet in English: 40,000 KHR chosen, the ABA Bank account copied, and the transfer details ringed: put your phone number in the transfer note, processing takes 3 to 4 working hours
    03 / 04 · Driver app

    Admins approve every top-up.

    Bank integration wasn't legally possible at MVP stage, and automated checks would have grown the scope before the MVP proved itself. Manual approval works without the bank.

  • The Btaxi driver sign-up step Enter a referral code, in English: the referral code is the phone number of the driver who invited you, and the step is optional
    04 / 04 · Driver app

    A referral is a phone number.

    A new driver types the inviter's phone number. The inviter is rewarded only after the new driver finishes a first ride, so fake accounts earn nothing.

No bank integration?
Design a deposit flow admins can trust.

The payment workaround

A semi-automated deposit with manual admin approval, so drivers can top up before a bank integration is legally possible.

Built: bank transfer with approval, a working payment flow without the legal blocker. Four steps: the driver requests a top-up in the app, transfers to the Btaxi account with their phone number in the note, an admin matches the transfer and approves on the web within 4 hours, the balance is topped up. Beside them two driver app screens in English: the wallet with the transfer details and the account number copied, and the top-up history with the newest 40,000 KHR request Pending.
Expected: in-app bank payment, not legally possible at MVP stage. Three greyed steps: the driver tops up through ABA Bank in the app, the bank confirms instantly, the balance is topped up. Beside them a locked panel: ABA Bank in the app, not legally possible at MVP stage.
ExpectedBuilt

Inside the two apps.

Product flows

Book a ride, ride it, drive it, and top up the driver's wallet.

The Btaxi rider app in English, in one phone: Where to?, the destination picked from suggestions, the three ride options, the coupon sheet with BTAXI50 typed and applied, then Book now and Finding a driver.
01 / 04 · Rider app

Book a tuk-tuk with a coupon

Pick a destination, choose a vehicle at a fixed price, add a coupon, book.

  • The Btaxi rider app in English, in one phone: Where to?, the destination picked from suggestions, the three ride options, the coupon sheet with BTAXI50 typed and applied, then Book now and Finding a driver.
    01 / 04 · Rider app

    Book a tuk-tuk with a coupon. Pick a destination, choose a vehicle at a fixed price, add a coupon, book.

    The booking path, the ride options and the coupon sheet.

  • The Btaxi rider app in English, in one phone: finding a driver, the driver Sokha accepted, on the way, at the pickup, the trip under way, then the cash payment of 10,500 KHR after the 50% coupon and the rating screen.
    02 / 04 · Rider app

    From finding a driver to rating them. Each trip state has one clear message, and the fare at the end shows the coupon as its own line.

    The trip states, the payment summary and the rating.

  • The Btaxi driver app in English, in one phone: a ride offer with a 30-second Accept, then Go to pickup, I've arrived, Rider picked up, Start trip, Arrived and Payment received, ending on Trip completed.
    03 / 04 · Driver app

    One button per step. Drivers work with one hand on a budget Android phone, so every step of a trip is a single large button at the bottom.

    The offer, the eight trip steps and the cash confirmation.

  • The Btaxi driver wallet in English, in one phone: 40,000 KHR chosen, the account number copied, Top up, the Request received dialog, then the top-up history with the new request pending.
    04 / 04 · Driver app

    Top up by bank transfer. The driver picks an amount, copies the account, transfers with their phone number in the note, and waits for an admin.

    The wallet, the transfer details and the pending state.

Profile,
documents, then review.

Driver sign-up

A new driver fills in a profile, uploads the ID, licence and vehicle papers, can add a referral, and waits for an admin to approve them.

Four Btaxi driver sign-up screens in English: the personal details form, the vehicle documents form, the optional referral code, and Your profile is under review

One admin behind both apps.

Admin web

Top-ups, drivers, rides, fares and coupons are run from one web admin. Captured from the live build, shown in English with demo data.

The Btaxi admin in English, Top-up requests: totals for pending (5, 760,000 KHR), approved today, this month and in total, then five pending requests from drivers with mobile, amount, time and Approve and Reject buttons.
01 / 06 · Admin web

Approve a driver's top-up

Every bank transfer a driver reports waits here, with the amount and the time, until an admin approves or rejects it.

  • The Btaxi admin in English, Top-up requests: totals for pending (5, 760,000 KHR), approved today, this month and in total, then five pending requests from drivers with mobile, amount, time and Approve and Reject buttons.
    01 / 06 · Admin web

    Approve a driver's top-up. Every bank transfer a driver reports waits here, with the amount and the time, until an admin approves or rejects it.

    The approval queue, its tabs and the totals above it.

  • The Btaxi admin in English, All drivers: ten drivers with phone, name, address in Phnom Penh, number of rides and a status of Approved, Pending or Locked.
    02 / 06 · Admin web

    Approve new drivers. Every driver with their rides and a status: approved, waiting for review, or locked.

    The driver list and its statuses.

  • The Btaxi admin in English, Ride requests: ten rides with rider, driver, ride type, fare in KHR and a status of Driver arrived, Completed or Cancelled, with search, Export and Filter.
    03 / 06 · Admin web

    Every ride in one list. Rider, driver, ride type, fare and status for every booking, with search, filters and export.

    The ride list and its status labels.

  • The Btaxi admin dashboard in English: drivers online, active rides, completed rides, total approved top-ups and pending top-ups, then the queue of five top-ups waiting with Approve and Reject.
    04 / 06 · Admin web

    What needs attention first. Drivers online, rides in progress, money approved and the top-ups still waiting, on the first screen an admin sees.

    The dashboard cards and the top-up queue on it.

  • The Btaxi admin in English, Services: Tuktuk, Sedan and SUV with seats, minimum fare, distance included, fare step and price per step in KHR.
    05 / 06 · Admin web

    Fares per ride type. Each ride type has its seats, a minimum fare, a distance included and a price for every 100 m after that.

    The service table that sets the prices the rider app shows.

  • The Btaxi admin in English, Coupons: seven codes including BTAXI50 at 50%, each with a title, a maximum number of users, dates it is valid and an On or Off status.
    06 / 06 · Admin web

    Coupons with limits. Each code has a discount, a cap on users and the dates it is valid. BTAXI50 is the code used in the rider app.

    The coupon list and its form.

One system,
five scripts.

Design system

Semantic colours, responsive type for the app and the admin web, and a font-family variable per language: Manrope for English and Vietnamese, Noto Sans Khmer for Khmer, and Noto for Chinese, Japanese and Korean.

The Btaxi variables from the Figma file, drawn like Figma's variables panel in dark mode: 33 semantic tokens for background, text and actions aliasing 60 primitives in teal, yellow, neutral and red ramps; responsive type sizes for mobile and web; and the font-family by language: Manrope, Noto Sans Khmer, Noto Sans SC, Noto Sans JP and Noto Sans KR.

I build with an AI agent.

How I build

I don't hand-write the code. I write the spec and the rules, the agent writes each change, and nothing ships until it passes my tests.

  1. 01SpecI define what gets built: the screens, flows and states for all three apps.
  2. 02Business rulesPricing, payments and permissions written down as rules the build has to follow.
  3. 03Build with the agentAn AI agent in Cursor writes each change and opens a pull request. The contract devs build against the same spec.
  4. 04Agent-assisted QAI test each build against my rules, with an AI agent helping to check behaviour.
  5. 05FixAnything that breaks the spec goes back with the correct logic written out.
  6. 06ShipA backend developer merges it, it deploys to staging on its own, and a smoke test checks it.

54 test cases between the rules and the release.

Run in Notion

Specs, tickets for the devs and the agent, and every test case live in one Notion hub. A change only moves on when its test case passes.

A sheet rebuilt from Hy's Notion hub for the build: the release pipeline Build, Internal QA, Client UAT passed on 7 Oct 2026, Sign-off as the current stage, Go-live as the client's decision; 54 test cases with 52 passing and 2 not applicable, broken down by module and by phase; and the five steps a change goes through.
Rebuilt from my Notion

Three months,
written down.

From the build log

Counted from my Notion logs, July to October 2026.

130updates done across the rider app, the driver app and the backend
13blocking bugs fixed in the backend
52/54test cases passing, the other 2 not applicable
6languages for push messages

One row per change,
in four logs.

The log itself

Backend, rider app, driver app and admin web each keep their own log: what changed, its priority, the files, the branch and whether it passed. My notes are in Vietnamese, the working language of the team.

Screenshots of Hy's Notion update logs for Btaxi, in dark mode, with code links blurred. Backend: about twenty tickets, almost all Done, with priority P0 to P2, type Fix, Logic or UI and who checked them. Then the rider app log, the driver app log and the admin web log, each a long table of dated rows marked Done.
Screenshots from my Notion · links blurred

A coupon that replaced the fare.

Caught in QA

Because I owned the pricing rules, I could see the build breaking them, write out the correct logic and get it fixed before handoff.

After the fix, per the rule: base fare as input, the coupon applied to the base fare, and a correct final price. Beside them the rider app in English with Coupon applied: 50% off, and each ride at half its base fare: Tuktuk 10,500 KHR from 21,000, Sedan 20,000 from 40,000, SUV 25,500 from 51,000.
Build as delivered, what the spec did not allow: three greyed steps, base fare as input, a bug where the coupon overwrites the base fare, and a wrong final price as output. Beside them a warning: coupon overwrites the base fare, wrong final price.
Build as deliveredAfter the fix, per the rule

Three bugs,
traced to where they started.

Root cause, not patch

When a ride failed, the ticket only closed once the cause was found, the data was repaired and a fresh test passed.

Backend bug traces3 runs
    1. SymptomRiders were told no drivers were available, even with drivers online.
    2. Root causeBooking saved the order, then called a live-update service that had been deleted, and broke. Each failure left a driver stuck as busy.
    3. FixThe backend now carries on when that service fails, and 6 stuck records were repaired.
    4. ProofA smoke test on staging passed.

When the happy path breaks.

The Btaxi verification code screen in English with all six boxes outlined in red and a Resend link
01 / 05 · Rider app

A wrong verification code

A wrong code turns every box red and offers Resend, instead of a message the rider has to read.

  • The Btaxi verification code screen in English with all six boxes outlined in red and a Resend link
    01 / 05 · Rider app

    A wrong verification code. A wrong code turns every box red and offers Resend, instead of a message the rider has to read.

    The error state of the code entry.

  • The Btaxi ride choice in English with a red Invalid coupon code. message ringed, and the base fares unchanged
    02 / 05 · Rider app

    A coupon that doesn't apply. An invalid code says so at the top and leaves the base fares as they were.

    The error message and the unchanged price rows.

  • The Btaxi cancel sheet in English: Tell us why you're cancelling the ride, with five reasons, Go back and Cancel ride
    03 / 05 · Rider app

    Ask why, in one tap. Cancelling asks for one reason from a short list, with Go back as the bigger button.

    The cancel sheet and its reasons.

  • The Btaxi driver wallet in English: Top-up requested, please allow 3 to 4 hours, and the newest 40,000 KHR request marked Pending, ringed
    04 / 05 · Driver app

    A top-up waiting for an admin. Until an admin approves it, the request shows as Pending at the top of the history, with the wait time above.

    The pending state and the history labels.

  • The Btaxi driver home offline in English, with today's earnings and balance, and No rides yet under today's activity
    05 / 05 · Driver app

    A new driver's first day. Offline with no rides, the home still shows earnings and balance, and says there are no rides yet.

    The empty state of the driver home.

What Btaxi taught me

The spec is the product.

The devs and the AI agent only build what I actually write down. When I wrote the logic tightly, the build came back clean. When I left a rule a little fuzzy, QA is where it came back to bite me. So writing the rules is the real work, not the warm-up.

Lessons
  • Invest selectivelyReusing infrastructure freed design time for the parts that build local trust.
  • Script is a technical problemKhmer support meant testing layout and rendering on budget Android, not just translating.
  • Admin risk is product riskThe biggest blocker wasn't design or code. It was paperwork: the Apple Developer account and the business licence the SMS sender needs.
Want something like this?

A multi-app MVP, scoped piece by piece.

Three connected apps are priced by what each one needs. Pick the pieces, and I send a written proposal within 48 hours of our call.

A build like this: multi-app, priced after a scoping call

More work

All work
Start a conversation

Have an app idea and a messy brief? Let’s sort out the rules first.