# ReactWare — Complete Project Guide

A fast, headless storefront for **Shopware 6**, built with **Next.js 14 (App Router)**, **React 18**, **TypeScript**, and **Tailwind CSS**. ReactWare renders your existing Shopware shop through the **Store API** (and a small, server-only slice of the **Admin API**) while keeping the Shopware admin, catalog, orders, and plugins exactly as they are.

> This guide explains how the project is structured, how data flows, every configuration option, and how to work on it day to day. For putting it on a server, see [DEPLOYMENT.md](./DEPLOYMENT.md).

---

## Table of contents

1. [What it is](#1-what-it-is)
2. [Architecture at a glance](#2-architecture-at-a-glance)
3. [Prerequisites](#3-prerequisites)
4. [Quick start (local)](#4-quick-start-local)
5. [Connecting to Shopware](#5-connecting-to-shopware)
6. [Environment variables (full reference)](#6-environment-variables-full-reference)
7. [Project structure](#7-project-structure)
8. [How data flows](#8-how-data-flows)
9. [Feature overview](#9-feature-overview)
10. [Theming & branding](#10-theming--branding)
11. [Internationalization (languages & currencies)](#11-internationalization-languages--currencies)
12. [CAPTCHA](#12-captcha)
13. [Caching & freshness](#13-caching--freshness)
14. [Maintenance mode](#14-maintenance-mode)
15. [Common tasks](#15-common-tasks)
16. [Troubleshooting](#16-troubleshooting)

---

## 1. What it is

ReactWare is a **decoupled frontend**: Shopware stays the backend (products, carts, orders, customers, CMS "Shopping Experiences", payments), and this Next.js app is the customer-facing storefront. The two talk over HTTP:

- **Store API** (`/store-api/*`) — public, authenticated with a Sales Channel access key. Used for everything customer-facing: products, navigation, cart, checkout, account, reviews, newsletter, CMS pages.
- **Admin API** (`/api/*`) — privileged, authenticated with an integration client id/secret. Used **server-side only** for a handful of things the Store API doesn't expose: UI translation snippets, sales-channel domains, shop-page IDs, and a few "Basic information / Security" settings (including the active CAPTCHA configuration).

Nothing privileged ever reaches the browser — Admin API credentials live only in server-side route handlers and `src/lib/shopware-admin.ts`.

---

## 2. Architecture at a glance

```
┌─────────────────────────┐        ┌──────────────────────────┐
│   ReactWare (Next.js)    │        │      Shopware 6           │
│                          │        │                           │
│  Server Components  ─────┼──────► │  Store API  (public key)  │
│  Route Handlers     ─────┼──────► │  Admin API  (integration) │
│  Client Components       │        │                           │
│  Middleware (locale,     │        │  Admin panel, catalog,    │
│   maintenance)           │        │  orders, plugins, CMS     │
└─────────────────────────┘        └──────────────────────────┘
        │  deploys to
        ▼
  Vercel / Node server / Docker  (see DEPLOYMENT.md)
```

- **Rendering**: mostly React Server Components (HTML rendered on the server, minimal JS shipped). Interactive pieces (cart, search, switchers, forms) are Client Components.
- **State**: React Context providers wrap the app in `src/app/layout.tsx` — auth, cart, wishlist, sales channel (currency/language), and i18n.
- **Routing**: Next.js App Router file conventions under `src/app`. A catch-all (`[...slug]`) resolves Shopware SEO URLs.

---

## 3. Prerequisites

- **Node.js 18+** (20 LTS recommended) and npm.
- A **Shopware 6** shop you can reach over HTTP(S).
- A **Headless Sales Channel** in that shop, with an **API access key**.
- (Recommended) An **Admin API integration** (client id + secret) to unlock snippets, the language switcher, shop pages, and dynamic CAPTCHA.

---

## 4. Quick start (local)

```bash
# 1. Install dependencies (like composer install)
npm install

# 2. Create your local config from the template
cp .env.example .env.local

# 3. Edit .env.local — at minimum set:
#    NEXT_PUBLIC_SHOPWARE_URL
#    NEXT_PUBLIC_SHOPWARE_ACCESS_KEY

# 4. Start the dev server
npm run dev
```

Open <http://localhost:3000>. Scripts:

| Command | What it does |
| --- | --- |
| `npm run dev` | Dev server with hot reload (unoptimized — **not** for performance testing) |
| `npm run build` | Production build |
| `npm start` | Serve the production build (run `build` first) |
| `npm run lint` | ESLint |

> **Performance note:** always measure Lighthouse/PageSpeed against `npm run build && npm start` (production), never `npm run dev`. Dev mode ships unminified, development-mode React and scores far lower.

---

## 5. Connecting to Shopware

### 5.1 Headless Sales Channel (required)

1. Shopware Admin → **Sales Channels → + → Headless**.
2. Set language(s), currency(ies), and **Domains**.
3. Copy the **API access key** → `NEXT_PUBLIC_SHOPWARE_ACCESS_KEY`.
4. Set `NEXT_PUBLIC_SHOPWARE_URL` to your shop's base URL (no trailing slash).

### 5.2 CORS / domains

In the Headless channel's **Domains**, add the URL(s) the storefront runs on (e.g. `http://localhost:3000` in dev, your real domain in prod). The domain rows also drive the **language switcher** and per-locale snippet sets.

### 5.3 Admin API integration (recommended)

1. Admin → **Settings → System → Integrations → Add integration**.
2. Give it read access; copy **Access key ID** and **Secret access key**.
3. Set `SHOPWARE_ADMIN_CLIENT_ID` and `SHOPWARE_ADMIN_CLIENT_SECRET` (server-only, **no** `NEXT_PUBLIC_` prefix).

Without the integration, the storefront still works but degrades quietly: no admin-authored UI snippets, no language switcher, no shop-page legal popups, and CAPTCHA falls back to "none".

---

## 6. Environment variables (full reference)

Copy `.env.example` → `.env.local`. Variables prefixed `NEXT_PUBLIC_` are exposed to the browser; all others are **server-only**.

### Required

| Variable | Description |
| --- | --- |
| `NEXT_PUBLIC_SHOPWARE_URL` | Shop base URL, no trailing slash (e.g. `https://shop.example.com`). |
| `NEXT_PUBLIC_SHOPWARE_ACCESS_KEY` | Headless Sales Channel API access key. |

### Recommended (server-only)

| Variable | Description |
| --- | --- |
| `SHOPWARE_ADMIN_CLIENT_ID` | Admin integration access key ID. Enables snippets, language switcher, shop pages, dynamic CAPTCHA. |
| `SHOPWARE_ADMIN_CLIENT_SECRET` | Admin integration secret access key. |

### Storefront identity & locale

| Variable | Default | Description |
| --- | --- | --- |
| `NEXT_PUBLIC_STORE_NAME` | `ReactWare` | Shown in header (text logo fallback), footer, `<title>`, and JSON-LD. |
| `NEXT_PUBLIC_SHOPWARE_STOREFRONT_URL` | request origin | Canonical storefront origin for SEO/structured data. |
| `NEXT_PUBLIC_CURRENCY` | `EUR` | Default currency ISO when none is selected. |
| `NEXT_PUBLIC_LOCALE` | `en-GB` | Default locale. |
| `NEXT_PUBLIC_FONT` | `Inter` | One of `Inter`, `Outfit`, `Open Sans`, `Roboto`. |

### Logos & favicon

| Variable | Description |
| --- | --- |
| `NEXT_PUBLIC_LOGO_DESKTOP` / `_TABLET` / `_MOBILE` | Responsive logo image URLs. |
| `NEXT_PUBLIC_LOGO_URL` | Single fallback logo if the responsive ones aren't set. |
| `NEXT_PUBLIC_FAVICON_URL` | Favicon URL. |

If no logo is configured, the header shows `NEXT_PUBLIC_STORE_NAME` as text.

### Theme colors (drive Tailwind `brand-*` and text colors)

| Variable | Default | Description |
| --- | --- | --- |
| `NEXT_PUBLIC_COLOR_PRIMARY` | `#0042a0` | Primary brand color (`brand-500`). |
| `NEXT_PUBLIC_COLOR_PRIMARY_DARK` | `#003080` | Hover/dark brand (`brand-600`+). |
| `NEXT_PUBLIC_COLOR_TEXT` | `#18181b` | Body text color. |
| `NEXT_PUBLIC_COLOR_HEADLINE` | `#18181b` | Heading color. |

### Top bar (service info)

| Variable | Description |
| --- | --- |
| `NEXT_PUBLIC_SUPPORT_PHONE` | Phone shown in the top bar (links to `tel:`). |
| `NEXT_PUBLIC_SUPPORT_HOURS` | Service hours text. |
| `NEXT_PUBLIC_SUPPORT_EMAIL` | Support email (used on the maintenance page). |
| `NEXT_PUBLIC_FREE_SHIPPING_NOTE` | Short free-shipping note in the top bar. |

### Operations & security (server-only)

| Variable | Description |
| --- | --- |
| `CAPTCHA_SECRET` | HMAC key for the stateless Basic (image) CAPTCHA. **Set a strong random value in production.** |
| `ADMIN_SECRET` | Shared secret for the cache-revalidation endpoint (`POST /api/revalidate?secret=…`). |
| `NEXT_PUBLIC_MAINTENANCE_MODE` | `1`/`true` to enable maintenance mode. |
| `MAINTENANCE_ALLOWLIST` | Comma-separated IPs allowed through during maintenance. |

> reCAPTCHA site/secret keys are **not** env vars — they're read from Shopware admin (Settings → CAPTCHA). See [CAPTCHA](#12-captcha).

---

## 7. Project structure

```
src/
├── app/                          # App Router routes
│   ├── layout.tsx                # Root layout: providers, theme vars, fonts, JSON-LD
│   ├── page.tsx                  # Homepage (renders the CMS page, else a product grid)
│   ├── [...slug]/                # Catch-all: resolves Shopware SEO URLs
│   ├── products/                 # PLP + PDP ([id])
│   ├── category/[id]/            # Category listing
│   ├── search/                   # Search results
│   ├── checkout/                 # cart, confirm, and the main checkout flow
│   ├── account/                  # login, register, profile, addresses, orders, recover/reset
│   ├── wishlist/ contact/ about/ maintenance/
│   └── api/                      # Route handlers (server) — see "How data flows"
│       ├── captcha/              # config, image, verify
│       ├── contact/ languages/ snippets/ storefront-settings/
│       ├── registration-config/ shop-page/ revalidate/ …
├── components/
│   ├── layout/                   # Header, Footer, TopBar, nav, switchers, cookie consent
│   ├── product/                  # ProductCard, gallery, variants, reviews, cross-selling…
│   ├── cms/                      # CmsPage renderer + every CMS element/block
│   ├── checkout/ account/ cart/ ui/
├── lib/
│   ├── shopware-api.ts           # ALL Store API calls (client + server safe)
│   ├── shopware-admin.ts         # Admin API client (SERVER ONLY)
│   ├── captcha-*.ts              # CAPTCHA types, server verifier, client gate
│   ├── *-context.tsx             # auth, cart, wishlist, sales-channel, i18n providers
│   ├── structured-data.ts        # schema.org JSON-LD builders
│   └── server-snippets.ts        # per-request snippet loading
└── middleware.ts                 # locale-prefix rewriting + maintenance gate
```

---

## 8. How data flows

There are two call paths, by design:

1. **Browser → Store API directly.** Most reads and many writes use `shopwareApi()` in `src/lib/shopware-api.ts`, sending the public `sw-access-key`. Examples: product fetches, cart, newsletter, reviews, registration, login. The Shopware **context token** (cart/session) round-trips via the `sw-context-token` header/cookie.

2. **Browser → Next route handler → Shopware.** Used whenever a **server secret** or **Admin API** is required, so credentials never reach the browser. Examples:
   - `/api/snippets`, `/api/languages`, `/api/shop-page`, `/api/storefront-settings`, `/api/registration-config` → Admin API via `shopware-admin.ts`.
   - `/api/contact` → verifies CAPTCHA, then forwards to the Store API contact-form endpoint.
   - `/api/captcha/config|verify` → reads active CAPTCHA config / verifies tokens (reCAPTCHA secret stays server-side).
   - `/api/revalidate` → clears the Next.js render cache (protected by `ADMIN_SECRET`).

Server Components call Store/Admin helpers directly during SSR; the root layout registers server cookie/header readers so the first SSR render already has the right context token and language.

---

## 9. Feature overview

Mapped to Shopware's default storefront:

- **Catalog**: homepage CMS page, category listing (PLP) with sort, pagination, manufacturer/property/price filters; product detail (PDP) with image gallery, variant selector, properties table, reviews, and cross-selling.
- **Search**: header search with autocomplete suggestions + a full results page.
- **Cart & checkout**: cart drawer + cart page; full checkout with delivery/billing address, shipping method, payment method, promotion codes, order comment, terms + digital-goods withdrawal consent, guest checkout, inline login, and payment redirect handling.
- **Account**: login, registration (private/commercial), profile (change name/email/password), address book (CRUD + defaults), order history + detail, **repeat order**, **change payment method**, password recovery/reset.
- **Content**: full Shopware "Shopping Experiences" CMS renderer (text, images, sliders, galleries, product listings/sliders/boxes, forms, HTML, video, hero, multi-column image blocks, sidebar layout).
- **Engagement**: wishlist (guest + customer, with merge on login), newsletter subscribe/unsubscribe, contact form, product reviews.
- **Cross-cutting**: multi-language + multi-currency switchers, cookie consent, dynamic CAPTCHA, maintenance mode, SEO (metadata, `sitemap.xml`, `robots.txt`, JSON-LD structured data), responsive design.

---

## 10. Theming & branding

The theme is **env-driven** so you can rebrand without touching code:

- Colors (`NEXT_PUBLIC_COLOR_*`) are injected in `src/app/layout.tsx` as CSS custom properties, which Tailwind's `brand-*` / text utilities consume. Change the env value → every `bg-brand-500`, `text-brand-600`, etc. follows.
- Logo via `NEXT_PUBLIC_LOGO_*` (image) or falls back to `NEXT_PUBLIC_STORE_NAME` as text.
- Font via `NEXT_PUBLIC_FONT` (one of four bundled Google fonts).

---

## 11. Internationalization (languages & currencies)

- **Languages** are derived from the Headless channel's **Domains** (a language appears in the switcher only if a domain exists for it), read via the Admin API (`getStorefrontLanguages`).
- URLs are **locale-prefixed** (e.g. `/de-DE/...`). `src/middleware.ts` strips the prefix, maps the locale → Shopware `languageId`, and forwards `x-sw-language-id` so the first SSR render is already translated.
- **Currencies** come from the Store API; the switcher updates the Shopware context and re-prices the cart.
- **UI snippets** (button labels, messages) are pulled from Shopware's snippet sets via the Admin API and merged per-locale; code provides English fallbacks via `t('key', 'fallback')`.

---

## 12. CAPTCHA

ReactWare mirrors Shopware's **dynamic** CAPTCHA system (Admin → Settings → Basic information → CAPTCHA). It reads the active config (`core.basicInformation.activeCaptchasV2`) and renders whatever is enabled — multiple can be active at once and **all** must pass:

| Type | Behavior |
| --- | --- |
| Honeypot | Hidden trap field; rejected if filled. |
| Basic Captcha | Stateless HMAC-signed image challenge (`CAPTCHA_SECRET`). |
| Google reCAPTCHA v2 | Checkbox/invisible; verified server-side via Google. |
| Google reCAPTCHA v3 | Score-based; respects the admin threshold. |

- Applied to: **contact, newsletter (subscribe), product review, registration** forms.
- reCAPTCHA **secret keys are read from Shopware admin** and used only server-side — never sent to the browser. No extra env needed (requires the Admin API integration).
- Reusable `<Captcha>` component (`src/components/ui/Captcha.tsx`) + server verifier (`src/lib/captcha-server.ts`) + verify-gate (`/api/captcha/verify`).

---

## 13. Caching & freshness

To avoid hammering Shopware, server-side data is cached in two layers:

- **Next.js render/ISR cache** — pages use ISR (e.g. the homepage revalidates every 60s). To clear everything on demand:
  ```bash
  curl -X POST "https://your-site.com/api/revalidate?secret=$ADMIN_SECRET"
  ```
- **In-memory caches** in `shopware-admin.ts` (module-level, per server process):
  | Data | TTL |
  | --- | --- |
  | Sales-channel domains (drives the language switcher) | 60s |
  | Language metadata | 60s |
  | Snippets | 10 min |
  | Shop-page IDs | 10 min |
  | Active CAPTCHAs | 60s |
  | Security/registration settings | 30s |

Because these live in process memory, **admin changes appear after the TTL elapses or when the server process restarts** — a full rebuild isn't required, just a restart (or waiting out the TTL).

---

## 14. Maintenance mode

Set `NEXT_PUBLIC_MAINTENANCE_MODE=1` (and restart). `src/middleware.ts` rewrites all non-asset requests to `/maintenance`, except IPs in `MAINTENANCE_ALLOWLIST` (comma-separated). The maintenance page uses `NEXT_PUBLIC_STORE_NAME`, `NEXT_PUBLIC_SUPPORT_EMAIL`, and `NEXT_PUBLIC_SUPPORT_PHONE`.

---

## 15. Common tasks

- **Add a page**: create `src/app/your-page/page.tsx` → available at `/your-page`.
- **Add a Store API call**: add an exported function in `src/lib/shopware-api.ts` using `shopwareApi('/endpoint', { body })`.
- **Add Admin-API-backed data**: add a function in `src/lib/shopware-admin.ts` (server-only) and expose it through a route handler under `src/app/api/`.
- **Rebrand**: edit `NEXT_PUBLIC_COLOR_*`, `NEXT_PUBLIC_LOGO_*`, `NEXT_PUBLIC_STORE_NAME`, `NEXT_PUBLIC_FONT` in `.env.local`, then restart.

---

## 16. Troubleshooting

| Symptom | Likely cause / fix |
| --- | --- |
| Products don't load | Check `NEXT_PUBLIC_SHOPWARE_URL`/`_ACCESS_KEY`; ensure the Headless channel is active. |
| CORS errors | Add your storefront URL to the Headless channel **Domains** in admin. |
| Language switcher missing/stale | Needs 2+ language **domains** and the Admin integration; changes reflect within ~60s (TTL) or after a server restart. |
| Snippets/labels are all English | Admin integration not configured, or snippets not authored in admin (code falls back to English). |
| CAPTCHA not showing | Not enabled in Admin → Settings → CAPTCHA, or the Admin integration isn't configured. |
| Low Lighthouse performance | You're testing `npm run dev`. Test `npm run build && npm start` in an Incognito window. |
| Stale page after admin edit | `POST /api/revalidate?secret=…`, or wait for the in-memory TTL. |
| `Cannot find module './XXXX.js'` in dev | Stale `.next` cache (often after running a prod build over a dev server). Stop dev, delete `.next`, restart `npm run dev`. |

---

For server/hosting setup, continue to **[DEPLOYMENT.md](./DEPLOYMENT.md)**.
