Hashmato: multi-tenant cloud POS
Payment, delivery, pricing, and ordering services for a database-per-tenant POS, where every tenant brings its own providers.
- Company
- HashmatoCloud POS for F&B and retail operators, part of RBS’s hospitality portfolio (4,800+ properties, 35+ countries).
- Role
- Software Engineer II
- Period
- Sep 2025 – Mar 2026
- Location
- Singapore (remote)
Original reconstruction for this portfolio.
Overview
Hashmato is a cloud POS for food-and-beverage and retail operators. I worked on its backend: the payment gateway, the food-delivery integration service, the shared data-access layer, a pricing engine, and a stored-value ordering backend.
Every one of these runs per tenant, and each tenant can be configured differently.
Context and problem
In a multi-tenant POS, tenants don’t share a payment provider, a delivery partner, or a price list. One tenant takes Stripe, another PayNow QR. One sells on Grab, another on Deliveroo.
Money and orders also leave no room for partial failure. Webhooks can arrive more than once, partners retry, and refunds have to reconcile.
My role and ownership
What I built
- Architected a multi-provider payment gateway: Stripe, Omise, PayNow QR, or an in-house gateway behind one adapter interface, with HMAC-verified webhooks and BullMQ retries.
- Built a food-delivery integration service connecting POS menus and orders to Deliveroo, Grab, and Delivery Hero: menu sync, order ingestion, store status, and OAuth2/HMAC webhooks.
- Designed the shared data-access layer behind 30+ domain modules of a database-per-tenant PostgreSQL/TypeORM platform: nested-relation filters, transactional bulk upserts, streaming export, and queued Excel import.
- Built a context-aware pricing engine from scratch (brand, location, channel, and timezone schedules), then removed an N+1 bottleneck by batching per-item override lookups into one query per page.
- Delivered a stored-value ordering backend: cart and combos, prepaid wallets, auto-recharge, ledgered refunds, and partial cancellations, using PostgreSQL transactions and atomic Redis Lua queue numbering.
- Extended Kubernetes delivery for 7 NestJS microservices (Helm, helmfile, SOPS, Traefik) and containerized 3 new services with multi-stage Docker builds and GitHub Actions publishing to GHCR.
Challenges
Many providers, one checkout
Each tenant can run a different payment provider, and the POS shouldn’t need to know which one.
Partners that speak different protocols
Delivery platforms each have their own menu formats, order flows, store status, and webhook security.
Prices that depend on context
The same item can cost different amounts by brand, location, channel, and time of day in the tenant’s timezone.
Money that must always reconcile
Wallets, auto-recharge, refunds, and partial cancellations all touch balances that must stay consistent.
Design and architecture decisions
Adapters behind one interface
Payment providers and delivery partners each implement a single interface. Webhooks are verified with HMAC (and OAuth2 where partners require it) and retried through BullMQ.
Database per tenant, shared access layer
Tenants keep separate PostgreSQL databases, while 30+ domain modules share one data-access layer for filtering, bulk upserts, export, and import.
Batch the lookups
The pricing engine’s first version looked up overrides per item. Batching them into one PostgreSQL query per page removed the N+1.
Transactions and atomic counters
Ordering uses PostgreSQL transactions for balances and ledgered refunds, and Redis Lua scripts for atomic queue numbers.
Selected implementation details
Loading the interactive reconstruction…
Payment gateway
Stripe, Omise, PayNow QR, and an in-house gateway behind one adapter, with HMAC-verified webhooks and BullMQ retries.
Delivery integrations
Deliveroo, Grab, and Delivery Hero: menu sync, order ingestion, store status, OAuth2/HMAC webhooks.
Delivery pipeline
7 NestJS microservices on Kubernetes with Helm, helmfile, SOPS, and Traefik; 3 new services containerized with GitHub Actions to GHCR.
Outcomes
- 4payment providers behind one adapter
- Stripe, Omise, PayNow QR, and an in-house gateway, chosen per tenant.
- 30+domain modules on one data-access layer
- Database-per-tenant PostgreSQL with TypeORM.
- 1 queryper page for price overrides
- Replaced an N+1 lookup in the pricing engine’s first version.
- 7NestJS microservices on Kubernetes delivery
- Extended with Helm, helmfile, SOPS, and Traefik.
Figures come from my resume or from measuring the shipped product. Where a number describes the product or the team rather than my work, the context says so.
Technologies
- NestJS
- TypeScript
- PostgreSQL
- TypeORM
- Redis
- BullMQ
- Docker
- Kubernetes
- Helm
- GitHub Actions