# Headless WordPress/WooCommerce + Next.js E-Commerce
## System Architecture & Technical Specification Document

> **Document Purpose**: This architecture note outlines the complete system flow, data layer mapping, Next.js file/component design, API contracts, and cPanel deployment strategy. It is formatted for technical review by developers and system architects.

---

## 1. System Architecture Overview

```mermaid
flowchart TB
    subgraph ClientBrowser ["Client Browser (End User)"]
        UI["Custom UI / UX (Next.js App)"]
        LocalStorage["Browser Storage (Cart-Token, Wishlist)"]
    end

    subgraph FrontendServer ["Next.js Frontend (Node.js / Passenger)"]
        SSR_ISR["Next.js App Router (ISR + React Server Components)"]
        ClientState["Client Component State (CartContext, Checkout State)"]
        RevalAPI["API Route: /api/revalidate (Webhook Listener)"]
    end

    subgraph BackendServer ["WordPress / WooCommerce Backend (cPanel)"]
        WPAdmin["WP Admin Panel (Client Manages Products & Orders)"]
        WPGraphQL["WPGraphQL + WooGraphQL (/graphql)"]
        StoreAPI["WooCommerce Store API (/wp-json/wc/store/v1/*)"]
        Webhooks["WooCommerce Webhooks (Product update events)"]
        CourierExt["Courier Integrations (Steadfast, Pathao, RedX)"]
        WPDatabase[("WordPress MySQL Database")]
    end

    %% Read Flow
    WPDatabase --> WPAdmin
    WPDatabase --> WPGraphQL
    WPGraphQL -->|Cached GraphQL Query| SSR_ISR
    SSR_ISR -->|HTML + RSC Payload (Sub-second)| UI

    %% Cache Invalidation Flow
    WPAdmin -->|Product Edit/Save| Webhooks
    Webhooks -->|POST /api/revalidate?secret=...| RevalAPI
    RevalAPI -->|revalidateTag('products')| SSR_ISR

    %% Write / Cart Flow
    UI <--> ClientState
    ClientState <-->|Cart-Token + Nonce + REST| StoreAPI
    StoreAPI <--> WPDatabase

    %% Order Placement & Admin Management
    ClientState -->|POST /wc/store/v1/checkout (COD)| StoreAPI
    StoreAPI -->|Creates Order #ID| WPDatabase
    WPAdmin -->|View/Process Orders| CourierExt
```

---

## 2. Database & Data Model Mapping

The headless architecture does not reinvent the database schema. **WordPress MySQL** remains the single source of truth:

| Entity | WordPress / WooCommerce DB Table | API Exposure Method | Next.js TypeScript Model |
| :--- | :--- | :--- | :--- |
| **Products** | `wp_posts` (`post_type = 'product'`), `wp_postmeta` (price, SKU, stock) | WPGraphQL (`products`) / Store API | `interface Product` |
| **Categories** | `wp_terms`, `wp_term_taxonomy` (`taxonomy = 'product_cat'`) | WPGraphQL (`productCategories`) | `interface Category` |
| **Attributes & Variations** | `wp_woocommerce_attribute_taxonomies`, `wp_posts` (`product_variation`) | WooGraphQL (`variations`) | `interface ProductVariation` |
| **Cart Session** | `wp_woocommerce_sessions` | Store API (`/wc/store/v1/cart`) | `interface Cart`, `CartItem` |
| **Orders** | `wp_wc_orders` (HPOS) or `wp_posts` (`shop_order`) + `wp_wc_order_stats` | Store API (`/wc/store/v1/checkout`) | `interface OrderResponse` |
| **Coupons** | `wp_posts` (`post_type = 'shop_coupon'`) | Store API (`/cart/apply-coupon`) | `interface Coupon` |

### Core TypeScript Interfaces (Next.js Data Layer)

```typescript
// Product Definition
export interface Product {
  id: number | string;
  name: string;
  slug: string;
  brand?: string;
  sku?: string;
  price: number;
  regularPrice: number;
  salePrice?: number;
  onSale: boolean;
  stockStatus: 'IN_STOCK' | 'OUT_OF_STOCK';
  images: Array<{
    id: string | number;
    sourceUrl: string;
    altText?: string;
  }>;
  categories: Array<{
    id: string | number;
    name: string;
    slug: string;
  }>;
  concerns?: string[]; // Custom taxonomy or attribute: Acne, Redness, etc.
  description: string;
  shortDescription?: string;
  keyIngredients?: Array<[title: string, description: string]>;
  howToUse?: string;
}

// Store API Cart Item Definition
export interface CartItem {
  key: string;
  id: number;
  name: string;
  quantity: number;
  prices: {
    price: string;
    regular_price: string;
    sale_price: string;
    currency_symbol: string;
  };
  images: Array<{ thumbnail: string; src: string; alt: string }>;
  totals: {
    line_subtotal: string;
    line_total: string;
  };
}

// Checkout Payload Definition
export interface CheckoutPayload {
  billing_address: {
    first_name: string;
    last_name?: string;
    phone: string;
    address_1: string;
    city: string;
    country: 'BD';
  };
  shipping_address?: {
    first_name: string;
    phone: string;
    address_1: string;
    city: string;
    country: 'BD';
  };
  payment_method: 'cod' | 'bkash' | 'nagad' | 'sslcommerz';
  customer_note?: string;
  shipping_lines?: Array<{
    method_id: 'inside_dhaka' | 'outside_dhaka';
  }>;
}
```

---

## 3. Next.js App Router: File & Component Structure

We follow the standard **Next.js App Router (14/15+)** architectural pattern, separating **Server Components (RSC)** (for fast, cached SEO rendering) from **Client Components (`'use client'`)** (for interactive cart/checkout).

```
d:/Work Station/Ecommcere Next Js + WP/
├── next.config.mjs                 # output: 'standalone' config
├── server.js                       # Entry point for cPanel / Phusion Passenger ($PORT)
├── package.json
├── tsconfig.json
├── .env.local                      # WP_URL, GRAPHQL_ENDPOINT, REVALIDATE_SECRET
├── public/                         # Static icons, logo, placeholders
└── src/
    ├── app/
    │   ├── globals.css             # Complete design tokens, responsive CSS & animations
    │   ├── layout.tsx              # Root layout (Header, CartDrawer, Footer, TabBar, CartProvider)
    │   ├── page.tsx                # Homepage (Server Component with ISR)
    │   ├── shop/
    │   │   └── page.tsx            # Shop catalog (Filter, Sort, Grid)
    │   ├── category/
    │   │   └── [slug]/page.tsx     # Dynamic category page (ISR)
    │   ├── product/
    │   │   └── [slug]/page.tsx     # Single Product Detail Page (PDP) (ISR)
    │   ├── cart/
    │   │   └── page.tsx            # Full cart view (Client Component)
    │   ├── checkout/
    │   │   └── page.tsx            # Custom 1-page checkout form (Client Component)
    │   ├── order-received/
    │   │   └── [id]/page.tsx       # Custom thank-you / order confirmation page
    │   └── api/
    │       └── revalidate/
    │           └── route.ts        # Webhook listener for on-demand cache revalidation
    ├── components/
    │   ├── layout/
    │   │   ├── Header.tsx          # Dynamic navigation, search trigger, cart counter badge
    │   │   ├── Footer.tsx          # Accordion footer on mobile, full grid on desktop
    │   │   ├── MobileTabBar.tsx    # Mobile bottom app navigation
    │   │   ├── CartDrawer.tsx      # Slide-out mini cart drawer ('use client')
    │   │   └── FloatingCartTab.tsx # Sticky floating cart launcher ('use client')
    │   ├── home/
    │   │   ├── Hero.tsx            # Hero banner & copy
    │   │   ├── TrustBar.tsx        # Value propositions & trust strip
    │   │   ├── OfferCards.tsx      # Promotional discount cards
    │   │   ├── ConcernFinder.tsx   # Interactive skin concern selector
    │   │   ├── RoutineSection.tsx  # 5-step skincare routine interactive section
    │   │   └── ReviewsSection.tsx  # Customer review quotes
    │   ├── product/
    │   │   ├── ProductCard.tsx     # Reusable product card with image, price, discount badge
    │   │   ├── ProductGrid.tsx     # Responsive grid container
    │   │   ├── AddToCartBtn.tsx    # Interactive add-to-cart button
    │   │   └── StickyBuyBar.tsx    # Mobile bottom sticky purchase bar
    │   └── ui/
    │       └── Icons.tsx           # SVG icon definitions (Search, Bag, Phone, etc.)
    ├── context/
    │   └── CartContext.tsx         # React Context managing Store API Cart-Token & items
    ├── lib/
    │   ├── wpgraphql.ts            # GraphQL query client for Products, Categories, Menus
    │   └── store-api.ts            # REST client for WooCommerce Store API (Cart & Checkout)
    └── types/
        └── woocommerce.ts          # Shared TypeScript type definitions
```

---

## 4. API Flow & Communication Contracts

### A. Catalog & Reading (WPGraphQL)
* **Endpoint**: `https://roseebelle.com/graphql`
* **Caching Strategy**: `fetch(url, { next: { revalidate: 3600, tags: ['products'] } })`
* **Query Example**:
```graphql
query GetProducts($first: Int, $category: String) {
  products(first: $first, where: { category: $category }) {
    nodes {
      databaseId
      name
      slug
      ... on SimpleProduct {
        price(format: RAW)
        regularPrice(format: RAW)
        salePrice(format: RAW)
        stockStatus
      }
      image {
        sourceUrl
        altText
      }
      productCategories {
        nodes {
          name
          slug
        }
      }
    }
  }
}
```

### B. Cart & Checkout (WooCommerce Store API)
* **Base Endpoint**: `https://roseebelle.com/wp-json/wc/store/v1/`
* **Session & Nonce Mechanism**: Handled via `Cart-Token` and `Nonce` (`X-WC-Store-API-Nonce`) headers.
  - On the first cart request (`GET /cart`), WooCommerce sends back:
    1. `Cart-Token` header (persisting the unique cart session across domains without relying on standard WP cookies).
    2. `Nonce` / `X-WC-Store-API-Nonce` header (preventing CSRF and required by WooCommerce 7.2+ for all mutation actions).
  - Next.js stores both values in client storage / cookies and attaches them to all mutation requests (`add-item`, `update-item`, `remove-item`, `checkout`):
    ```http
    Cart-Token: 18b456df-71d2-43f1-ba67-890abcdef123
    Nonce: 9a781b2c3d
    X-WC-Store-API-Nonce: 9a781b2c3d
    Content-Type: application/json
    ```
* **Endpoints Used**:
  - `GET /cart`: Fetch current cart items, subtotal, and coupons.
  - `POST /cart/add-item`: Add product ID & quantity.
  - `POST /cart/update-item`: Increment / decrement quantity.
  - `POST /cart/remove-item`: Remove item by key.
  - `POST /cart/apply-coupon`: Apply promotional discount code.
  - `POST /checkout`: Place order with billing address, shipping option, and `payment_method: "cod"`.

### C. WordPress Backend CORS Configuration
To allow the Next.js frontend to communicate seamlessly with `/graphql` and `/wp-json/wc/store/v1/*` without browser CORS rejection, add this snippet to WordPress (`wp-content/mu-plugins/headless-cors.php` or `functions.php`):

```php
<?php
/**
 * Plugin Name: Headless E-commerce CORS & Header Support
 */
add_action('init', function() {
    $allowed_origins = [
        'http://localhost:3000',
        'https://roseebelle.com', // Frontend domain
    ];
    $origin = get_http_origin();

    if (in_array($origin, $allowed_origins, true)) {
        header("Access-Control-Allow-Origin: " . $origin);
        header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE");
        header("Access-Control-Allow-Credentials: true");
        header("Access-Control-Allow-Headers: Authorization, Content-Type, Cart-Token, Nonce, X-WC-Store-API-Nonce");
        header("Access-Control-Expose-Headers: Cart-Token, Nonce, X-WC-Store-API-Nonce");
    }

    if ('OPTIONS' === $_SERVER['REQUEST_METHOD']) {
        status_header(200);
        exit();
    }
});
```

### D. On-Demand Revalidation (`/api/revalidate`)
* **Trigger**: WooCommerce Webhook on `product.updated`, `product.created`, `product.deleted`.
* **Payload**: Includes webhook secret token in URL query:
  `POST /api/revalidate?secret=YOUR_SECURE_TOKEN`
* **Action**:
  ```typescript
  export async function POST(request: Request) {
    const { searchParams } = new URL(request.url);
    if (searchParams.get('secret') !== process.env.REVALIDATION_SECRET) {
      return Response.json({ message: 'Invalid token' }, { status: 401 });
    }
    revalidateTag('products');
    revalidatePath('/shop');
    return Response.json({ revalidated: true, now: Date.now() });
  }
  ```

---

## 5. Order Lifecycle & Management Flow

```mermaid
sequenceDiagram
    autonumber
    actor Customer as Customer (Next.js Frontend)
    participant NextClient as Next.js Checkout View
    participant StoreAPI as WC Store API (/checkout)
    participant WPAdmin as WP Admin (WooCommerce Orders)
    participant Courier as Courier System (Steadfast/Pathao)

    Customer->>NextClient: Fills Name, Phone (01XXXXXXXXX), Area (Inside/Outside Dhaka), Address
    Customer->>NextClient: Selects Cash on Delivery (COD) & clicks "Place Order"
    NextClient->>StoreAPI: POST /wc/store/v1/checkout (Cart-Token, Nonce, Billing Info, payment_method: 'cod')
    StoreAPI-->>NextClient: 200 OK (Order #1045 Created, Status: Processing, Total: ৳2,160)
    NextClient->>Customer: Renders Custom Order Received Screen (#1045)
    
    Note over StoreAPI,WPAdmin: Order instantly recorded in WP Database
    StoreAPI->>WPAdmin: Sends standard WC Email / SMS notifications
    WPAdmin->>WPAdmin: Admin reviews order details, phone, and delivery fee
    WPAdmin->>Courier: Admin clicks "Send to Courier" (via WP Courier Plugin)
    WPAdmin->>WPAdmin: Changes status: Processing -> Completed
```

### Key Takeaways for Developers:
1. **Zero Admin Friction**: The shop manager does not touch Next.js to fulfill orders. They use the standard WordPress orders page.
2. **Payment Simplification**: Focused on Cash on Delivery (COD) for v1. Payment gateway redirects (bKash / SSLCommerz) can be plugged in during Phase 2 via WooCommerce gateway callback endpoints.
3. **Courier Plugins Compatibility**: Plugins like Steadfast, Pathao, or Paperfly that hook into WooCommerce orders continue to function normally.
4. **Tracking Ready**: Next.js can query order status by ID & Billing Phone using WooCommerce REST API for customer self-service tracking.

---

## 6. cPanel Shared Hosting (Phusion Passenger) Deployment Strategy

### Challenges on Shared cPanel:
1. **Dynamic Port**: Passenger passes an unpredictable internal port via `process.env.PORT`.
2. **Idle Sleep**: CloudLinux suspends inactive Node.js processes after ~10-15 minutes of zero traffic.
3. **RAM Constraints**: Shared accounts typically have 512MB - 1GB RAM limits; running `npm run build` directly on the server can trigger an Out-Of-Memory (OOM) kill.

### Production Solution:
1. **Build Locally with Standalone Output**:
   In `next.config.mjs`:
   ```javascript
   /** @type {import('next').NextConfig} */
   const nextConfig = {
     output: 'standalone',
     images: {
       remotePatterns: [
         { protocol: 'https', hostname: 'roseebelle.com' },
       ],
     },
   };
   export default nextConfig;
   ```
   Running `npm run build` locally produces `.next/standalone/`. Next.js generates its own minimal, self-contained `server.js` inside `.next/standalone/` that automatically reads `process.env.PORT`.

2. **cPanel Deployment Steps**:
   - Upload the contents of `.next/standalone/` directly into your cPanel application root (e.g. `/home/username/roseebelle-app/`).
   - Copy `.next/static/` into `/home/username/roseebelle-app/.next/static/`.
   - Copy `public/` into `/home/username/roseebelle-app/public/`.
   - In cPanel **"Setup Node.js App"**:
     - **Node.js Version**: 18.x or 20.x
     - **Application Mode**: Production
     - **Application Startup File**: `server.js` (The generated standalone server.js)
     - **Environment Variables**:
       - `PORT` (Provided by Passenger)
       - `NODE_ENV=production`
       - `NEXT_PUBLIC_WORDPRESS_URL=https://roseebelle.com`
       - `REVALIDATION_SECRET=your_random_secret_token`

---

## 7. Review Checklist for Peer Developers

When sharing this note with team members or senior developers, verify:
- [ ] **GraphQL vs Store API separation**: Is WPGraphQL preferred for catalog queries and Store API for session-based cart/checkout? *(Yes, standard headless WC best practice)*
- [ ] **Session Handling**: Is `Cart-Token` sufficient for headless guests without WP cookie auth? *(Yes, Store API was specifically designed by Automattic for this)*
- [ ] **ISR vs SSR**: Is 60s revalidation with webhook on-demand invalidation appropriate for e-commerce catalog speed? *(Yes, provides sub-200ms page loads)*
- [ ] **cPanel Deployment**: Is local build + standalone upload agreed upon over running `npm run build` on low-RAM shared hosting? *(Strongly recommended)*
