ALL PROJECTS/RIQUID PLATFORM

Overview

Riquid is a multi-module product suite that covers the commerce lifecycle end to end — selling, fulfilment, tracking and marketing. It is built for a B2B commerce operation that runs its own storefront while also managing logistics and reporting internally. Rather than one monolithic application, the suite is three separate front-end codebases — a React + Vite operations core, a Next.js storefront, and a Next.js business site — that share a common design system.

Problem

A commerce operation of any real size outgrows a single storefront quickly. Selling is only one surface: orders have to be fulfilled, shipments have to be located and tracked, sales have to be measured, and the business needs a public face that speaks the same visual language as the product. The obvious path is to bolt each of these onto whatever codebase already exists, and the predictable result is a single application carrying a checkout flow, a Mapbox integration, a charting library and a marketing landing page all in one bundle — every surface competing for the same release train. The alternative failure mode is to split them and let each drift, so that a customer moving from the marketing site to the storefront to a tracking view feels three unrelated products. The problem was to get the separation without the drift: distinct apps with distinct release cadences that still read as one system.

System Design

The suite is three deployable front ends. The operations core (riquid-website) is a React 18 application on Vite 4, routed with React Router v6. It carries the two integrations that would be dead weight in a storefront bundle: Mapbox GL — wrapped by react-map-gl — for location and logistics views, and Chart.js via react-chartjs-2 for sales analytics. Motion and presentation are handled with Framer Motion, AOS and Swiper, with react-intersection-observer driving scroll-triggered reveals and react-countup animating figures. Tailwind CSS with PostCSS and Autoprefixer supplies the styling layer, and ESLint runs with --max-warnings 0, so the lint gate is a hard gate rather than advisory.

The storefront (riquid-store) is a Next.js 14 App Router project in TypeScript, deployed to Vercel via a checked-in vercel.json and a .env.production. Cart and client state live in Zustand v5 — a store rather than prop-drilled context, which keeps the cart addressable from anywhere in the tree without a provider cascade. Payments run through Stripe's React bindings, @stripe/react-stripe-js over @stripe/stripe-js, so card entry happens inside Stripe-hosted Elements iframes and raw card data never touches application state. Server data is fetched with axios and cached and revalidated with SWR, giving stale-while-revalidate behaviour on catalogue and order reads. The component layer is shadcn/ui on top of @base-ui/react, with class-variance-authority, clsx and tailwind-merge composing variant-driven class names, lucide-react for iconography, and Framer Motion v12 for transitions. It is the only module with a test harness: Vitest with jsdom, Testing Library (react, jest-dom, user-event) and a vitest.setup.ts — the module that handles money is the module that gets tests.

The business site (riquid-business) is a deliberately lean Next.js 14 TypeScript app, also on Vercel, running on port 4601 in development so it can sit alongside the storefront locally without a port clash. It shares the storefront's styling and utility vocabulary — Tailwind, tailwindcss-animate, clsx, tailwind-merge, lucide-react, Zustand, axios — but carries none of its payment, testing or mapping weight. That shared vocabulary is what holds the suite together: three codebases converging on the same Tailwind configuration, the same class-composition helpers and the same icon set, so a component written for one surface is legible on any other. Nothing forces the modules into lockstep; each has its own package.json, its own lint config, and its own deploy.

A shared commerce core serves several module frontends — storefront, business, operations and logistics — over one API and data tier.

CLIENTS
Storefront (Next.js)Business Portal (React)Command / Ops (React)Logistics Trace (React)
EDGE
CDNLoad Balancer
API GATEWAY
API Gateway
SERVICES
Auth & OrgsCatalog & OrdersPaymentsLogistics & TrackingAnalytics
ASYNC · REALTIME
Task WorkersEvent Bus
DATA
PostgreSQLRedisObject Storage
EXTERNAL
StripeMapbox

High-level architecture — abstracted for confidentiality; no internal endpoints, hostnames, or credentials are shown.

How It Works

01/03
01

Storefront Checkout

A customer moves from catalogue browse to a Stripe-confirmed payment without card data ever entering application state.

  1. 1The catalogue renders from the Next.js App Router, with product and inventory reads fetched over axios and cached by SWR.
  2. 2Adding an item dispatches to the Zustand cart store, which holds line items and quantities as client state readable from any component.
  3. 3The cart view derives totals from that store and reflects changes immediately, with no round trip for quantity edits.
  4. 4Checkout mounts Stripe Elements through @stripe/react-stripe-js, so card fields render inside Stripe-controlled iframes.
  5. 5The payment is confirmed against Stripe using the publishable key from the production environment file; card details never enter the Zustand store or the application bundle.
  6. 6On confirmation, the cart store is cleared and the order surface re-fetches through SWR to pick up the newly created order.
02

Logistics and Analytics in the Operations Core

The React + Vite core resolves a route to either a Mapbox-backed logistics view or a Chart.js reporting surface over the same sales data.

  1. 1The operations core loads under React Router, resolving the requested route to a logistics or analytics view.
  2. 2Logistics views mount react-map-gl over Mapbox GL, initialising a map with the token supplied through the app's environment configuration.
  3. 3Location and shipment data is projected onto the map as markers and layers, giving positional context for fulfilment and tracking.
  4. 4Analytics views feed the same underlying sales data into react-chartjs-2, which renders Chart.js canvases for the reporting surfaces.
  5. 5react-intersection-observer triggers reveals and react-countup animates summary figures as each panel scrolls into view.
03

Independent Module Deployment

Each of the three front ends builds, lints and deploys on its own cadence while converging on a shared design vocabulary.

  1. 1Each module is its own repository with its own package.json, lockfile and lint configuration.
  2. 2A change to the storefront runs next lint and the Vitest suite; a change to the operations core runs ESLint under --max-warnings 0, which fails the build on any warning.
  3. 3The storefront and business site build with next build and deploy to Vercel under their own vercel.json; the operations core builds with vite build.
  4. 4Because the shared design vocabulary lives in the Tailwind configuration and the class-composition utilities rather than in a runtime dependency, one module can deploy without rebuilding or redeploying the others.

Key Features

  • Next.js storefront with Stripe checkout
  • Zustand-powered cart & state
  • Mapbox logistics & location tracking
  • Chart.js sales analytics
  • Shared design system across modules
  • Marketing & business landing site

Outcomes

  • A cohesive multi-app suite instead of disconnected tools
  • Independent deploys per module
  • Consistent brand across every surface

More work