Skip to content

4-layer headless architecture

Each layer with clear responsibility, dependency only on the layer below. Swap the UI without touching the cart. Swap the backend without rewriting providers.

Technical documentation

  1. Layer 4 - App / Storefront

    Next.js 15 app that composes the 3 layers into a real store. App router (dynamic routes via Supabase), middleware (auth/rate limit), CMS for visual editing, integrations with any payment gateway, SEO (sitemap, robots, metadata), Vercel deploy.

    • app router
    • middleware.ts
    • CMS
    • payments
    • sitemap/robots
    • Vercel deploy
  2. Layer 3 - UI

    Opinionated components (Tailwind + Radix). ~20 domain components (ProductCard, CartDrawer, ProductFilters, HeroCarousel, etc.) + primitives. Theme via HSL CSS vars compatible with shadcn.

    • ProductCard
    • CartDrawer
    • ProductGallery
    • ProductFilters
    • GlobalHeader
    • Footer
  3. Layer 2 - React Providers & Hooks

    Glue layer between headless clients and the UI. CartProvider, WishlistProvider, SupabaseAuthProvider, listing and auth hooks.

    • CartProvider
    • WishlistProvider
    • SupabaseAuthProvider
    • useCart
    • useWishlist
    • useProductsPage
  4. Layer 1 - Headless clients

    No React, no Next.js. Pure classes with injectable auth/logger/fetcher. Runs in any runtime (Node, edge, worker).

    • OdooHttpClient
    • ProductService
    • CartService
    • SalesService
    • AddressService

Design principles

What holds the libs' coherence together.

  • Headless by default

    No lib (except the React and UI layers) knows React, Next.js or any UI framework. Everything accepts fetch, auth, logger and storage as injected dependencies.

  • Explicit config

    No lib reads process.env directly. URLs, secrets and flags arrive via constructor. Eases tests and multi-env deployments.

  • Replaceable

    Each service is a class; the consumer can subclass it or swap with a mock in tests without touching the rest. No internal vendor lock-in.

  • Typed and tested

    TypeScript strict, ESM. Vitest tests cover pure helpers, HTTP client, cart, JWT, rate limit, storage. Green CI on GitHub Actions.

Typical data flow

From customer opening the store to confirmed order.

  1. 1

    Customer opens the storefront

    UI

    Next.js 15 SSR. Listing page fetches products from Elasticsearch via ProductService (server-side).

  2. 2

    Customer searches a product

    UI -> Headless

    Faceted search on Elasticsearch. Results with collapse by model, brands, categories, related products via Levenshtein.

  3. 3

    Customer logs in

    Auth

    SupabaseAuthProvider opens Supabase flow. Token returns to client + server. CartProvider syncs local cart with Odoo.

  4. 4

    Customer adds to cart

    React -> Headless -> Odoo

    useCart() calls CartService.addToCart(). Supabase token flows through to Odoo via OdooHttpClient. State updates in React.

  5. 5

    Checkout

    Headless -> Odoo

    AddressService fetches addresses. DeliveryCarriersService computes shipping. SalesService confirms order in Odoo. Native tax (NF-e/NFS-e).

  6. 6

    Payment and fulfillment

    Odoo

    Payment via Pix Cobrança / hybrid boleto / card (Odoo gateway). Webhook hits Odoo, releases fulfillment. Stock decrements.

Security and auth

HttpOnly cookies, JWT, rate limit, structured logs.

  • Shopper auth via Supabase

    Supabase JWT token flows through to Odoo via OdooHttpClient with getExtraHeaders. No re-spreading users, no two password systems.

  • Admin session with HttpOnly cookie JWT

    Package @kmee/admin-session: jose for JWT, Next.js cookie helpers, runtime-agnostic getClientIp, AdminRateLimiter with pluggable store (memory default, Redis/KV in prod).

  • Configurable rate limit

    Per IP, per endpoint, per user. Mitigates brute force, API abuse and catalog scraping.

  • Structured logs

    Injectable logger with levels. Easy to plug into Datadog, Sentry, Grafana, ELK. No raw PII in logs by design.

Tests and CI

Vitest covering helpers, HTTP, cart, JWT, rate limit, storage.

  • Vitest 4.x

    Coverage v8, watch mode, snapshot, automatic mock. Single config in vitest.config.ts at the monorepo root.

  • GitHub Actions

    Pipeline at .github/workflows/test.yml: typecheck (tsc --noEmit) + tests + coverage report. Green on every PR.

  • Changesets

    Versioning and CHANGELOG via Changesets. Release PRs auto-opened when there are changes in publishable packages.

Want to talk to KMEE engineering?

Specific question about auth flow, multi-tenancy, gateway integration? Schedule a technical conversation.