N-2 Water: React & Next.js E-Commerce with Shopify Integration

A Next.js 15 monorepo storefront for N-2 Water: Shopify Storefront + Customer Account APIs, designer-led UI phases, PKCE auth, cross-domain cart bridge, and a staged migration from a legacy static marketing site.

Highlights

  • npm workspaces: `apps/store` + shared `packages/ui` (Rollup CJS/ESM) with brand design tokens
  • OAuth 2.0 + PKCE for Customer Account API; HttpOnly cookies for tokens and OAuth intermediates
  • Cross-domain cart via `widget.js` + `X-Cart-Id` header bridging legacy static host and the React app
  • Designer integration Phases 1–8 merged (CEO toggle for legacy vs new UI pending Phase 9 sign-off)
  • v2.4.0: copy/content QA across legal, science, About, FAQ, benefits, Instagram feed (Basic Display API + ISR)

Tech Stack

Tags

Overview

N-2 Water is a mineral-first hydration brand. This project is the full digital platform: a Next.js 15 (App Router) store in an npm workspaces monorepo, integrated with Shopify Storefront API (GraphQL) and Customer Account API (OAuth 2.0 + PKCE), deployed on Vercel. Development spans static HTML → React store → 20+ designer-delivered components across homepage, science, shop, and account surfaces.

Problem & Context

The brand needed marketing storytelling and real e-commerce (catalog, PDP variants, cart, checkout, authenticated orders) in one maintainable codebase. Early static HTML could not support PKCE account flows, shared cart state across origins, or the scoped UI work from an external designer — without a controlled migration path.

Constraints

  • Public OAuth client — no server-side secret; PKCE required for Customer Account API.
  • Cross-origin cart: legacy static site and Next app on different origins; cookies alone are insufficient (SameSite limits).
  • OpenID Connect discovery for Shopify customer endpoints — avoid hardcoded URLs.
  • Designer phases must land inside App Router without blocking commerce-critical paths.
  • No fabricated Lighthouse or revenue metrics — performance hardening and production domains remain planned/deferred per internal status docs.

Approach & Design Decisions

  • Gradual migration: root vercel.json redirect shell sends traffic to the store app; legacy static remained reachable during build-out.
  • PKCE + short-lived HttpOnly cookies for OAuth state/nonce/verifier (5-minute TTL), cleared after token exchange — tokens never exposed to client JS.
  • X-Cart-Id header: widget.js stores Shopify cart id in localStorage for the static site; API routes read header (static) or cookie (same-origin).
  • DesignContext + Shift+Ctrl+D: CEO/stakeholder toggle comparing designer vs legacy components until Phase 9 cleanup (delete legacy/admin paths).
  • Zod on API routes for safe request parsing before Shopify mutations.

Implementation Highlights

  • GraphQL via graphql-request: products, cart mutations, customer operations (see shopify.ts / customer OAuth helpers).
  • REST API routes: /api/cart, /api/auth/*, /api/account/*, newsletter/contact stubs ready for provider wiring.
  • next/image migration (v2.2.0): <img><Image> across key surfaces; remotePatterns for Shopify CDN.
  • Jest: integration, security (CORS, injection), safety, and E2E-style coverage categories.
  • Workflow alignment (v2.3.0): docs and audit patterns aligned to shared workflow-core Mode A conventions.

Results & Evaluation

  • v2.0.0: Designer phases 1–8 merged to main (March 2026).
  • v2.4.0 (2026-04-04): Copy + content QA — 11 tickets (legal, science, About, FAQ, benefits, ingredients, team narratives, Terms of Use) plus Instagram Basic Display with 1-hour ISR caching.
  • v2.5.0 (next): Analytics & conversion — GA4, Meta Pixel, consent/CMP, data layer, Vercel env configuration.
  • Soft launch: production domains (n-2water.com, shop.n-2water.com) in active DNS/Vercel setup; full performance audit still deferred.

Tradeoffs & Limitations

  • Newsletter / contact API routes are stubs until wired to Klaviyo/Resend (per internal roadmap).
  • Phase 9 human gate still blocks deleting legacy/admin bundles.
  • Third-party dependency on Shopify APIs and rate/field behaviors.
  • Internal metrics not published here.

What I Learned

Migrating a live brand site while integrating OAuth PKCE, cross-domain cart state, and parallel designer UI forces explicit contracts: cookie shapes, CORS allowlists, and feature flags for safe rollout.