Tales of BOS
Custom headless storefront for a faith-driven luxury fashion label

Overview
A production e-commerce platform for a faith-driven Christian luxury fashion brand: a fully custom Next.js 16 storefront on a headless Medusa v2 commerce core, with NGN-first multi-currency pricing, Paystack checkout, a full admin back-office, and hard correctness guarantees around money and inventory.
My role
Sole builder on a client project. Scope covered end-to-end: architecture and ADRs; the 100% custom Next.js 16 storefront (RSC + Server Actions); the Medusa v2 backend with custom Store API routes, security middleware, subscribers and a Resend email provider; the shared Money value object and design-system package; Paystack checkout and money/inventory correctness; SEO/analytics/observability; and production deployment/ops (Vercel + a self-hosted VPS).
The problem
A Christian luxury fashion brand needed a production online store that a template builder can't express: bespoke, editorial, mobile-first, with collections that each carry a faith story, gifting/personalisation, and appointments. It also had to be correct where money leaks (multi-currency pricing with no float money, .99 charm prices per currency, and inventory that cannot oversell) while launching lean in Nigeria/NGN first and leaving room to scale to UK/EU/US. Hand-building a commerce engine risks exactly those money/inventory bugs; off-the-shelf builders don't model the brand.
The solution
A headless split: Medusa v2 owns the correctness-critical machinery (cart, transactional inventory/reservations, orders, per-currency price lists, tax, refunds) while a fully custom Next.js 16 App Router storefront (RSC-first, React 19 Server Actions) renders the brand over the Store API: no Medusa starter UI. Brand-specific capabilities were added without forking the schema: faith-story content via collection metadata, gift curation via native product tags, gift-wrap/message via line-item metadata. Money runs through one integer-minor-unit Money value object (charm pricing, largest-remainder allocation; FX never at checkout), and a thin NGN/Paystack slice was shipped to production.
Key features
- Custom Next.js 16 storefront (RSC + Server Actions): faith-story collection pages, PDP with an invalid-combo-aware variant selector, server-authoritative cart, and a two-step checkout (the brand experience is 100% hand-built, not a Medusa starter).
- Paystack (NGN) checkout with 7.5% Nigeria VAT: hosted fields only (server mints the access code, PCI SAQ A), verify-by-reference with a signature-verified webhook backstop, and a "finalizing" state that prevents a second charge if order completion fails after funds are captured.
- Accounts & auth: email/password + Google OAuth, soft email verification with an account-holder checkout gate, address-book CRUD and order history (backed by an IDOR fix on order reads and server-side tamper protection on the email_verified flag).
- URL-driven faceted search (department/collection/colour/size/price/availability with disjunctive live counts) plus a type-ahead overlay: an in-memory engine written against a stable contract so Meilisearch can drop in later with no UI change.
- Gift curation via product tags (for-her/for-him) with wrap + message propagating to the order, confirmation email, ops email and admin metadata; wishlist that stores handles in localStorage for guests, customer.metadata for members, and merges on sign-in.
- Central design system (packages/ui): brand tokens, mobile-first, and whole-app dark mode via a single CSS-variable token remap (no per-component work); SEO (Product/WebSite JSON-LD, dynamic sitemap, generated OG image), consent-gated PostHog, and env-gated Sentry.
Architecture & engineering
A two-runtime headless topology. The storefront runs on Vercel (RSC + ISR/generateStaticParams, tag revalidation, an unstable_cache catalogue layer that degrades to empty instead of crashing when the backend is down), talking to a Medusa v2 backend self-hosted on a Hostinger VPS (Node 22 via nvm, pm2 running the compiled server, nginx reverse-proxy + certbot TLS at api.talesofbos.com). Data plane: Supabase Postgres via the IPv4 session pooler; Upstash Redis for cache + admin sessions only, with the event bus and workflow engine deliberately left in-memory after serverless Redis stalled Medusa's BullMQ modules on boot (documented as single-instance-correct). A Turborepo monorepo keeps the React-19 web workspace isolated from the React-18 Medusa workspace (separate lockfiles) to avoid dependency conflicts. A shared Money value object (integer minor units, banker's rounding, deterministic largest-remainder allocation for correct partial refunds) is the single money primitive; custom Medusa middleware adds order-ownership enforcement, metadata-tamper protection, and per-IP rate limiting.
The hardest problem
Every Paystack payment was failing in test: 7.5% VAT applied to .99 charm prices produced sub-kobo minor-unit totals (e.g. ₦196,187.4785) and Paystack rejects non-integer amounts. It was fixed durably with a pinned pnpm patch adding Math.round to the community provider, which then silently regressed in production because the standalone build drops patched dependencies, so the deploy script had to be taught to re-propagate patches before install. Separately, Medusa v2 OOM'd on 512MB tiers (it needs ~1-2GB), forcing a migration off the PaaS to a 7.8GB VPS with pm2 + nginx.
Results
Deployed live to production: the storefront on Vercel and the Medusa backend/admin self-hosted on a VPS (api.talesofbos.com). The full paid-checkout flow (Nigeria region + 7.5% VAT), branded order emails, and Google sign-in were verified end-to-end across 8 faith collections and 12 products (117 NGN variants). Built in roughly two weeks, documented across 23 architecture decision records.
Key learnings
Headless commerce (Medusa) buys correct, battle-tested money/inventory primitives, but moves the cost to integration and ops: two runtimes, CORS/secret coordination, patch propagation into the standalone build, and validating a community payment provider in sandbox. Investing early in one Money value object and treating the payment verify/webhook as the source of truth caught real defects (sub-kobo VAT, a double-charge on failed completion) that float math and redirect-trust would have shipped. And a token-driven design system paid off: whole-app dark mode fell out of a single CSS-variable remap instead of touching ~43 components.
Want to see it in action?
Explore the live product, or reach out to talk through the build.