docs: add consolidated dev URL reference and migrate /shop to /storefront
Some checks failed
Some checks failed
- Add Development URL Quick Reference section to url-routing overview with all login URLs, entry points, and full examples - Replace /shop/ path segments with /storefront/ across 50 docs files - Update file references: shop_pages.py → storefront_pages.py, templates/shop/ → templates/storefront/, api/v1/shop/ → api/v1/storefront/ - Preserve domain references (orion.shop) and /store/ staff dashboard paths - Archive docs left unchanged (historical) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
╔══════════════════════════════════════════════════════════════════╗
|
||||
║ SHOP FRONTEND ARCHITECTURE OVERVIEW ║
|
||||
║ STOREFRONT FRONTEND ARCHITECTURE OVERVIEW ║
|
||||
║ Alpine.js + Jinja2 + Tailwind CSS + Multi-Theme ║
|
||||
╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
📦 WHAT IS THIS?
|
||||
═════════════════════════════════════════════════════════════════
|
||||
|
||||
Customer-facing shop frontend provides visitors with a branded
|
||||
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)
|
||||
@@ -46,7 +46,7 @@ e-commerce experience unique to each store. Built with:
|
||||
═════════════════════════════════════════════════════════════════
|
||||
|
||||
app/
|
||||
├── templates/shop/
|
||||
├── templates/storefront/
|
||||
│ ├── base.html ← ✅ Base template (layout + theme)
|
||||
│ ├── home.html ← ✅ Homepage / featured products
|
||||
│ ├── products.html ← ✅ Product catalog with filters
|
||||
@@ -67,11 +67,11 @@ app/
|
||||
│ ├── 404.html
|
||||
│ └── 500.html
|
||||
│
|
||||
├── static/shop/
|
||||
├── static/storefront/
|
||||
│ ├── css/
|
||||
│ │ └── shop.css ← ✅ Shop-specific styles (IMPLEMENTED)
|
||||
│ │ └── storefront.css ← ✅ Storefront-specific styles (IMPLEMENTED)
|
||||
│ ├── js/
|
||||
│ │ └── shop-layout.js ← ✅ Base shop functionality (IMPLEMENTED)
|
||||
│ │ └── storefront-layout.js ← ✅ Base storefront functionality (IMPLEMENTED)
|
||||
│ └── img/
|
||||
│ └── (placeholder images)
|
||||
│
|
||||
@@ -85,7 +85,7 @@ app/
|
||||
│ └── (shared styles if needed)
|
||||
│
|
||||
└── routes/
|
||||
└── shop_pages.py ← ✅ Route handlers (IMPLEMENTED)
|
||||
└── storefront_pages.py ← ✅ Route handlers (IMPLEMENTED)
|
||||
|
||||
|
||||
🏗️ ARCHITECTURE LAYERS
|
||||
@@ -107,37 +107,37 @@ Layer 6: Database
|
||||
Layer 1: ROUTES (FastAPI)
|
||||
──────────────────────────────────────────────────────────────────
|
||||
Purpose: Store Detection + Template Rendering
|
||||
Location: app/routes/shop_pages.py
|
||||
Location: app/routes/storefront_pages.py
|
||||
|
||||
⚠️ ROUTE REGISTRATION (main.py):
|
||||
The shop router is mounted at TWO prefixes to support both access methods:
|
||||
The storefront 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
|
||||
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 /shop prefix in shop_pages.py:
|
||||
@router.get("/products") → /shop/products OR /stores/{code}/shop/products
|
||||
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 /shop prefix in route definitions!
|
||||
@router.get("/shop/products") ❌ WRONG - creates /shop/shop/products
|
||||
@router.get("/products") ✅ CORRECT - creates /shop/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 shop_products_page(request: Request):
|
||||
async def storefront_products_page(request: Request):
|
||||
"""
|
||||
Render shop homepage / product catalog.
|
||||
Render storefront homepage / product catalog.
|
||||
Store and theme are auto-injected by middleware.
|
||||
"""
|
||||
return templates.TemplateResponse(
|
||||
"shop/products.html",
|
||||
get_shop_context(request) # Helper function
|
||||
"storefront/products.html",
|
||||
get_storefront_context(request) # Helper function
|
||||
)
|
||||
|
||||
Helper Function:
|
||||
def get_shop_context(request: Request, **extra_context) -> dict:
|
||||
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)
|
||||
@@ -176,39 +176,39 @@ Responsibilities:
|
||||
|
||||
⭐ MULTI-ACCESS ROUTING (Domain, Subdomain, Path-Based)
|
||||
──────────────────────────────────────────────────────────────────
|
||||
The shop frontend supports THREE access methods:
|
||||
The storefront frontend supports THREE access methods:
|
||||
|
||||
1. **Custom Domain** (Production)
|
||||
URL: https://customdomain.com/shop/products
|
||||
URL: https://customdomain.com/storefront/products
|
||||
- Store has their own domain
|
||||
- base_url = "/"
|
||||
- Links: /shop/products, /shop/about, /shop/contact
|
||||
- Links: /storefront/products, /storefront/about, /storefront/contact
|
||||
|
||||
2. **Subdomain** (Production)
|
||||
URL: https://orion.letzshop.com/shop/products
|
||||
URL: https://orion.letzshop.com/storefront/products
|
||||
- Store uses platform subdomain
|
||||
- base_url = "/"
|
||||
- Links: /shop/products, /shop/about, /shop/contact
|
||||
- Links: /storefront/products, /storefront/about, /storefront/contact
|
||||
|
||||
3. **Path-Based** (Development/Testing)
|
||||
URL: http://localhost:8000/stores/orion/shop/products
|
||||
URL: http://localhost:8000/storefront/orion/products
|
||||
- Store accessed via path prefix
|
||||
- base_url = "/stores/orion/"
|
||||
- Links: /stores/orion/shop/products, /stores/orion/shop/about
|
||||
- base_url = "/storefront/orion/"
|
||||
- Links: /storefront/orion/products, /storefront/orion/about
|
||||
|
||||
⚠️ CRITICAL: All template links MUST use {{ base_url }}shop/ prefix
|
||||
⚠️ CRITICAL: All template links MUST use {{ base_url }}storefront/ 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>
|
||||
✅ GOOD: <a href="{{ base_url }}storefront/products">Products</a>
|
||||
|
||||
Note: The router is mounted at /shop prefix in main.py, so all links need shop/ after base_url
|
||||
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_shop_context() calculates base_url from 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
|
||||
|
||||
@@ -243,7 +243,7 @@ Detection Methods:
|
||||
Layer 3: TEMPLATES (Jinja2)
|
||||
──────────────────────────────────────────────────────────────────
|
||||
Purpose: HTML Structure + Store Branding
|
||||
Location: app/templates/shop/
|
||||
Location: app/templates/storefront/
|
||||
|
||||
Template Hierarchy:
|
||||
base.html (layout + theme injection)
|
||||
@@ -253,7 +253,7 @@ Template Hierarchy:
|
||||
partials/product-card.html (components)
|
||||
|
||||
Example:
|
||||
{% extends "shop/base.html" %}
|
||||
{% extends "storefront/base.html" %}
|
||||
{% block title %}{{ store.name }}{% endblock %}
|
||||
{% block alpine_data %}shopHome(){% endblock %}
|
||||
{% block content %}
|
||||
@@ -276,7 +276,7 @@ Key Features:
|
||||
Layer 4: JAVASCRIPT (Alpine.js)
|
||||
──────────────────────────────────────────────────────────────────
|
||||
Purpose: Client-Side Interactivity + Cart + Search
|
||||
Location: app/static/shop/js/
|
||||
Location: app/static/storefront/js/
|
||||
|
||||
⚠️ CRITICAL: JavaScript Loading Order
|
||||
──────────────────────────────────────────────────────────────────
|
||||
@@ -284,14 +284,14 @@ 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!)
|
||||
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:
|
||||
• shop-layout.js defines storefrontLayoutData() BEFORE Alpine initializes
|
||||
• 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
|
||||
@@ -299,7 +299,7 @@ Why This Order Matters:
|
||||
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='storefront/js/storefront-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>
|
||||
@@ -307,14 +307,14 @@ Example from base.html:
|
||||
Alpine.js Component Architecture:
|
||||
──────────────────────────────────────────────────────────────────
|
||||
|
||||
⭐ BASE COMPONENT (shop-layout.js):
|
||||
⭐ BASE COMPONENT (storefront-layout.js):
|
||||
|
||||
Provides shared functionality for all shop pages:
|
||||
Provides shared functionality for all storefront pages:
|
||||
|
||||
function storefrontLayoutData() {
|
||||
return {
|
||||
// Theme state
|
||||
dark: localStorage.getItem('shop-theme') === 'dark',
|
||||
dark: localStorage.getItem('storefront-theme') === 'dark',
|
||||
|
||||
// UI state
|
||||
mobileMenuOpen: false,
|
||||
@@ -325,12 +325,12 @@ Provides shared functionality for all shop pages:
|
||||
cart: [],
|
||||
|
||||
init() {
|
||||
shopLog.info('Shop layout initializing...');
|
||||
shopLog.info('Storefront layout initializing...');
|
||||
this.loadCart();
|
||||
window.addEventListener('cart-updated', () => {
|
||||
this.loadCart();
|
||||
});
|
||||
shopLog.info('Shop layout initialized');
|
||||
shopLog.info('Storefront layout initialized');
|
||||
},
|
||||
|
||||
addToCart(product, quantity = 1) {
|
||||
@@ -356,7 +356,7 @@ Provides shared functionality for all shop pages:
|
||||
|
||||
toggleTheme() {
|
||||
this.dark = !this.dark;
|
||||
localStorage.setItem('shop-theme',
|
||||
localStorage.setItem('storefront-theme',
|
||||
this.dark ? 'dark' : 'light');
|
||||
shopLog.debug('Theme toggled:', this.dark ? 'dark' : 'light');
|
||||
},
|
||||
@@ -393,7 +393,7 @@ Each page extends storefrontLayoutData() for page-specific functionality:
|
||||
|
||||
// Page-specific methods
|
||||
async loadProducts() {
|
||||
const response = await fetch('/api/v1/shop/products');
|
||||
const response = await fetch('/api/v1/storefront/products');
|
||||
const data = await response.json();
|
||||
this.products = data.products;
|
||||
this.loading = false;
|
||||
@@ -454,30 +454,30 @@ Responsibilities:
|
||||
Layer 5: API (REST)
|
||||
──────────────────────────────────────────────────────────────────
|
||||
Purpose: Product Data + Cart + Orders
|
||||
Location: app/api/v1/shop/*.py
|
||||
Location: app/api/v1/storefront/*.py
|
||||
|
||||
⭐ NEW API STRUCTURE (as of 2025-11-22):
|
||||
All shop endpoints use middleware-based store context.
|
||||
All storefront 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
|
||||
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 shop page (e.g., /stores/orion/shop/products)
|
||||
2. Browser automatically sends Referer header: http://localhost:8000/stores/orion/shop/products
|
||||
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 = <Store: orion>
|
||||
5. API endpoint accesses store: store = request.state.store
|
||||
@@ -489,13 +489,13 @@ How Store Context Works:
|
||||
|
||||
Page Load Flow:
|
||||
──────────────────────────────────────────────────────────────────
|
||||
1. Customer → visits acme-shop.com (or /stores/acme/shop/products)
|
||||
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 shop/products.html
|
||||
4. FastAPI → Renders storefront/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)
|
||||
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
|
||||
@@ -516,7 +516,7 @@ 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)
|
||||
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
|
||||
@@ -621,7 +621,7 @@ Key Functions:
|
||||
|
||||
Cart Persistence:
|
||||
• Survives page refresh
|
||||
• Shared across shop pages
|
||||
• Shared across storefront pages
|
||||
• Cleared on checkout completion
|
||||
• Synced across tabs (optional)
|
||||
|
||||
@@ -637,7 +637,7 @@ Search System:
|
||||
• Keyboard shortcuts (Cmd+K)
|
||||
|
||||
2. Search API
|
||||
POST /api/v1/shop/{store_code}/search
|
||||
POST /api/v1/storefront/{store_code}/search
|
||||
{
|
||||
"query": "laptop",
|
||||
"category": "electronics",
|
||||
@@ -730,10 +730,10 @@ Account Features:
|
||||
✅ Profile management
|
||||
|
||||
Auth Flow:
|
||||
1. Login/Register → POST /api/v1/shop/auth/login (with Referer header)
|
||||
1. Login/Register → POST /api/v1/storefront/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)
|
||||
4. API → Returns JWT token + sets cookie (path=/storefront)
|
||||
5. JavaScript → Store token in localStorage
|
||||
6. API Client → Add token to authenticated requests
|
||||
7. Optional → Use account features (orders, profile, etc.)
|
||||
@@ -745,9 +745,9 @@ Auth Flow:
|
||||
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)
|
||||
✅ Login Page (app/templates/storefront/account/login.html)
|
||||
──────────────────────────────────────────────────────────────────
|
||||
Route: /shop/account/login
|
||||
Route: /storefront/account/login
|
||||
|
||||
Features:
|
||||
• Two-column layout (branding + form)
|
||||
@@ -773,7 +773,7 @@ Alpine.js Component:
|
||||
dark: false,
|
||||
|
||||
async handleLogin() {
|
||||
// POST /api/v1/shop/auth/login
|
||||
// POST /api/v1/storefront/auth/login
|
||||
// Store token in localStorage
|
||||
// Redirect to account or return URL
|
||||
}
|
||||
@@ -781,13 +781,13 @@ Alpine.js Component:
|
||||
}
|
||||
|
||||
API Endpoint:
|
||||
POST /api/v1/shop/auth/login
|
||||
POST /api/v1/storefront/auth/login
|
||||
Body: { email_or_username, password }
|
||||
Returns: { access_token, user }
|
||||
|
||||
✅ Register Page (app/templates/shop/account/register.html)
|
||||
✅ Register Page (app/templates/storefront/account/register.html)
|
||||
──────────────────────────────────────────────────────────────────
|
||||
Route: /shop/account/register
|
||||
Route: /storefront/account/register
|
||||
|
||||
Features:
|
||||
• Two-column layout with store branding
|
||||
@@ -824,20 +824,20 @@ Alpine.js Component:
|
||||
},
|
||||
|
||||
async handleRegister() {
|
||||
// POST /api/v1/shop/auth/register
|
||||
// POST /api/v1/storefront/auth/register
|
||||
// Redirect to login?registered=true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
API Endpoint:
|
||||
POST /api/v1/shop/auth/register
|
||||
POST /api/v1/storefront/auth/register
|
||||
Body: { first_name, last_name, email, phone?, password, marketing_consent }
|
||||
Returns: { message }
|
||||
|
||||
✅ Forgot Password Page (app/templates/shop/account/forgot-password.html)
|
||||
✅ Forgot Password Page (app/templates/storefront/account/forgot-password.html)
|
||||
──────────────────────────────────────────────────────────────────
|
||||
Route: /shop/account/forgot-password
|
||||
Route: /storefront/account/forgot-password
|
||||
|
||||
Features:
|
||||
• Two-column layout with store branding
|
||||
@@ -848,7 +848,7 @@ Features:
|
||||
• Success state with checkmark icon
|
||||
• Option to retry if email not received
|
||||
• Theme-aware styling
|
||||
• Links back to login and shop
|
||||
• Links back to login and storefront
|
||||
• Dark mode support
|
||||
|
||||
Alpine.js Component:
|
||||
@@ -859,7 +859,7 @@ Alpine.js Component:
|
||||
loading: false,
|
||||
|
||||
async handleSubmit() {
|
||||
// POST /api/v1/shop/auth/forgot-password
|
||||
// POST /api/v1/storefront/auth/forgot-password
|
||||
// Show success message
|
||||
// emailSent = true
|
||||
}
|
||||
@@ -867,7 +867,7 @@ Alpine.js Component:
|
||||
}
|
||||
|
||||
API Endpoint:
|
||||
POST /api/v1/shop/auth/forgot-password
|
||||
POST /api/v1/storefront/auth/forgot-password
|
||||
Body: { email }
|
||||
Returns: { message }
|
||||
|
||||
@@ -907,7 +907,7 @@ Key Theme Elements:
|
||||
|
||||
Benefits:
|
||||
✅ Each store's auth pages match their brand
|
||||
✅ Consistent with main shop design
|
||||
✅ Consistent with main storefront design
|
||||
✅ Dark mode adapts to store colors
|
||||
✅ Professional, polished appearance
|
||||
|
||||
@@ -959,17 +959,17 @@ No store_code needed! Store extracted from Referer header automatically.
|
||||
|
||||
Usage:
|
||||
// Product catalog
|
||||
const products = await fetch('/api/v1/shop/products');
|
||||
const products = await fetch('/api/v1/storefront/products');
|
||||
|
||||
// Add to cart
|
||||
const response = await fetch('/api/v1/shop/cart/session123/items', {
|
||||
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/shop/orders', {
|
||||
const order = await fetch('/api/v1/storefront/orders', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(orderData)
|
||||
@@ -987,7 +987,7 @@ Features:
|
||||
|
||||
Location: app/static/shared/js/log-config.js
|
||||
|
||||
Shop-Specific Logging:
|
||||
Storefront-Specific Logging:
|
||||
shopLog.info('Product added to cart', product);
|
||||
shopLog.error('Checkout failed', error);
|
||||
shopLog.debug('Search query', { query, results });
|
||||
@@ -1008,7 +1008,7 @@ 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:
|
||||
Storefront Icons:
|
||||
• shopping-cart, shopping-bag
|
||||
• heart (wishlist)
|
||||
• search, filter
|
||||
@@ -1066,7 +1066,7 @@ Components:
|
||||
• Category cards
|
||||
• About store section
|
||||
Data Sources:
|
||||
• GET /api/v1/shop/products?is_featured=true
|
||||
• GET /api/v1/storefront/products?is_featured=true
|
||||
|
||||
/products
|
||||
──────────────────────────────────────────────────────────────────
|
||||
@@ -1077,8 +1077,8 @@ Components:
|
||||
• Sort dropdown
|
||||
• Pagination
|
||||
Data Sources:
|
||||
• GET /api/v1/shop/products?skip=0&limit=20
|
||||
• GET /api/v1/shop/products?search=query
|
||||
• 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}
|
||||
@@ -1091,8 +1091,8 @@ Components:
|
||||
• Related products
|
||||
• Reviews (optional)
|
||||
Data Sources:
|
||||
• GET /api/v1/shop/products/{id}
|
||||
• GET /api/v1/shop/products?limit=4 (related products)
|
||||
• GET /api/v1/storefront/products/{id}
|
||||
• GET /api/v1/storefront/products?limit=4 (related products)
|
||||
|
||||
/cart
|
||||
──────────────────────────────────────────────────────────────────
|
||||
@@ -1116,7 +1116,7 @@ Components:
|
||||
• Order summary
|
||||
• Submit button
|
||||
Data Sources:
|
||||
• POST /api/v1/shop/orders
|
||||
• POST /api/v1/storefront/orders
|
||||
• Stripe/PayPal integration
|
||||
|
||||
/search
|
||||
@@ -1128,7 +1128,7 @@ Components:
|
||||
• Filter options
|
||||
• Sort options
|
||||
Data Sources:
|
||||
• GET /api/v1/shop/products?search=query
|
||||
• GET /api/v1/storefront/products?search=query
|
||||
|
||||
/category/{category_slug}
|
||||
──────────────────────────────────────────────────────────────────
|
||||
@@ -1139,7 +1139,7 @@ Components:
|
||||
• Subcategories
|
||||
• Filters
|
||||
Data Sources:
|
||||
• GET /api/v1/shop/products?category={slug}
|
||||
• GET /api/v1/storefront/products?category={slug}
|
||||
|
||||
/about
|
||||
──────────────────────────────────────────────────────────────────
|
||||
@@ -1162,7 +1162,7 @@ Components:
|
||||
• Business hours
|
||||
• Social links
|
||||
Data Sources:
|
||||
• CMS content page (GET /api/v1/shop/content-pages/contact)
|
||||
• CMS content page (GET /api/v1/storefront/content-pages/contact)
|
||||
• Form submission to store email
|
||||
|
||||
|
||||
@@ -1179,7 +1179,7 @@ For New Developers:
|
||||
|
||||
2. Study Existing Page (2 hours)
|
||||
→ Open home.html
|
||||
→ Open shop-layout.js
|
||||
→ Open storefront-layout.js
|
||||
→ Trace product loading flow
|
||||
→ Examine cart management
|
||||
|
||||
@@ -1228,20 +1228,20 @@ Before Deploying:
|
||||
|
||||
Multi-Access Aware Error Pages:
|
||||
|
||||
All shop error pages (404, 500, etc.) are store-context aware and display
|
||||
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/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
|
||||
• 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):
|
||||
|
||||
@@ -1252,7 +1252,7 @@ Calculates base_url dynamically based on store access method:
|
||||
access_method = getattr(request.state, "access_method", None)
|
||||
store_context = getattr(request.state, "store_context", None)
|
||||
|
||||
# Calculate base_url for shop links
|
||||
# Calculate base_url for storefront links
|
||||
base_url = "/"
|
||||
if access_method == "path" and store:
|
||||
full_prefix = store_context.get('full_prefix', '/store/')
|
||||
@@ -1280,13 +1280,13 @@ All error page links use {{ base_url }} prefix for correct routing:
|
||||
How It Works:
|
||||
|
||||
1. Error occurs (404, 500, etc.)
|
||||
2. Exception handler detects shop context
|
||||
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/stores/orion/ → base_url = "/stores/orion/"
|
||||
- Path: localhost/storefront/orion/ → base_url = "/storefront/orion/"
|
||||
|
||||
Benefits:
|
||||
✅ Error pages work correctly regardless of access method
|
||||
@@ -1333,13 +1333,13 @@ Documentation:
|
||||
• FastAPI: https://fastapi.tiangolo.com/
|
||||
|
||||
Internal Docs:
|
||||
• Page Template Guide: FRONTEND_SHOP_ALPINE_PAGE_TEMPLATE.md
|
||||
• Multi-Theme Guide: MULTI_THEME_SHOP_GUIDE.md
|
||||
• 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
|
||||
|
||||
|
||||
══════════════════════════════════════════════════════════════════
|
||||
SHOP FRONTEND ARCHITECTURE
|
||||
STOREFRONT FRONTEND ARCHITECTURE
|
||||
Theme-Driven, Customer-Focused, Brand-Consistent
|
||||
══════════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user