All case studies
Marketplace

AYH Market

A Khmer-first marketplace that put escrow, chat and search behind a single mobile app.

Engagement
Cambotix product
Industry
Retail & Marketplace
Year
2026
Our responsibility
Product architectureFlutter buyer & seller appsNestJS APIAdmin portal

The challenge

Cambodia's online selling happens across Facebook groups, Telegram channels and one dominant classifieds site. None were built mobile-first or held money in escrow. Buyers had no protection, sellers had no storefront, and every transaction depended on trusting a stranger's screenshot.

Our approach

We treated escrow as the product, not a feature. The catalog, chat and search all help two strangers reach the point where money can move safely. That framing decided the architecture: a wallet ledger at the core, with the marketplace surfaces built around it. The buyer and seller apps share one Flutter codebase with role-scoped navigation, which kept two products moving at the cost of one.

What it had to achieve

  • Give buyers a reason to trust a stranger's listing without meeting in person
  • Let a seller list, chat and get paid without leaving their phone
  • Support electronics, fashion, groceries, vehicles and services in one catalog
  • Work in Khmer as the primary language, not as a translation layer

Architecture

The decisions that made the rest possible.

01

Append-only wallet ledger

Escrow balances are derived from an immutable transaction log rather than stored as a mutable number. A failed payout can never silently corrupt a balance, and every cent is auditable back to its origin.

02

WebSocket chat separated from the REST API

Buyer–seller messaging runs on its own socket gateway with Redis-backed presence, so a spike in chat traffic cannot degrade checkout or listing endpoints.

03

Khmer-aware search indexing

Khmer has no spaces between words, so standard tokenizers fail. Listings are indexed with a Khmer segmentation pass plus romanized fallbacks, letting shoppers find items whether they type Khmer or Latin characters.

04

One Flutter codebase, two audiences

Buyer and seller experiences share models, networking and design tokens. Only the navigation shell differs, which halves the surface area to maintain.

Built with
FlutterNext.jsNestJSPostgreSQLRedisWebSocket

What we delivered

  • Buyer app: browse, search, chat, order, wallet, order tracking
  • Seller app: listing management, order fulfilment, payouts, performance view
  • Next.js admin portal: moderation, category management, dispute handling
  • NestJS REST + WebSocket API with role-based access control
  • Escrow wallet with hold, release and refund flows
  • Real-time buyer–seller messaging with unread state and presence

Security & reliability

  • Role-based access control enforced at the API layer, not in the client
  • Escrow releases require an explicit state transition with no implicit payouts
  • Rate limiting on listing creation and messaging to blunt spam campaigns
  • Uploaded media served from object storage with signed, expiring URLs

Outcomes

What changed once it was live.

  • Buyers and sellers transact without either party trusting the other first
  • Sellers run a full storefront from a phone, with no desktop step
  • Moderators handle disputes from one queue instead of scattered chat threads
  • Adding a product category is a configuration change, not a release

What we would do differently

Every project teaches something. Publishing it is how you tell whether a team is reflecting or just selling.

  • Khmer text search is the hard part of a Cambodian marketplace, not payments. We should have committed to a segmentation strategy in week one instead of retrofitting it.
  • Sharing one Flutter codebase across buyer and seller paid for itself, but only because we drew the boundary at the navigation shell early. Later would have been a rewrite.

Let's find out if this is worth building.

A 45-minute discovery call, free. You describe the problem, we tell you honestly what it takes, what it costs, and whether you should build it at all.