DeltaHi Points & Rewards
An employee engagement platform where staff join activities, earn points and redeem rewards. I designed the points and rewards service.
Points and rewards that stay correct when many employees redeem at once.
- Role
- Designed the points service; built admin features
- Ownership
- Owner of the points and rewards service
- Core stack
- TypeScript · Nuxt.js · Vue.js · NestJS · PostgreSQL
Employees earn points from activities and content and redeem them for limited stock. Two people redeeming the last item at once must not both succeed.

What I built
I designed and built the Points Management service and built features in the shared admin and API.
- Designed redemption as one database transaction: lock the reward and balance rows, check eligibility, burn points, write history and adjust stock, then commit or roll back everything
- Made point earning extensible with a Strategy + Factory pattern covering earning channels such as activities, content, refunds and app shares
- Added a daily expiry job that clears expired balances and writes an
EXPIREhistory entry - Built admin features in Nuxt 3: reward orders, stock management, per-action permissions (create, edit, delete, export), debounced search and Excel exports
- Added Thai word segmentation to search in the main API
How it fits together
Employees use a Flutter app. An AdonisJS API handles the wider employee platform and syncs staff from the company's SQL Server. The NestJS points service owns balances, rewards and redemption history in its own PostgreSQL database, and pushes updates to the admin over Socket.IO.
Outcome
Points and stock stay consistent when many employees redeem at once, and every earn, burn and expiry is recorded.
Deep diveCore feature walkthroughAn interactive flow of the hardest workflow, step by step.
How the main product workflows operate
A redemption coordinates balance, order history and inventory inside one transaction
The point-management service treats redemption as a multi-record operation. It locks the selected reward, validates eligibility, burns points, creates a waiting fulfilment record and commits only when every database step succeeds.
NestJS · TypeORM · PostgreSQL · Decimal arithmetic
Balance and point cost avoid floating-point arithmetic, and every earn or burn writes a separate history record.
A pessimistic write lock is the concurrency boundary around validation and redemption.
I built redemption as one transaction: lock the reward, check eligibility, burn points, write history, adjust stock. Any failure rolls every write back, so a member never loses points without getting an order.