GTaugment AR
AR-powered merch catalogues · NestJS · Next.js · Prisma
Impact: Three payment gateways, three cloud storage providers, and three currencies behind a single subscription API — businesses onboard in NG/US/RU markets without code changes.
NestJS · Next.js 15 · TypeScript · Prisma · PostgreSQL · MUI · Redux Toolkit · Socket.IO · Cloudinary · AWS S3 · PayPal · Paystack · YooMoney · Docker


Problem
Small merchants and creators wanted product pages that felt richer than flat e-commerce listings — short demo videos, 3D views, scannable in-store QR codes — but every off-the-shelf path forced a trade-off. Shopify and similar platforms offered the storefront but no AR primitives; standalone AR tools offered the media but no commerce, payments, or analytics. Worse, the audience spanned Nigeria, the US, and Russia, so a one-payment-gateway-fits-all approach (the default for most SaaS) would lock out two of three markets at sign-up.
Approach
- 01
Modelled the AR album as a first-class entity, not a media attachment. Albums have their own ID space, view counters, ratings, embedded CTA buttons, and QR codes — so the same record can power an in-store scan, an Instagram link, and an in-app feed without duplicating logic.
- 02
Made the payment gateway a runtime decision, not a config flag. A user’s country drives currency, currency drives gateway (Paystack → NGN, PayPal → USD, YooMoney → RUB), and the subscription service hands the right adapter to the checkout flow — so adding a new market is one adapter, not a checkout rewrite.
- 03
Abstracted storage behind a single upload interface backed by a DB-stored provider setting. Ops can flip from Cloudinary to S3 to GCS by updating one row; the upload pipeline reads StorageSetting and dispatches accordingly. Kept the team from getting locked into Cloudinary’s pricing early.
- 04
Used JWT request-type tagging instead of separate token endpoints. One JWT structure carries a requestType (LOGIN, USER_VERIFICATION, BUSINESS_VERIFICATION, REQUEST_RESET_PASSWORD, RESET_PASSWORD) so the same auth guard handles every flow — fewer code paths, fewer ways to misroute a token.
- 05
Built the marketing site, customer app, and backend as three separable deployables. The Next.js marketing site ships independently from the customer-facing Next.js app and the NestJS API, so content changes do not require a backend deploy.
Outcome
- 01
Single platform serves NG/US/RU merchants natively — no "we do not accept your card" wall at checkout.
- 02
Album media stays portable: storage provider can be swapped without code changes, which decoupled vendor pricing risk from feature velocity.
- 03
AR album + QR pattern doubles as both an online product page and an in-store scan target, so one upload powers two distribution channels.
- 04
Led a CapacityDey team of 20 to ship API, customer app, and marketing site as three independently deployable surfaces.
Lessons
- 01
Make money flows pluggable from day one, even if you launch with one gateway. Retrofitting multi-currency, multi-gateway logic into a system already wired to Stripe is painful; designing the subscription/payment layer around a paymentGateway enum and country-derived currency from the start cost about a week and unlocked two markets.
- 02
Do not let your storage SDK leak into business logic. Wrapping Cloudinary/S3/GCS behind one uploadFile(file, path) interface kept the album, catalogue, and advertisement modules indifferent to where bytes actually live — and made the "what if Cloudinary doubles pricing" conversation a one-day migration instead of a quarter.
- 03
One JWT shape with a requestType discriminator beats five purpose-specific tokens. Every "send a token in an email" flow (verify, reset, invite) collapses into the same guard plus a switch — fewer endpoints to audit, fewer mistakes around token reuse.