Skip to content
All work

Canten · Food & beverage · 2026

Canten

Online ordering, outlet POS and a 5×5 rewards matrix for a fresh sugarcane & coconut juice brand.

Role
Full-stack developer at Bloom IT Solutions — rewards engine, wallets, withdrawals, wallet checkout, POS-sales integration and their admin & customer UIs.
Platforms
Customer web · Outlet POS · Back office · NestJS API
Status
Live · actively developed
L2L1purchase5 × 5 · breadth-first · auto-placed at signup

income_ledger · append-only

  • purchasercredited
  • level 1credited
  • level 2credited
  • replayed eventignored

Illustration of the system — not a screenshot.

Breadth-first rewards matrix
5×5
Breadth-first rewards matrix
Backend domain modules
22
Backend domain modules
Test suites — MLM, wallet, payments
28+
Test suites — MLM, wallet, payments
Real-time WebSocket gateways
8
Real-time WebSocket gateways

Overview

Overview

Canten is a multi-outlet juice brand platform: customers order online, outlet staff ring up walk-in sales on a POS, and super admins run inventory, payments and payouts from a back office. I built the rewards layer — every customer, online or in-store, is placed in a 5×5 matrix and each purchase pays the buyer and up to five upline levels through an append-only wallet ledger.

The challenge

Canten sells online and across walk-in outlets, and wanted every customer rewarded wherever they buy — commissions to five upline levels, paid out to real bank accounts. With signups arriving concurrently and payment webhooks retrying, nothing could ever be placed twice or paid twice.

The approach

I built the rewards layer on a NestJS + Prisma monorepo: a breadth-first placement engine protected by row locks and database constraints, commission plans that admins configure instead of developers, and an append-only wallet ledger with idempotency keys. Online orders and POS sales emit the same events, so every purchase flows through one path.

Walkthrough

How it works

  1. 01

    A juice brand, online and in-store

    Customers order fresh sugarcane and coconut juice for delivery from their nearest outlet, while outlet staff ring up walk-in sales on a POS. My work was the rewards layer that sits across both — so every customer earns, wherever they buy.

    Canten customer ordering site
  2. 02

    Placement that's safe under load

    Every new customer is placed automatically in a strict breadth-first 5×5 matrix — no referral codes. Concurrent signups are serialised with row locks and a bounded retry, and the database itself rejects an impossible tree. Admins browse it as a live placement tree.

    5×5 matrix placement tree in the back office
  3. 03

    Commission plans, not hard-coded numbers

    Admins manage plans with a purchaser share and a share per level 1–5. Plans move through draft, active and retired, and a partial unique index guarantees only one is active.

    spec · 03

    Commission plans, not hard-coded numbers

    • ›DRAFT → ACTIVE → RETIRED
    • ›purchaser % + L1…L5 %
    • ›partial unique index: 1 ACTIVE
    • ›rates live in the DB, not code
  4. 04

    Every purchase pays exactly once

    Each purchase writes one immutable income row per beneficiary, keyed for idempotency — triggered by events from both online orders and in-store POS sales.

    spec · 04

    Every purchase pays exactly once

    • ›1 row per (purchase, beneficiary)
    • ›idempotency key
    • ›events: order.paid · pos.sale
    • ›replayed event → no-op
  5. 05

    A wallet that can't go negative

    Balance and reserved balance sit on an append-only ledger that records the balance before and after every movement. Admins see each customer's wallet, orders and tree placement in one place.

    Customer detail with wallet, orders and tree placement
  6. 06

    Payouts to real bank accounts

    Customers withdraw earnings to a saved bank account. Requests get sequence-numbered references and go through admin approve, fail or cancel flows with configurable rules.

    Wallet withdrawal requests and payout status
  7. 07

    Pay with wallet, atomically

    At checkout, one transaction creates the order, debits the wallet, marks it paid, records the payment and clears the cart — all or nothing.

    Product page with add to cart
  8. 08

    One Razorpay settlement path

    Checkout confirmation, webhooks and the pending-payment expiry job share a single idempotent settlement path that uses compare-and-set on payment status.

    spec · 08

    One Razorpay settlement path

    • ›compare-and-set on status
    • ›PAID · PENDING · NOT_PAID
    • ›REVIEW_REQUIRED
    • ›confirm = webhook = expiry job
  9. 09

    Walk-in sales count too

    An orchestrator joins in-store POS purchases to the same customer account, so counter sales earn the same rewards as online orders.

    Outlet counter-sale POS
  10. 10

    Numbers for HQ and every outlet

    The back office gets an executive view across outlets — revenue, orders, new customers and offline sales — while each outlet sees its own insights, including POS sales from a cached summary.

    Back-office executive dashboard

Every screen

Sample data · scroll → · click to enlarge

  • Back-office executive dashboard

  • Canten customer ordering site

  • Product page with add to cart

  • 5×5 matrix placement tree in the back office

  • Customer detail with wallet, orders and tree placement

  • Wallet withdrawal requests and payout status

  • Outlet insights dashboard

  • Outlet counter-sale POS

Built with

Stack

Backend
NestJSTypeScriptPrismaPostgreSQLRedisBullMQSocket.IOSwagger
Payments
RazorpayWebhooksAWS S3
Security
Argon2TOTP MFAHelmetRate limiting
Tooling
pnpm workspacesTurborepoDocker ComposeNginxJest
Web apps
Next.jsReactTailwind CSSTanStack QueryZustandRechartsMapbox

Open to full-time roles & select freelance projects

Need something like this?

Email

Local time

Giridih, IN · IST

Replies within 24 hours on weekdays