╔══════════════════════════════════════════════════════════════════╗ ║ STOREFRONT FRONTEND ARCHITECTURE OVERVIEW ║ ║ Alpine.js + Jinja2 + Tailwind CSS + Multi-Theme ║ ╚══════════════════════════════════════════════════════════════════╝ 📦 WHAT IS THIS? ═════════════════════════════════════════════════════════════════ Customer-facing storefront 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/storefront/ │ ├── 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/storefront/ │ ├── css/ │ │ └── storefront.css ← ✅ Storefront-specific styles (IMPLEMENTED) │ ├── js/ │ │ └── storefront-layout.js ← ✅ Base storefront 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/ └── storefront_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/storefront_pages.py ⚠️ ROUTE REGISTRATION (main.py): The storefront router is mounted at TWO prefixes to support both access methods: # main.py app.include_router(storefront_pages.router, prefix="/storefront", ...) # Domain/subdomain app.include_router(storefront_pages.router, prefix="/storefront/{store_code}", ...) # Path-based This means routes defined WITHOUT /storefront prefix in storefront_pages.py: @router.get("/products") → /storefront/products OR /storefront/{code}/products ❌ COMMON MISTAKE: Don't add /storefront prefix in route definitions! @router.get("/storefront/products") ❌ WRONG - creates /storefront/storefront/products @router.get("/products") ✅ CORRECT - creates /storefront/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 storefront_products_page(request: Request): """ Render storefront homepage / product catalog. Store and theme are auto-injected by middleware. """ return templates.TemplateResponse( "storefront/products.html", get_storefront_context(request) # Helper function ) Helper Function: def get_storefront_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 storefront frontend supports THREE access methods: 1. **Custom Domain** (Production) URL: https://customdomain.com/storefront/products - Store has their own domain - base_url = "/" - Links: /storefront/products, /storefront/about, /storefront/contact 2. **Subdomain** (Production) URL: https://orion.letzshop.com/storefront/products - Store uses platform subdomain - base_url = "/" - Links: /storefront/products, /storefront/about, /storefront/contact 3. **Path-Based** (Development/Testing) URL: http://localhost:8000/storefront/orion/products - Store accessed via path prefix - base_url = "/storefront/orion/" - Links: /storefront/orion/products, /storefront/orion/about ⚠️ CRITICAL: All template links MUST use {{ base_url }}storefront/ prefix Example: ❌ BAD: Products ❌ BAD: Products ✅ GOOD: Products Note: The router is mounted at /storefront prefix in main.py, so all links need storefront/ after base_url How It Works: 1. StoreContextMiddleware detects access method 2. Sets request.state.store_context with detection_method 3. get_storefront_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/storefront/ Template Hierarchy: base.html (layout + theme injection) ↓ home.html (product grid) ↓ partials/product-card.html (components) Example: {% extends "storefront/base.html" %} {% block title %}{{ store.name }}{% endblock %} {% block alpine_data %}shopHome(){% endblock %} {% block content %}
Loading products...
{% 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/storefront/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. storefront-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: • storefront-layout.js defines storefrontLayoutData() 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: Alpine.js Component Architecture: ────────────────────────────────────────────────────────────────── ⭐ BASE COMPONENT (storefront-layout.js): Provides shared functionality for all storefront pages: function storefrontLayoutData() { return { // Theme state dark: localStorage.getItem('storefront-theme') === 'dark', // UI state mobileMenuOpen: false, searchOpen: false, cartCount: 0, // Cart state cart: [], init() { shopLog.info('Storefront layout initializing...'); this.loadCart(); window.addEventListener('cart-updated', () => { this.loadCart(); }); shopLog.info('Storefront 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('storefront-theme', this.dark ? 'dark' : 'light'); shopLog.debug('Theme toggled:', this.dark ? 'dark' : 'light'); }, showToast(message, type = 'info') { // Toast notification implementation } }; } // Make globally available window.storefrontLayoutData = storefrontLayoutData; ⭐ PAGE-SPECIFIC COMPONENTS: Each page extends storefrontLayoutData() for page-specific functionality: // Example: products.html document.addEventListener('alpine:init', () => { Alpine.data('shopProducts', () => ({ ...storefrontLayoutData(), // 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 storefrontLayoutData await this.loadProducts(); // Page-specific }, // Page-specific methods async loadProducts() { const response = await fetch('/api/v1/storefront/products'); const data = await response.json(); this.products = data.products; this.loading = false; } })); }); Template Usage: ────────────────────────────────────────────────────────────────── {# In base.html - uses block to allow override #} {# 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 storefrontLayoutData() #} ⭐ COMPONENT HIERARCHY: storefrontLayoutData() ← 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 storefrontLayoutData() 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 storefrontLayoutData() 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/storefront/*.py ⭐ NEW API STRUCTURE (as of 2025-11-22): All storefront endpoints use middleware-based store context. NO store_id or store_code in URLs! Example Endpoints: GET /api/v1/storefront/products ← Product catalog GET /api/v1/storefront/products/{id} ← Product details GET /api/v1/storefront/products?search=... ← Search products GET /api/v1/storefront/cart/{session_id} ← Get cart POST /api/v1/storefront/cart/{session_id}/items ← Add to cart PUT /api/v1/storefront/cart/{session_id}/items/{product_id} ← Update item DELETE /api/v1/storefront/cart/{session_id}/items/{product_id} ← Remove item POST /api/v1/storefront/orders ← Place order (auth required) GET /api/v1/storefront/orders ← Order history (auth required) POST /api/v1/storefront/auth/login ← Customer login POST /api/v1/storefront/auth/register ← Customer registration GET /api/v1/storefront/content-pages/navigation ← CMS navigation GET /api/v1/storefront/content-pages/{slug} ← CMS page content How Store Context Works: 1. Browser makes API call from storefront page (e.g., /storefront/orion/products) 2. Browser automatically sends Referer header: http://localhost:8000/storefront/orion/products 3. StoreContextMiddleware extracts store from Referer header 4. Middleware sets request.state.store = 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 /storefront/acme/products) 2. Store Middleware → Identifies "ACME" store from domain/path 3. Theme Middleware → Loads ACME's theme config 4. FastAPI → Renders storefront/products.html 5. Browser → Receives HTML with theme CSS variables 6. Alpine.js → init() executes 7. JavaScript → GET /api/v1/storefront/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/storefront/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 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 storefront 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/storefront/products'); // Add to cart const response = await fetch('/api/v1/storefront/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/storefront/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 Storefront-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: Storefront 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/storefront/products?is_featured=true /products ────────────────────────────────────────────────────────────────── Purpose: Browse all products with filters Components: • Product grid • Filter sidebar • Sort dropdown • Pagination Data Sources: • GET /api/v1/storefront/products?skip=0&limit=20 • GET /api/v1/storefront/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/storefront/products/{id} • GET /api/v1/storefront/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/storefront/orders • Stripe/PayPal integration /search ────────────────────────────────────────────────────────────────── Purpose: Search results page Components: • Search input • Results grid • Filter options • Sort options Data Sources: • GET /api/v1/storefront/products?search=query /category/{category_slug} ────────────────────────────────────────────────────────────────── Purpose: Browse products by category Components: • Breadcrumbs • Product grid • Subcategories • Filters Data Sources: • GET /api/v1/storefront/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/storefront/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 storefront-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 storefront 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/storefront/errors/404.html - Not Found • app/templates/storefront/errors/400.html - Bad Request • app/templates/storefront/errors/401.html - Unauthorized • app/templates/storefront/errors/403.html - Forbidden • app/templates/storefront/errors/422.html - Validation Error • app/templates/storefront/errors/429.html - Rate Limited • app/templates/storefront/errors/500.html - Server Error • app/templates/storefront/errors/502.html - Bad Gateway • app/templates/storefront/errors/base.html - Base error template • app/templates/storefront/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 storefront 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 #} Continue Shopping View Products {# ✅ GOOD - Context-aware links #} Continue Shopping View Products How It Works: 1. Error occurs (404, 500, etc.) 2. Exception handler detects storefront 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/storefront/orion/ → base_url = "/storefront/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_STOREFRONT_ALPINE_PAGE_TEMPLATE.md • Multi-Theme Guide: MULTI_THEME_STOREFRONT_GUIDE.md • API Documentation: API_REFERENCE.md • Database Schema: DATABASE_SCHEMA.md ══════════════════════════════════════════════════════════════════ STOREFRONT FRONTEND ARCHITECTURE Theme-Driven, Customer-Focused, Brand-Consistent ══════════════════════════════════════════════════════════════════