Primsell NFT E-Commerce
Node.js Business Logic on PostgreSQL — Checkout, Stripe Connect & Royalty Ledger
Role: Main full-stack developer in a team of 3–5: backend business logic in Node.js on PostgreSQL (Express/Sequelize core API, NestJS payment service), the blockchain background jobs and the React apps. Mentored 2 junior engineers.
Main full-stack developer on a B2B NFT-commerce platform: Node.js business logic on PostgreSQL (Express/Sequelize core API, NestJS Stripe Connect payment service), blockchain background jobs on Polygon, and React apps for brands, checkout, redeem and venue verification sharing one UI kit and API client. Mentored 2 junior engineers.
Key Features
- Express + Sequelize core API on PostgreSQL (~79 REST endpoints, JWT + ACL roles, validation and rate limits per route)
- NestJS + MikroORM payment service on Stripe Connect: per-brand accounts, application fees, signed webhooks, decimal.js money math
- Checkout overselling fixed with SELECT … FOR UPDATE on the campaign row and atomic SQL counters
- Royalty ledger fed by an OpenSea/Rarible resale indexer (checkpoints, overlap re-scan, dedup) with confirmation-gated withdrawals
- Idempotent burn-to-redeem on the transaction hash, plus a recovery job for interrupted redeems
- State-machine workflow engine for orders, ledger operations and contract deployment; cron jobs with a DB-backed job log
Tech Stack
Backend
Frontend
Payments & Blockchain
Infra
Challenges & Solutions
Overselling Under Concurrent Checkout
Order creation read the campaign, checked stock in application memory, then wrote the new booked count back. Two concurrent buyers could both pass the check, one increment was lost, and more NFTs were booked than existed.
One READ COMMITTED transaction takes SELECT … FOR UPDATE on the campaign row, checks stock under the lock, inserts the order and bumps the booked count with an atomic SQL update. Release and booked → bought transfers are atomic updates too, and available stock is a derived value that cannot be written directly.
Late Payments vs Order Expiry
Orders hold stock for a limited time. A buyer who paid just after the reservation expired could be charged for an order the system had already released, and amounts computed as floats broke on prices like 19.99.
The expiry job asks Stripe for the PaymentIntent status before expiring an order: paid orders complete, the rest release stock in bulk and cancel their intent so they can never be charged. Money moved to decimal.js minor units, with the platform fee rounded down so it never exceeds the percentage.
Royalty Ledger From On-Chain Resales
Brands earn royalties when their NFTs resell on OpenSea or Rarible, and must be able to withdraw them — without missing events near the chain head or counting a sale twice.
A resale indexer reads block windows from a stored checkpoint, re-scans an overlap, halves the range on provider errors and dedupes by transaction. It feeds a per-brand, per-currency ledger of signed operations whose lifecycle runs on the workflow engine, with a balance guard on withdrawals and N block confirmations before completion.
Redeems That Must Not Be Lost
A buyer burns the NFT on-chain to get a real-world code. If the browser closed after signing, the burn happened but the backend never heard about it.
The client records a redeem intent before signing. The redeem endpoint verifies the receipt and the decoded event and is idempotent on the transaction hash, and a recovery job scans chain events from the intent's block to complete redeems whose HTTP call never arrived.
Brand ↔ Customer CRM Mapping
Brands must see only their own customers, while one wallet can buy from many brands — and the mapping had to cover past purchases too.
A many-to-many table with a composite key, filled by a BEFORE INSERT trigger on purchases with ON CONFLICT DO NOTHING, plus a separate idempotent backfill migration for the history.