Skip to content
Huy Vo
Side projects

Side project · CS2 skin marketplace · web, admin, API

POLG

A Vietnamese marketplace for CS2 skins: live prices in đồng, exact listings by float and stickers, the price locked at confirmation, and an admin for orders, pricing and rates.

Screen recording

Role
Solo, AI-assisted
Year
2026
Platforms
Web · Admin · API
Stack
  • Nx
  • Next.js 16
  • NestJS 11
  • MongoDB
  • Redis
  • Better Auth

Buying CS2 skins in Vietnam usually means chatting with a seller and trusting a quoted price. I wanted a proper storefront in đồng: real listings, prices that can't silently change at checkout, and an admin that runs orders without spreadsheets.

My part. All 100 commits, built in four weeks (Apr–May 2026): web, admin, API, ops.

At a glance

  • 100

    commits in four weeks, solo

    Source: git

  • 1%

    price-drift tolerance before re-confirming

    Source: price policy

  • ⌘K

    fuzzy search across every variant

    Source: web app

What I built

Item pages that answer the real question

Sell and buy price, liquidity, other variants, and live listings with float bar, paint seed, Doppler phase and applied stickers, so a buyer can add one exact skin to the cart.

Sell listings for AK-47 Neon Revolution (Field-Tested): each row has a float bar with a marker on the wear scale, the exact float and paint seed, applied stickers shown as small sticker art with their condition percentage, the price in đồng with the seller's handle, and a gold Mua button.

Price lock with inline drift

Instead of a dead-end error, the confirm dialog shows the old and new price and the buyer re-confirms in one click. Exact listings never drift.

The order confirm dialog after a price change: a gold notice that the market price moved since the cart was viewed, the AK-47 line with 2.885.922 đ struck through and 2.952.520 đ marked Tăng, the Butterfly Knife listing with its float bar unchanged at 61.280.700 đ, the new total and the Đặt ở giá mới button.

Run like a product

An admin with KPIs, orders with per-item float and stickers, staff, price overrides, versioned exchange rates and an audit log, plus alerting, backups and push-to-deploy.

The admin dashboard: eight KPI cards (orders and GMV for 7 days with sparklines and change versus the previous week, average order value, completed orders, cancellation rate, orders in progress, new customers, and the price-feed status showing Healthy), above a 7-day chart of daily order counts as bars and revenue as a line.

Architecture

STOREFRONT · NEXT.JS 16ADMIN · NEXT.JS 16API · NESTJS 11DATA & UPSTREAMMarket · cartSWR · ⌘K searchBack officeorders · prices · ratesAuthBetter Auth sessionsCataloguegoods · listingsCart · ordersre-price · 1% driftTwo-layer cacheLRU → Redis SWRPricingmarkups · VND ratesMarket feedqueue · pre-warmerDashboard · auditKPIs · audit logAlerting5xx · client errorsMongoDBMongooseRediscache · locksMarket dataexternal feedRESTRESTTHROTTLED
A solo Nx monorepo: a Next.js 16 storefront and a Next.js 16 admin call one NestJS 11 API over REST. It keeps orders and the audit log in MongoDB, caches the market feed in an in-process LRU over Redis and throttles every upstream call through a queue.
  • Components:
    • Storefront · Next.js 16: Market · cart (SWR · ⌘K search), built by me (solo)
    • Admin · Next.js 16: Back office (orders · prices · rates), built by me (solo)
    • API · NestJS 11: Auth (Better Auth sessions), built by me (solo)
    • API · NestJS 11: Catalogue (goods · listings), built by me (solo)
    • API · NestJS 11: Cart · orders (re-price · 1% drift), built by me (solo)
    • API · NestJS 11: Two-layer cache (LRU → Redis SWR), built by me (solo)
    • API · NestJS 11: Pricing (markups · VND rates), built by me (solo)
    • API · NestJS 11: Market feed (queue · pre-warmer), built by me (solo)
    • API · NestJS 11: Dashboard · audit (KPIs · audit log), built by me (solo)
    • API · NestJS 11: Alerting (5xx · client errors), built by me (solo)
    • Data & upstream: MongoDB (Mongoose)
    • Data & upstream: Redis (cache · locks)
    • Data & upstream: Market data (external feed)
  • Connections:
    • Storefront · Next.js 16 to API · NestJS 11: REST
    • Admin · Next.js 16 to API · NestJS 11: REST
    • API · NestJS 11 to MongoDB
    • Two-layer cache to Redis
    • Market feed to Market data: throttled

Key decisions

  1. Re-confirm instead of reject

    The server rejects only price drift above 1%, and the buyer re-confirms the new price in one click instead of starting checkout over.

    Problem, choice and trade-off: Re-confirm instead of reject
    Problem
    Skin prices move while a buyer fills in checkout, and a hard 409 'price changed, back to cart' lost the sale.
    Choice
    The server re-prices every line at submit and rejects only drift above 1%; the confirm dialog shows the old price struck through next to the new one and re-confirms in one click. Exact listings are priced from the cart and never drift.
    Why
    The buyer still never pays a price they did not see, but a small move costs one click instead of the whole checkout.
    Trade-off
    Generic items and exact listings now follow two pricing paths that both need tests.
  2. Cache in two layers, fetch once

    An in-process LRU over a Redis stale-while-revalidate layer, with single-flight at both levels, so a burst of buyers never becomes a burst upstream.

    Problem, choice and trade-off: Cache in two layers, fetch once
    Problem
    The upstream market feed is slow, rate-limited and occasionally unavailable, and popular item pages were requested by many buyers at once.
    Choice
    An in-process LRU in front of a Redis stale-while-revalidate layer, with single-flight at both levels, a queue that throttles upstream calls, and an opt-in leader-elected pre-warmer for the most-opened pages.
    Why
    Stale-but-fast beats an error page for prices that are re-checked at checkout anyway, and single-flight stops a burst from turning into a burst upstream.
    Trade-off
    Prices on browse pages can lag by the cache window; only checkout is authoritative.

Credit. Solo, built with AI assistance. Screens are from a local run with fictional customers, sellers and orders. Not affiliated with Valve: Counter-Strike 2, StatTrak™ and all item art belong to Valve.

Next side project

GlowTrack

AI skincare tracking · mobile + ML backend