╔══════════════════════════════════════════════════════════════════╗
║         SHOP FRONTEND ARCHITECTURE OVERVIEW                      ║
║         Alpine.js + Jinja2 + Tailwind CSS + Multi-Theme          ║
╚══════════════════════════════════════════════════════════════════╝

📦 WHAT IS THIS?
═════════════════════════════════════════════════════════════════

Customer-facing shop frontend provides visitors with a branded
e-commerce experience unique to each store. Built with:
  ✅ Jinja2 Templates (server-side rendering)
  ✅ Alpine.js (client-side reactivity)
  ✅ Tailwind CSS (utility-first styling)
  ✅ Multi-Theme System (store branding)
  ✅ FastAPI (backend routes)


🎯 KEY PRINCIPLES
═════════════════════════════════════════════════════════════════

1. Theme-First Design
   • Each store has unique colors, fonts, logos
   • CSS variables for dynamic theming
   • Custom CSS support per store
   • Dark mode with store colors

2. Progressive Enhancement
   • Works without JavaScript (basic HTML)
   • JavaScript adds cart, search, filters
   • Graceful degradation for older browsers

3. API-First Data Loading
   • All products from REST APIs
   • Client-side cart management
   • Real-time stock updates
   • Search and filtering

4. Responsive & Mobile-First
   • Mobile-first Tailwind approach
   • Touch-friendly interactions
   • Optimized images
   • Fast page loads


📁 FILE STRUCTURE
═════════════════════════════════════════════════════════════════

app/
├── templates/shop/
│   ├── base.html                    ← ✅ Base template (layout + theme)
│   ├── home.html                    ← ✅ Homepage / featured products
│   ├── products.html                ← ✅ Product catalog with filters
│   ├── product.html                 ← Product detail page
│   ├── cart.html                    ← Shopping cart
│   ├── checkout.html                ← Checkout flow
│   ├── search.html                  ← Search results
│   ├── account/                     ← Customer account pages
│   │   ├── login.html               ← ✅ Customer login (IMPLEMENTED)
│   │   ├── register.html            ← ✅ Customer registration (IMPLEMENTED)
│   │   ├── forgot-password.html     ← ✅ Password reset (IMPLEMENTED)
│   │   ├── dashboard.html
│   │   ├── orders.html
│   │   ├── profile.html
│   │   └── addresses.html
│   └── errors/                      ← Error pages
│       ├── 400.html
│       ├── 404.html
│       └── 500.html
│
├── static/shop/
│   ├── css/
│   │   └── shop.css                 ← ✅ Shop-specific styles (IMPLEMENTED)
│   ├── js/
│   │   └── shop-layout.js           ← ✅ Base shop functionality (IMPLEMENTED)
│   └── img/
│       └── (placeholder images)
│
├── static/shared/                   ← ✅ Shared across all areas (IMPLEMENTED)
│   ├── js/
│   │   ├── log-config.js            ← ✅ Logging setup
│   │   ├── icons.js                 ← ✅ Icon registry
│   │   ├── utils.js                 ← ✅ Utility functions
│   │   └── api-client.js            ← ✅ API wrapper
│   └── css/
│       └── (shared styles if needed)
│
└── routes/
    └── shop_pages.py                ← ✅ Route handlers (IMPLEMENTED)


🏗️  ARCHITECTURE LAYERS
═════════════════════════════════════════════════════════════════

Layer 1: Routes (FastAPI)
  ↓
Layer 2: Middleware (Store + Theme Detection)
  ↓
Layer 3: Templates (Jinja2)
  ↓
Layer 4: JavaScript (Alpine.js)
  ↓
Layer 5: API (REST endpoints)
  ↓
Layer 6: Database


Layer 1: ROUTES (FastAPI)
──────────────────────────────────────────────────────────────────
Purpose: Store Detection + Template Rendering
Location: app/routes/shop_pages.py

⚠️ ROUTE REGISTRATION (main.py):
The shop router is mounted at TWO prefixes to support both access methods:

  # main.py
  app.include_router(shop_pages.router, prefix="/shop", ...)           # Domain/subdomain
  app.include_router(shop_pages.router, prefix="/stores/{store_code}/shop", ...)  # Path-based

This means routes defined WITHOUT /shop prefix in shop_pages.py:
  @router.get("/products")  →  /shop/products  OR  /stores/{code}/shop/products

❌ COMMON MISTAKE: Don't add /shop prefix in route definitions!
  @router.get("/shop/products")  ❌ WRONG - creates /shop/shop/products
  @router.get("/products")       ✅ CORRECT - creates /shop/products

Example Route Handler:
  @router.get("/", response_class=HTMLResponse, include_in_schema=False)
  @router.get("/products", response_class=HTMLResponse, include_in_schema=False)
  async def shop_products_page(request: Request):
      """
      Render shop homepage / product catalog.
      Store and theme are auto-injected by middleware.
      """
      return templates.TemplateResponse(
          "shop/products.html",
          get_shop_context(request)  # Helper function
      )

Helper Function:
  def get_shop_context(request: Request, **extra_context) -> dict:
      """Build template context with store/theme from middleware"""
      store = getattr(request.state, 'store', None)
      theme = getattr(request.state, 'theme', None)
      clean_path = getattr(request.state, 'clean_path', request.url.path)
      store_context = getattr(request.state, 'store_context', None)

      # Get detection method (domain, subdomain, or path)
      access_method = store_context.get('detection_method', 'unknown') if store_context else 'unknown'

      # Calculate base URL for links
      # - Domain/subdomain: base_url = "/"
      # - Path-based: base_url = "/store/{store_code}/"
      base_url = "/"
      if access_method == "path" and store:
          full_prefix = store_context.get('full_prefix', '/store/')
          base_url = f"{full_prefix}{store.subdomain}/"

      return {
          "request": request,
          "store": store,
          "theme": theme,
          "clean_path": clean_path,
          "access_method": access_method,
          "base_url": base_url,  # ⭐ Used for all links in templates
          **extra_context
      }

Responsibilities:
  ✅ Access store from middleware (request.state.store)
  ✅ Access theme from middleware (request.state.theme)
  ✅ Calculate base_url for routing-aware links
  ✅ Render template with context
  ❌ NO database queries (data loaded client-side via API)
  ❌ NO business logic (handled by API endpoints)


⭐ MULTI-ACCESS ROUTING (Domain, Subdomain, Path-Based)
──────────────────────────────────────────────────────────────────
The shop frontend supports THREE access methods:

1. **Custom Domain** (Production)
   URL: https://customdomain.com/shop/products
   - Store has their own domain
   - base_url = "/"
   - Links: /shop/products, /shop/about, /shop/contact

2. **Subdomain** (Production)
   URL: https://orion.letzshop.com/shop/products
   - Store uses platform subdomain
   - base_url = "/"
   - Links: /shop/products, /shop/about, /shop/contact

3. **Path-Based** (Development/Testing)
   URL: http://localhost:8000/stores/orion/shop/products
   - Store accessed via path prefix
   - base_url = "/stores/orion/"
   - Links: /stores/orion/shop/products, /stores/orion/shop/about

⚠️ CRITICAL: All template links MUST use {{ base_url }}shop/ prefix

Example:
  ❌ BAD:  <a href="/products">Products</a>
  ❌ BAD:  <a href="{{ base_url }}products">Products</a>
  ✅ GOOD: <a href="{{ base_url }}shop/products">Products</a>

Note: The router is mounted at /shop prefix in main.py, so all links need shop/ after base_url

How It Works:
  1. StoreContextMiddleware detects access method
  2. Sets request.state.store_context with detection_method
  3. get_shop_context() calculates base_url from detection_method
  4. Templates use {{ base_url }} for all internal links
  5. Links work correctly regardless of access method


Layer 2: MIDDLEWARE
──────────────────────────────────────────────────────────────────
Purpose: Store & Theme Identification

Two middleware components work together:

1. Store Context Middleware (middleware/store_context.py)
   • Detects store from domain/subdomain/path
   • Sets request.state.store
   • Sets request.state.store_context (includes detection_method)
   • Sets request.state.clean_path (path without store prefix)
   • Returns 404 if store not found

2. Theme Context Middleware (middleware/theme_context.py)
   • Loads theme for detected store
   • Sets request.state.theme
   • Falls back to default theme

Order matters:
  store_context_middleware → theme_context_middleware

Detection Methods:
  - custom_domain: Store has custom domain
  - subdomain: Store uses platform subdomain
  - path: Store accessed via /store/{code}/ or /stores/{code}/


Layer 3: TEMPLATES (Jinja2)
──────────────────────────────────────────────────────────────────
Purpose: HTML Structure + Store Branding
Location: app/templates/shop/

Template Hierarchy:
  base.html (layout + theme injection)
    ↓
  home.html (product grid)
    ↓
  partials/product-card.html (components)

Example:
  {% extends "shop/base.html" %}
  {% block title %}{{ store.name }}{% endblock %}
  {% block alpine_data %}shopHome(){% endblock %}
  {% block content %}
    <div x-show="loading">Loading products...</div>
    <div x-show="!loading" class="grid grid-cols-1 md:grid-cols-4 gap-6">
      <template x-for="product in products" :key="product.id">
        <!-- Product card -->
      </template>
    </div>
  {% endblock %}

Key Features:
  ✅ Theme CSS variables injection
  ✅ Store logo (light/dark mode)
  ✅ Custom CSS from theme
  ✅ Social links from theme
  ✅ Dynamic favicon


Layer 4: JAVASCRIPT (Alpine.js)
──────────────────────────────────────────────────────────────────
Purpose: Client-Side Interactivity + Cart + Search
Location: app/static/shop/js/

⚠️ CRITICAL: JavaScript Loading Order
──────────────────────────────────────────────────────────────────
Scripts MUST load in this exact order (see base.html):

  1. log-config.js         ← Logging system (loads first)
  2. icons.js              ← Icon registry
  3. shop-layout.js        ← Alpine component (before Alpine!)
  4. utils.js              ← Utility functions
  5. api-client.js         ← API wrapper
  6. Alpine.js (deferred)  ← Loads last
  7. Page-specific JS      ← Optional page scripts

Why This Order Matters:
  • shop-layout.js defines shopLayoutData() BEFORE Alpine initializes
  • Alpine.js defers to ensure DOM is ready
  • Shared utilities available to all scripts
  • Icons and logging available immediately

Example from base.html:
  <script src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
  <script src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
  <script src="{{ url_for('static', path='shop/js/shop-layout.js') }}"></script>
  <script src="{{ url_for('static', path='shared/js/utils.js') }}"></script>
  <script src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
  <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>

Alpine.js Component Architecture:
──────────────────────────────────────────────────────────────────

⭐ BASE COMPONENT (shop-layout.js):

Provides shared functionality for all shop pages:

  function shopLayoutData() {
      return {
          // Theme state
          dark: localStorage.getItem('shop-theme') === 'dark',

          // UI state
          mobileMenuOpen: false,
          searchOpen: false,
          cartCount: 0,

          // Cart state
          cart: [],

          init() {
              shopLog.info('Shop layout initializing...');
              this.loadCart();
              window.addEventListener('cart-updated', () => {
                  this.loadCart();
              });
              shopLog.info('Shop layout initialized');
          },

          addToCart(product, quantity = 1) {
              const existingIndex = this.cart.findIndex(
                  item => item.id === product.id
              );

              if (existingIndex !== -1) {
                  this.cart[existingIndex].quantity += quantity;
              } else {
                  this.cart.push({
                      id: product.id,
                      name: product.name,
                      price: product.price,
                      image: product.image,
                      quantity: quantity
                  });
              }

              this.saveCart();
              this.showToast(`${product.name} added to cart`, 'success');
          },

          toggleTheme() {
              this.dark = !this.dark;
              localStorage.setItem('shop-theme',
                  this.dark ? 'dark' : 'light');
              shopLog.debug('Theme toggled:', this.dark ? 'dark' : 'light');
          },

          showToast(message, type = 'info') {
              // Toast notification implementation
          }
      };
  }

  // Make globally available
  window.shopLayoutData = shopLayoutData;

⭐ PAGE-SPECIFIC COMPONENTS:

Each page extends shopLayoutData() for page-specific functionality:

  // Example: products.html
  document.addEventListener('alpine:init', () => {
      Alpine.data('shopProducts', () => ({
          ...shopLayoutData(),  // Extend base component

          // Page-specific state
          products: [],
          loading: true,
          filters: { search: '', category: '' },

          // Override init to add page-specific initialization
          async init() {
              shopLog.info('Products page initializing...');
              this.loadCart();  // From shopLayoutData
              await this.loadProducts();  // Page-specific
          },

          // Page-specific methods
          async loadProducts() {
              const response = await fetch('/api/v1/shop/products');
              const data = await response.json();
              this.products = data.products;
              this.loading = false;
          }
      }));
  });

Template Usage:
──────────────────────────────────────────────────────────────────

  {# In base.html - uses block to allow override #}
  <html x-data="{% block alpine_data %}shopLayoutData(){% endblock %}"
        x-bind:class="{ 'dark': dark }">

  {# In products.html - overrides to use page-specific component #}
  {% block alpine_data %}shopProducts(){% endblock %}

  {# In home.html - uses default base component #}
  {# No block override needed, inherits shopLayoutData() #}

⭐ COMPONENT HIERARCHY:

  shopLayoutData()           ← Base component (shared state & methods)
      ↓
  shopProducts()             ← Products page (extends base + products state)
  shopCart()                 ← Cart page (extends base + cart state)
  shopCheckout()             ← Checkout page (extends base + order state)
  shopAccount()              ← Account page (extends base + user state)

Benefits:
  ✅ Shared functionality (theme, cart, toasts) available on all pages
  ✅ Each page has its own state and methods
  ✅ DRY - base functionality defined once
  ✅ Flexible - pages can override init() or add new methods

Tradeoffs:
  ⚠️  One component per page (not multiple components)
  ⚠️  All page state is at root level
  ⚠️  Can't easily split page into independent sub-components

Best Practices:
  1. Always extend shopLayoutData() in page components
  2. Override init() if you need page-specific initialization
  3. Call parent methods when needed (this.loadCart(), this.showToast())
  4. Keep page-specific state in the page component
  5. Keep shared state in shopLayoutData()

Responsibilities:
  ✅ Load products from API
  ✅ Manage cart in localStorage
  ✅ Handle search and filters
  ✅ Update DOM reactively
  ✅ Theme toggling (light/dark)
  ✅ Mobile menu management
  ✅ Toast notifications


Layer 5: API (REST)
──────────────────────────────────────────────────────────────────
Purpose: Product Data + Cart + Orders
Location: app/api/v1/shop/*.py

⭐ NEW API STRUCTURE (as of 2025-11-22):
All shop endpoints use middleware-based store context.
NO store_id or store_code in URLs!

Example Endpoints:
  GET    /api/v1/shop/products              ← Product catalog
  GET    /api/v1/shop/products/{id}         ← Product details
  GET    /api/v1/shop/products?search=...   ← Search products
  GET    /api/v1/shop/cart/{session_id}     ← Get cart
  POST   /api/v1/shop/cart/{session_id}/items  ← Add to cart
  PUT    /api/v1/shop/cart/{session_id}/items/{product_id}  ← Update item
  DELETE /api/v1/shop/cart/{session_id}/items/{product_id}  ← Remove item
  POST   /api/v1/shop/orders                ← Place order (auth required)
  GET    /api/v1/shop/orders                ← Order history (auth required)
  POST   /api/v1/shop/auth/login            ← Customer login
  POST   /api/v1/shop/auth/register         ← Customer registration
  GET    /api/v1/shop/content-pages/navigation  ← CMS navigation
  GET    /api/v1/shop/content-pages/{slug}  ← CMS page content

How Store Context Works:
  1. Browser makes API call from shop page (e.g., /stores/orion/shop/products)
  2. Browser automatically sends Referer header: http://localhost:8000/stores/orion/shop/products
  3. StoreContextMiddleware extracts store from Referer header
  4. Middleware sets request.state.store = <Store: orion>
  5. API endpoint accesses store: store = request.state.store
  6. No store_id needed in URL!


🔄 DATA FLOW
═════════════════════════════════════════════════════════════════

Page Load Flow:
──────────────────────────────────────────────────────────────────
  1. Customer → visits acme-shop.com (or /stores/acme/shop/products)
  2. Store Middleware → Identifies "ACME" store from domain/path
  3. Theme Middleware → Loads ACME's theme config
  4. FastAPI → Renders shop/products.html
  5. Browser → Receives HTML with theme CSS variables
  6. Alpine.js → init() executes
  7. JavaScript → GET /api/v1/shop/products (with Referer header)
  8. Middleware → Extracts store from Referer, injects into request.state
  9. API → Returns product list JSON for ACME store
  10. Alpine.js → Updates products array
  11. Browser → DOM updates with product cards

Add to Cart Flow:
──────────────────────────────────────────────────────────────────
  1. Customer → Clicks "Add to Cart"
  2. Alpine.js → addToCart(product, quantity)
  3. Alpine.js → Updates cart array
  4. Alpine.js → Saves to localStorage
  5. Alpine.js → Updates cartCount badge
  6. Alpine.js → Shows toast notification
  7. Browser → Cart icon updates automatically

Checkout Flow:
──────────────────────────────────────────────────────────────────
  1. Customer → Goes to /cart
  2. Page → Loads cart from localStorage
  3. Customer → Fills checkout form
  4. Alpine.js → POST /api/v1/shop/orders (with Referer header)
  5. Middleware → Extracts store from Referer
  6. API → Creates order + payment intent for store
  7. Alpine.js → Redirects to payment
  8. Payment → Completes
  9. Redirect → /order/{order_id}/confirmation


🎨 MULTI-THEME SYSTEM
═════════════════════════════════════════════════════════════════

How Themes Work:

1. Database Storage
   • Each store has a theme record
   • Stores colors, fonts, logos, layout prefs
   • Custom CSS per store

2. CSS Variables Injection
   • base.html injects variables in <style> tag
   • Variables available throughout page
   • Example:
     :root {
         --color-primary: #6366f1;
         --color-secondary: #8b5cf6;
         --color-accent: #ec4899;
         --color-background: #ffffff;
         --color-text: #1f2937;
         --font-heading: Inter, sans-serif;
         --font-body: Inter, sans-serif;
     }

3. Usage in Templates
   <button style="background-color: var(--color-primary)">
       Buy Now
   </button>

4. Dark Mode
   • Store colors adjust for dark mode
   • Saved in localStorage
   • Applied via :class="{ 'dark': dark }"
   • Uses dark: variants in Tailwind


Theme Configuration Example:
──────────────────────────────────────────────────────────────────
{
    "theme_name": "modern",
    "colors": {
        "primary": "#6366f1",
        "secondary": "#8b5cf6",
        "accent": "#ec4899",
        "background": "#ffffff",
        "text": "#1f2937"
    },
    "fonts": {
        "heading": "Inter, sans-serif",
        "body": "Inter, sans-serif"
    },
    "branding": {
        "logo": "/media/stores/acme/logo.png",
        "logo_dark": "/media/stores/acme/logo-dark.png",
        "favicon": "/media/stores/acme/favicon.ico"
    },
    "layout": {
        "header": "fixed",
        "style": "grid"
    },
    "social_links": {
        "facebook": "https://facebook.com/acme",
        "instagram": "https://instagram.com/acme"
    },
    "custom_css": ".product-card { border-radius: 12px; }"
}


🛒 CART SYSTEM
═════════════════════════════════════════════════════════════════

Client-Side Cart Management:

Storage: localStorage
Format: JSON array of cart items

Cart Item Structure:
{
    "id": "product-123",
    "name": "Product Name",
    "price": 29.99,
    "quantity": 2,
    "image": "/media/products/image.jpg",
    "store_code": "ACME"
}

Key Functions:
  • loadCart(): Load from localStorage
  • saveCart(): Persist to localStorage
  • addToCart(product, quantity): Add item
  • updateCartItem(id, quantity): Update quantity
  • removeFromCart(id): Remove item
  • clearCart(): Empty cart
  • cartTotal: Computed total price

Cart Persistence:
  • Survives page refresh
  • Shared across shop pages
  • Cleared on checkout completion
  • Synced across tabs (optional)


🔍 SEARCH & FILTERS
═════════════════════════════════════════════════════════════════

Search System:

1. Search Modal
   • Overlay with input
   • Live search as you type
   • Keyboard shortcuts (Cmd+K)

2. Search API
   POST /api/v1/shop/{store_code}/search
   {
       "query": "laptop",
       "category": "electronics",
       "min_price": 100,
       "max_price": 1000,
       "sort": "price:asc"
   }

3. Client-Side Filtering
   • Filter products array
   • No API call needed for basic filters
   • Use for in-memory datasets

Filter Components:
  • Category dropdown
  • Price range slider
  • Sort options
  • Availability toggle
  • Brand checkboxes


📱 RESPONSIVE DESIGN
═════════════════════════════════════════════════════════════════

Breakpoints (Tailwind):
  • sm: 640px  (mobile landscape)
  • md: 768px  (tablet)
  • lg: 1024px (desktop)
  • xl: 1280px (large desktop)

Product Grid Responsive:
  • Mobile: 1 column
  • Tablet: 2 columns
  • Desktop: 4 columns

Example:
  <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
    <!-- Product cards -->
  </div>

Touch Optimization:
  • Larger touch targets (min 44x44px)
  • Swipeable carousels
  • Touch-friendly buttons
  • Tap to zoom images


🌙 DARK MODE
═════════════════════════════════════════════════════════════════

Implementation:
  1. Alpine.js state: dark: boolean
  2. HTML class binding: :class="{ 'dark': dark }"
  3. Tailwind variants: dark:bg-gray-800
  4. LocalStorage persistence
  5. Store colors adapt to dark mode

Toggle Button:
  <button @click="toggleTheme()">
      <svg x-show="!dark"><!-- Sun icon --></svg>
      <svg x-show="dark"><!-- Moon icon --></svg>
  </button>

Dark Mode Colors:
  • Background: dark:bg-gray-900
  • Text: dark:text-gray-100
  • Borders: dark:border-gray-700
  • Cards: dark:bg-gray-800

Store Colors:
  • Primary color adjusts brightness
  • Maintains brand identity
  • Readable in both modes


🔐 CUSTOMER AUTHENTICATION
═════════════════════════════════════════════════════════════════

Optional Auth System:

Guest Checkout:
  ✅ No account required
  ✅ Email for order updates
  ✅ Quick checkout

Account Features:
  ✅ Order history
  ✅ Saved addresses
  ✅ Wishlist
  ✅ Profile management

Auth Flow:
  1. Login/Register → POST /api/v1/shop/auth/login (with Referer header)
  2. Middleware → Extracts store from Referer
  3. API → Validates credentials for store's customers
  4. API → Returns JWT token + sets cookie (path=/shop)
  5. JavaScript → Store token in localStorage
  6. API Client → Add token to authenticated requests
  7. Optional → Use account features (orders, profile, etc.)

## Authentication Pages

*Added: 2025-11-24*

All authentication pages use Tailwind CSS, Alpine.js, and theme integration
for a consistent, branded experience across all stores.

✅ Login Page (app/templates/shop/account/login.html)
──────────────────────────────────────────────────────────────────
Route: /shop/account/login

Features:
  • Two-column layout (branding + form)
  • Email and password fields with validation
  • Password visibility toggle
  • "Remember me" checkbox
  • Error and success message alerts
  • Loading states with animated spinner
  • Links to register and forgot password
  • Theme-aware colors from CSS variables
  • Dark mode support
  • Mobile responsive design

Alpine.js Component:
  function customerLogin() {
      return {
          credentials: { email: '', password: '' },
          rememberMe: false,
          showPassword: false,
          loading: false,
          errors: {},
          alert: { show: false, type: 'error', message: '' },
          dark: false,

          async handleLogin() {
              // POST /api/v1/shop/auth/login
              // Store token in localStorage
              // Redirect to account or return URL
          }
      }
  }

API Endpoint:
  POST /api/v1/shop/auth/login
  Body: { email_or_username, password }
  Returns: { access_token, user }

✅ Register Page (app/templates/shop/account/register.html)
──────────────────────────────────────────────────────────────────
Route: /shop/account/register

Features:
  • Two-column layout with store branding
  • First name, last name, email fields
  • Phone number (optional)
  • Password with strength requirements
  • Confirm password field
  • Marketing consent checkbox
  • Real-time client-side validation
  • Password visibility toggle
  • Theme-aware styling
  • Loading states
  • Redirects to login after success

Validation Rules:
  • First name: required
  • Last name: required
  • Email: required, valid format
  • Password: min 8 chars, 1 letter, 1 number
  • Confirm password: must match password

Alpine.js Component:
  function customerRegistration() {
      return {
          formData: {
              first_name: '', last_name: '', email: '',
              phone: '', password: '', marketing_consent: false
          },
          confirmPassword: '',

          validateForm() {
              // Validates all fields
              // Returns true if valid
          },

          async handleRegister() {
              // POST /api/v1/shop/auth/register
              // Redirect to login?registered=true
          }
      }
  }

API Endpoint:
  POST /api/v1/shop/auth/register
  Body: { first_name, last_name, email, phone?, password, marketing_consent }
  Returns: { message }

✅ Forgot Password Page (app/templates/shop/account/forgot-password.html)
──────────────────────────────────────────────────────────────────
Route: /shop/account/forgot-password

Features:
  • Two-column layout with store branding
  • Email input field
  • Two-state interface:
    1. Form submission state
    2. Success confirmation state
  • Success state with checkmark icon
  • Option to retry if email not received
  • Theme-aware styling
  • Links back to login and shop
  • Dark mode support

Alpine.js Component:
  function forgotPassword() {
      return {
          email: '',
          emailSent: false,
          loading: false,

          async handleSubmit() {
              // POST /api/v1/shop/auth/forgot-password
              // Show success message
              // emailSent = true
          }
      }
  }

API Endpoint:
  POST /api/v1/shop/auth/forgot-password
  Body: { email }
  Returns: { message }

🎨 THEME INTEGRATION
──────────────────────────────────────────────────────────────────

All authentication pages inject store theme CSS variables:

  <style id="store-theme-variables">
      :root {
          {% for key, value in theme.css_variables.items() %}
          {{ key }}: {{ value }};
          {% endfor %}
      }

      /* Theme-aware button and focus colors */
      .btn-primary-theme {
          background-color: var(--color-primary);
      }
      .btn-primary-theme:hover:not(:disabled) {
          background-color: var(--color-primary-dark, var(--color-primary));
          filter: brightness(0.9);
      }
      .focus-primary:focus {
          border-color: var(--color-primary);
          box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb, 124, 58, 237), 0.1);
      }
  </style>

Key Theme Elements:
  • Left panel background: var(--color-primary)
  • Submit buttons: var(--color-primary)
  • Links: var(--color-primary)
  • Checkboxes: var(--color-primary)
  • Focus states: var(--color-primary) with transparency
  • Store logo from theme.branding.logo

Benefits:
  ✅ Each store's auth pages match their brand
  ✅ Consistent with main shop design
  ✅ Dark mode adapts to store colors
  ✅ Professional, polished appearance

📱 RESPONSIVE DESIGN
──────────────────────────────────────────────────────────────────

Mobile (<640px):
  • Vertical layout (image on top, form below)
  • Smaller padding and spacing
  • Full-width buttons
  • Touch-friendly input fields

Tablet (640px-1024px):
  • Side-by-side layout begins
  • Balanced column widths
  • Comfortable spacing

Desktop (>1024px):
  • Full two-column layout
  • Max width container (max-w-4xl)
  • Centered on page
  • Larger brand imagery

🔒 SECURITY FEATURES
──────────────────────────────────────────────────────────────────

Client-Side:
  • Input validation before submission
  • Password visibility toggle
  • HTTPS required
  • No sensitive data in URLs
  • Token stored in localStorage (not cookies)

Server-Side (API handles):
  • Password hashing (bcrypt)
  • Email verification
  • Rate limiting
  • CSRF protection
  • SQL injection prevention


📡 API CLIENT
═════════════════════════════════════════════════════════════════

Location: app/static/shared/js/api-client.js

⭐ NEW USAGE (as of 2025-11-22):
No store_code needed! Store extracted from Referer header automatically.

Usage:
  // Product catalog
  const products = await fetch('/api/v1/shop/products');

  // Add to cart
  const response = await fetch('/api/v1/shop/cart/session123/items', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ product_id: 1, quantity: 2 })
  });

  // Place order
  const order = await fetch('/api/v1/shop/orders', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(orderData)
  });

Features:
  ✅ Automatic error handling
  ✅ JSON parsing
  ✅ Loading states
  ✅ Auth token injection (if logged in)


🐛 LOGGING
═════════════════════════════════════════════════════════════════

Location: app/static/shared/js/log-config.js

Shop-Specific Logging:
  shopLog.info('Product added to cart', product);
  shopLog.error('Checkout failed', error);
  shopLog.debug('Search query', { query, results });

Levels:
  • INFO: User actions
  • ERROR: Failures and exceptions
  • DEBUG: Development debugging
  • WARN: Warnings


🎭 ICONS
═════════════════════════════════════════════════════════════════

Location: app/static/shared/js/icons.js

Usage:
  <span x-html="$icon('shopping-cart', 'w-5 h-5')"></span>
  <span x-html="$icon('search', 'w-6 h-6 text-primary')"></span>

Shop Icons:
  • shopping-cart, shopping-bag
  • heart (wishlist)
  • search, filter
  • eye (view)
  • star (rating)
  • truck (shipping)
  • check (success)
  • x (close)
  • chevron-left, chevron-right
  • spinner (loading)


🚀 PERFORMANCE
═════════════════════════════════════════════════════════════════

Optimization Techniques:

1. Image Optimization
   • WebP format
   • Lazy loading
   • Responsive images (srcset)
   • CDN delivery

2. Code Splitting
   • Base layout loads first
   • Page-specific JS loads after
   • Deferred non-critical CSS

3. Caching
   • Browser cache for assets
   • LocalStorage for cart
   • Service worker (optional)

4. Lazy Loading
   • Products load as you scroll
   • Images load when visible
   • Infinite scroll for large catalogs

5. CDN Assets with Fallback
   • Tailwind CSS from CDN (fallback to local)
   • Alpine.js from CDN (fallback to local)
   • Works offline and in restricted networks
   • See: [CDN Fallback Strategy](../cdn-fallback-strategy.md)


📊 PAGE-BY-PAGE BREAKDOWN
═════════════════════════════════════════════════════════════════

/ (Homepage)
──────────────────────────────────────────────────────────────────
Purpose: Display featured products, hero section
Components:
  • Hero banner with CTA
  • Featured products grid
  • Category cards
  • About store section
Data Sources:
  • GET /api/v1/shop/products?is_featured=true

/products
──────────────────────────────────────────────────────────────────
Purpose: Browse all products with filters
Components:
  • Product grid
  • Filter sidebar
  • Sort dropdown
  • Pagination
Data Sources:
  • GET /api/v1/shop/products?skip=0&limit=20
  • GET /api/v1/shop/products?search=query
  • Filters applied client-side or server-side

/products/{product_id}
──────────────────────────────────────────────────────────────────
Purpose: Single product detail page
Components:
  • Image gallery
  • Product info
  • Add to cart form
  • Related products
  • Reviews (optional)
Data Sources:
  • GET /api/v1/shop/products/{id}
  • GET /api/v1/shop/products?limit=4 (related products)

/cart
──────────────────────────────────────────────────────────────────
Purpose: Review cart contents before checkout
Components:
  • Cart items list
  • Quantity adjusters
  • Remove buttons
  • Cart total
  • Checkout button
Data Sources:
  • LocalStorage cart
  • No API call needed

/checkout
──────────────────────────────────────────────────────────────────
Purpose: Complete purchase
Components:
  • Shipping form
  • Payment form
  • Order summary
  • Submit button
Data Sources:
  • POST /api/v1/shop/orders
  • Stripe/PayPal integration

/search
──────────────────────────────────────────────────────────────────
Purpose: Search results page
Components:
  • Search input
  • Results grid
  • Filter options
  • Sort options
Data Sources:
  • GET /api/v1/shop/products?search=query

/category/{category_slug}
──────────────────────────────────────────────────────────────────
Purpose: Browse products by category
Components:
  • Breadcrumbs
  • Product grid
  • Subcategories
  • Filters
Data Sources:
  • GET /api/v1/shop/products?category={slug}

/about
──────────────────────────────────────────────────────────────────
Purpose: About the store
Components:
  • Store story
  • Team photos
  • Values/mission
  • Contact info
Data Sources:
  • Store info from middleware
  • Static content

/contact
──────────────────────────────────────────────────────────────────
Purpose: Contact form
Components:
  • Contact form
  • Map (optional)
  • Business hours
  • Social links
Data Sources:
  • CMS content page (GET /api/v1/shop/content-pages/contact)
  • Form submission to store email


🎓 LEARNING PATH
═════════════════════════════════════════════════════════════════

For New Developers:

1. Understand Architecture (1 hour)
   → Read this document
   → Review file structure
   → Examine base template
   → Understand theme system

2. Study Existing Page (2 hours)
   → Open home.html
   → Open shop-layout.js
   → Trace product loading flow
   → Examine cart management

3. Create Simple Page (4 hours)
   → Copy templates
   → Modify for new feature
   → Test with different store themes
   → Verify responsive design

4. Add Complex Feature (1 day)
   → Product filters
   → Cart operations
   → API integration
   → Search functionality

5. Master Patterns (1 week)
   → All common patterns
   → Theme customization
   → Performance optimization
   → Mobile responsiveness


🔄 DEPLOYMENT CHECKLIST
═════════════════════════════════════════════════════════════════

Before Deploying:
  □ Build Tailwind CSS
  □ Minify JavaScript
  □ Test all routes
  □ Test with multiple store themes
  □ Verify cart persistence
  □ Check mobile responsive
  □ Test dark mode
  □ Validate product display
  □ Test checkout flow
  □ Check image optimization
  □ Test search functionality
  □ Verify social links
  □ Test across browsers
  □ Check console for errors
  □ Test in production mode


🚨 ERROR HANDLING & ERROR PAGES
═════════════════════════════════════════════════════════════════

Multi-Access Aware Error Pages:

All shop error pages (404, 500, etc.) are store-context aware and display
correct links based on the access method (domain, subdomain, or path-based).

Error Page Templates:
  • app/templates/shop/errors/404.html - Not Found
  • app/templates/shop/errors/400.html - Bad Request
  • app/templates/shop/errors/401.html - Unauthorized
  • app/templates/shop/errors/403.html - Forbidden
  • app/templates/shop/errors/422.html - Validation Error
  • app/templates/shop/errors/429.html - Rate Limited
  • app/templates/shop/errors/500.html - Server Error
  • app/templates/shop/errors/502.html - Bad Gateway
  • app/templates/shop/errors/base.html - Base error template
  • app/templates/shop/errors/generic.html - Generic error

Error Renderer (app/exceptions/error_renderer.py):

Calculates base_url dynamically based on store access method:

  def _get_context_data(self, request: Request, ...):
      store = getattr(request.state, 'store', None)
      access_method = getattr(request.state, "access_method", None)
      store_context = getattr(request.state, "store_context", None)

      # Calculate base_url for shop links
      base_url = "/"
      if access_method == "path" and store:
          full_prefix = store_context.get('full_prefix', '/store/')
          base_url = f"{full_prefix}{store.subdomain}/"

      return {
          "request": request,
          "store": store,
          "base_url": base_url,  # ⭐ Used in error templates
          ...
      }

Error Template Usage:

All error page links use {{ base_url }} prefix for correct routing:

  {# ❌ BAD - Hardcoded links #}
  <a href="/">Continue Shopping</a>
  <a href="/products">View Products</a>

  {# ✅ GOOD - Context-aware links #}
  <a href="{{ base_url or '/' }}">Continue Shopping</a>
  <a href="{{ base_url or '/' }}products">View Products</a>

How It Works:

1. Error occurs (404, 500, etc.)
2. Exception handler detects shop context
3. error_renderer.py calculates base_url from store_context
4. Error template renders with correct base_url
5. Links work for all access methods:
   - Domain: customshop.com → base_url = "/"
   - Subdomain: orion.platform.com → base_url = "/"
   - Path: localhost/stores/orion/ → base_url = "/stores/orion/"

Benefits:
  ✅ Error pages work correctly regardless of access method
  ✅ No broken links in error states
  ✅ Consistent user experience
  ✅ Store branding maintained in errors


🔒 SECURITY
═════════════════════════════════════════════════════════════════

Best Practices:

1. Input Validation
   ✅ Validate all form inputs
   ✅ Sanitize user content
   ✅ XSS prevention

2. Cart Security
   ✅ Validate cart on server
   ✅ Check stock availability
   ✅ Verify prices server-side
   ✅ Never trust client cart

3. Payment Security
   ✅ Use trusted payment providers
   ✅ Never store card details
   ✅ HTTPS only
   ✅ PCI compliance

4. Rate Limiting
   ✅ Search endpoint throttling
   ✅ Contact form limits
   ✅ Checkout attempt limits


📚 REFERENCE LINKS
═════════════════════════════════════════════════════════════════

Documentation:
  • Alpine.js: https://alpinejs.dev/
  • Tailwind CSS: https://tailwindcss.com/
  • Jinja2: https://jinja.palletsprojects.com/
  • FastAPI: https://fastapi.tiangolo.com/

Internal Docs:
  • Page Template Guide: FRONTEND_SHOP_ALPINE_PAGE_TEMPLATE.md
  • Multi-Theme Guide: MULTI_THEME_SHOP_GUIDE.md
  • API Documentation: API_REFERENCE.md
  • Database Schema: DATABASE_SCHEMA.md


══════════════════════════════════════════════════════════════════
                    SHOP FRONTEND ARCHITECTURE
         Theme-Driven, Customer-Focused, Brand-Consistent
══════════════════════════════════════════════════════════════════
