Headless e-commerce for a natural-cosmetics brand — B2C + B2B, an AI selection assistant, Polish payments, and Instagram automation. Built from scratch, architecture to deployment, on a reusable white-label foundation.
Lunula Botanique is a "biocompatible skincare" brand — cosmetics whose ingredients are recognizable to the skin. The catalog is unusual for a typical store: alongside physical products (oils, serums, creams, ritual soaps) there are workshops and digital products, and sales run on two tracks — retail (B2C) and wholesale to salons (B2B).
Off-the-shelf platforms (Shopify, WooCommerce) couldn't handle these requirements without compromises and costly plugins. We chose a headless architecture — a decoupled Medusa.js v2 backend and a Next.js 15 storefront — for full control over business logic, design, and integrations. As a bonus, the whole thing takes shape as a white-label-ready template for future brands.
Some of the store's strongest features weren't in the brief — I proposed them, and the client adopted them: the AI selection assistant, the bidirectional ingredient lexicon, and the Instagram comment-to-DM automation. Not "ticking off a spec," but product thinking — pointing out where technology would genuinely lift sales, education, and acquisition, then delivering each idea end to end.
Two pricing models in one store — gross prices for retail, net prices for salons (B2B), with a separate wholesale price list.
The Polish payments market — a native integration with the Paynow gateway (BLIK), not a generic Stripe setup.
Content as a differentiator — the brand is built on ingredient education; the store needed an ingredient lexicon linked both ways with products (and the SEO value that comes with it).
Clean migration & domain cutover — replacing the brand's existing WordPress site on the same domain, seamlessly, with SEO rebuilt properly on the new platform.
Help with choosing — a knowledge-driven catalog (skin type, concerns, face vs. body) where the customer needs guidance from need to product, not a wall of categories.
Acquiring sales from Instagram — a comment under a post should automatically trigger a product link sent in a private message.
Brand scalability — a foundation that can be quickly "re-skinned" for another brand.
Brand-specific logic lives in custom Medusa modules, keeping the platform core clean and upgradable. Nine building blocks:
A "Salon/B2B" customer group with a separate price list. Price presentation adapts to context — gross for retail, net for businesses — with correct VAT breakdown in cart and checkout, and customer-type detection on the API side. Salons get a dedicated "For Salons" landing page with a retail-vs-wholesale price comparison and a partner CTA.
A custom Paynow integration (HMAC verification, idempotency keys, webhooks, status polling) supporting inline BLIK with no redirect, plus classic transfer/card. On top: InPost parcel-locker selection via Geowidget, in-person pickup, and free shipping above a threshold with a progress-bar nudge.
A custom data module: every ingredient has its own page (name, Latin name, properties, source) and a list of products that contain it — with add-to-cart right there. Product pages link back to the lexicon. One coupling that works as an SEO hub, an education tool, and natural cross-sell at once.
A multi-step wizard asks about skin type, concerns, and area, then uses the Claude model to pick from the store's real catalog — grounded in brand philosophy, constrained by hard rules (face vs. body, exactly three items, advisor's tone). Recommendations never hallucinate products and lead straight to the cart.
The most elaborate module — a full "comment a keyword, get a link in a message" flow:
Brand (name, logo, taglines), colors (CSS variables), typography, and feature set are driven by a single config and feature flags (B2B, subscriptions, workshops, IG bot, newsletter). Spinning up another store under a different brand is a config change — not rewriting code.
Hosted on Railway, media on Cloudflare R2. Backend-driven revalidation: a subscriber listens to Medusa events and refreshes the storefront cache — admin changes appear almost instantly, with no rebuild. Analytics via GA4 with Consent Mode v2 and a custom GDPR banner; transactional email through a custom Resend module.
A dynamic sitemap.xml (products, categories, collections, lexicon), JSON-LD structured data (Organization, WebSite, Product, BreadcrumbList), and dynamic metadata + OpenGraph images per page. The ingredient lexicon adds valuable, indexable content around ingredient keywords.
The new store replaced the brand's previous WordPress site on the same domain — a clean DNS cutover, managed SSL, www→apex normalization, and SEO built right from day one. Cloudflare also serves as the infra layer: DNS, CDN/proxy, R2 object storage, and Email Routing for the brand inbox.
A "magic link" ties it together: a ?discount=CODE URL (e.g. from the bot's DM) auto-applies the code in the cart and carries UTM params straight into analytics.
| Frontend | Next.js 15 (App Router, SSR), TypeScript, Tailwind CSS, next-intl |
| Backend | Medusa.js v2, Node.js 22, custom modules (TypeScript) |
| Database | PostgreSQL |
| Payments & delivery | Paynow (BLIK + transfer/card, custom integration), InPost parcel lockers (Geowidget) |
| AI | Anthropic API (Claude) — recommendation engine for the selection assistant |
| Integrations | Instagram Graph API / Meta, Resend (email), GA4 + Google Consent Mode v2 |
| Infrastructure | Railway, Cloudflare (DNS, CDN, R2 files, Email Routing), backend-driven ISR revalidation, CI/CD via a deploy branch |
The brand got a store tailored to its sales model — combining retail and wholesale, an AI selection assistant, ingredient education linked bidirectionally with the store, Polish payments, and automated acquisition from Instagram — rather than a set of compromises around an off-the-shelf platform.
Thanks to the headless, modular approach, the business logic is tested, extensible, and resilient to core updates, and the whole architecture serves as a ready white-label foundation for future rollouts.
Whether it's commerce, AI, or a custom system — I build software that survives contact with reality. Drop me a line.