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:
@@ -189,7 +189,7 @@ app/templates/shared/
|
||||
|
||||
### Shop Frontend
|
||||
|
||||
**Template:** `app/templates/shop/base.html`
|
||||
**Template:** `app/templates/storefront/base.html`
|
||||
|
||||
```html
|
||||
{# Lines 41-42: Tailwind CSS fallback #}
|
||||
|
||||
@@ -148,39 +148,39 @@ function myPageComponent() {
|
||||
return {
|
||||
...data(),
|
||||
currentPage: 'my-page',
|
||||
|
||||
|
||||
items: [],
|
||||
loading: false,
|
||||
|
||||
|
||||
async init() {
|
||||
pageLog.info('Initializing page');
|
||||
|
||||
|
||||
// Prevent double init
|
||||
if (window._myPageInitialized) return;
|
||||
window._myPageInitialized = true;
|
||||
|
||||
|
||||
const start = performance.now();
|
||||
|
||||
|
||||
try {
|
||||
pageLog.group('Loading Data');
|
||||
await this.loadData();
|
||||
pageLog.groupEnd();
|
||||
|
||||
|
||||
const duration = performance.now() - start;
|
||||
window.LogConfig.logPerformance('Page Init', duration);
|
||||
|
||||
|
||||
pageLog.info('Page initialized successfully');
|
||||
} catch (error) {
|
||||
window.LogConfig.logError(error, 'Page Init');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
async loadData() {
|
||||
const url = '/api/my-data';
|
||||
window.LogConfig.logApiCall('GET', url, null, 'request');
|
||||
|
||||
|
||||
const data = await apiClient.get(url);
|
||||
|
||||
|
||||
window.LogConfig.logApiCall('GET', url, data, 'response');
|
||||
this.items = data;
|
||||
}
|
||||
@@ -300,7 +300,7 @@ The system automatically detects which frontend based on URL:
|
||||
|----------|----------|--------|
|
||||
| `/admin/*` | admin | `ADMIN:` |
|
||||
| `/store/*` | store | `STORE:` |
|
||||
| `/shop/*` | shop | `SHOP:` |
|
||||
| `/storefront/*` | storefront | `SHOP:` |
|
||||
|
||||
---
|
||||
|
||||
@@ -338,21 +338,21 @@ const DEFAULT_LOG_LEVELS = {
|
||||
window.LogConfig = {
|
||||
// Log levels
|
||||
LOG_LEVELS: { ERROR: 1, WARN: 2, INFO: 3, DEBUG: 4 },
|
||||
|
||||
|
||||
// Current config
|
||||
frontend: 'admin' | 'store' | 'shop',
|
||||
environment: 'development' | 'production',
|
||||
logLevel: 1 | 2 | 3 | 4,
|
||||
|
||||
|
||||
// Default logger
|
||||
log: { error(), warn(), info(), debug(), group(), groupEnd(), table(), time(), timeEnd() },
|
||||
|
||||
|
||||
// Pre-configured loggers
|
||||
loggers: { stores, products, orders, ... },
|
||||
|
||||
|
||||
// Create custom logger
|
||||
createLogger(prefix, level?),
|
||||
|
||||
|
||||
// Utility functions
|
||||
logApiCall(method, url, data?, status),
|
||||
logError(error, context),
|
||||
|
||||
@@ -327,13 +327,13 @@ Tab navigation components for switching between content sections.
|
||||
|
||||
---
|
||||
|
||||
## E-commerce Components (Shop Frontend)
|
||||
## E-commerce Components (Storefront Frontend)
|
||||
|
||||
Reusable macros for shop/storefront functionality. Located in `app/templates/shared/macros/shop/`.
|
||||
Reusable macros for storefront functionality. Located in `app/templates/shared/macros/storefront/`.
|
||||
|
||||
### 🛍️ Product Card
|
||||
```html
|
||||
{% from 'shared/macros/shop/product-card.html' import product_card %}
|
||||
{% from 'shared/macros/storefront/product-card.html' import product_card %}
|
||||
|
||||
{# Basic product card #}
|
||||
{{ product_card(product_var='product') }}
|
||||
@@ -360,7 +360,7 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
|
||||
### 🛍️ Product Grid
|
||||
```html
|
||||
{% from 'shared/macros/shop/product-grid.html' import product_grid %}
|
||||
{% from 'shared/macros/storefront/product-grid.html' import product_grid %}
|
||||
|
||||
{# Basic grid #}
|
||||
{{ product_grid(products_var='products', loading_var='loading') }}
|
||||
@@ -381,7 +381,7 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
|
||||
### 🛒 Add to Cart
|
||||
```html
|
||||
{% from 'shared/macros/shop/add-to-cart.html' import add_to_cart_button, add_to_cart_form, buy_now_button %}
|
||||
{% from 'shared/macros/storefront/add-to-cart.html' import add_to_cart_button, add_to_cart_form, buy_now_button %}
|
||||
|
||||
{# Simple button #}
|
||||
{{ add_to_cart_button(action='addToCart()') }}
|
||||
@@ -397,11 +397,11 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
- `add_to_cart_button()` - Simple button with loading state
|
||||
- `add_to_cart_form()` - Form with quantity selector + button
|
||||
- `buy_now_button()` - Direct checkout button
|
||||
- `shop_quantity_selector()` - Stock-aware quantity input
|
||||
- `storefront_quantity_selector()` - Stock-aware quantity input
|
||||
|
||||
### 🛒 Mini Cart (Header)
|
||||
```html
|
||||
{% from 'shared/macros/shop/mini-cart.html' import mini_cart, mini_cart_icon %}
|
||||
{% from 'shared/macros/storefront/mini-cart.html' import mini_cart, mini_cart_icon %}
|
||||
|
||||
{# Complete mini cart with dropdown #}
|
||||
{{ mini_cart(cart_var='cart', show_var='showCart') }}
|
||||
@@ -419,7 +419,7 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
|
||||
### 🖼️ Product Gallery (Priority 3)
|
||||
```html
|
||||
{% from 'shared/macros/shop/product-gallery.html' import product_gallery %}
|
||||
{% from 'shared/macros/storefront/product-gallery.html' import product_gallery %}
|
||||
|
||||
{# Full gallery with thumbnails, zoom, and lightbox #}
|
||||
{{ product_gallery(images_var='product.images', enable_zoom=true, enable_lightbox=true) }}
|
||||
@@ -436,7 +436,7 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
|
||||
### 🎨 Variant Selector (Priority 3)
|
||||
```html
|
||||
{% from 'shared/macros/shop/variant-selector.html' import size_selector, color_swatches %}
|
||||
{% from 'shared/macros/storefront/variant-selector.html' import size_selector, color_swatches %}
|
||||
|
||||
{# Size buttons with size guide link #}
|
||||
{{ size_selector(sizes_var='product.sizes', show_guide=true) }}
|
||||
@@ -453,7 +453,7 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
|
||||
### 📄 Product Info (Priority 3)
|
||||
```html
|
||||
{% from 'shared/macros/shop/product-info.html' import product_info, product_price %}
|
||||
{% from 'shared/macros/storefront/product-info.html' import product_info, product_price %}
|
||||
|
||||
{# Complete info block #}
|
||||
{{ product_info(product_var='product', show_store=true, show_rating=true) }}
|
||||
@@ -473,7 +473,7 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
|
||||
### 📑 Product Tabs (Priority 3)
|
||||
```html
|
||||
{% from 'shared/macros/shop/product-tabs.html' import product_tabs %}
|
||||
{% from 'shared/macros/storefront/product-tabs.html' import product_tabs %}
|
||||
|
||||
{# Tabbed product information #}
|
||||
{{ product_tabs(
|
||||
@@ -486,7 +486,7 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
|
||||
### 📂 Category Navigation (Priority 4)
|
||||
```html
|
||||
{% from 'shared/macros/shop/category-nav.html' import category_nav, category_tree, category_menu %}
|
||||
{% from 'shared/macros/storefront/category-nav.html' import category_nav, category_tree, category_menu %}
|
||||
|
||||
{# Sidebar with nested categories #}
|
||||
{{ category_nav(categories_var='categories', current_var='currentCategory', show_count=true) }}
|
||||
@@ -502,10 +502,10 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
|
||||
### 🍞 Breadcrumbs (Priority 4)
|
||||
```html
|
||||
{% from 'shared/macros/shop/breadcrumbs.html' import shop_breadcrumbs, compact_breadcrumbs %}
|
||||
{% from 'shared/macros/storefront/breadcrumbs.html' import storefront_breadcrumbs, compact_breadcrumbs %}
|
||||
|
||||
{# Static breadcrumbs #}
|
||||
{{ shop_breadcrumbs(items=[
|
||||
{{ storefront_breadcrumbs(items=[
|
||||
{'label': 'Electronics', 'url': '/electronics'},
|
||||
{'label': 'Audio', 'url': '/audio'},
|
||||
{'label': 'Headphones'}
|
||||
@@ -515,11 +515,11 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
{{ compact_breadcrumbs(parent={'label': 'Audio', 'url': '/audio'}, current='Headphones') }}
|
||||
```
|
||||
|
||||
**Macros:** `shop_breadcrumbs()`, `auto_breadcrumbs()`, `compact_breadcrumbs()`
|
||||
**Macros:** `storefront_breadcrumbs()`, `auto_breadcrumbs()`, `compact_breadcrumbs()`
|
||||
|
||||
### 🔍 Search Bar (Priority 4)
|
||||
```html
|
||||
{% from 'shared/macros/shop/search-bar.html' import search_bar, search_autocomplete %}
|
||||
{% from 'shared/macros/storefront/search-bar.html' import search_bar, search_autocomplete %}
|
||||
|
||||
{# Basic search #}
|
||||
{{ search_bar(placeholder='Search products...') }}
|
||||
@@ -535,7 +535,7 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
|
||||
### 🎛️ Filter Sidebar (Priority 4)
|
||||
```html
|
||||
{% from 'shared/macros/shop/filter-sidebar.html' import filter_sidebar, price_filter, sort_dropdown %}
|
||||
{% from 'shared/macros/storefront/filter-sidebar.html' import filter_sidebar, price_filter, sort_dropdown %}
|
||||
|
||||
{# Complete filter panel #}
|
||||
{{ filter_sidebar(filters_var='filters', active_filters_var='activeFilters', on_change='filterProducts()') }}
|
||||
@@ -551,7 +551,7 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
|
||||
### ⭐ Star Rating (Priority 5)
|
||||
```html
|
||||
{% from 'shared/macros/shop/star-rating.html' import star_rating, rating_input, rating_summary, compact_rating %}
|
||||
{% from 'shared/macros/storefront/star-rating.html' import star_rating, rating_input, rating_summary, compact_rating %}
|
||||
|
||||
{# Static star rating with half-star support #}
|
||||
{{ star_rating(rating=4.5, show_value=true, show_count=true, count=127) }}
|
||||
@@ -573,7 +573,7 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
|
||||
### 💬 Reviews (Priority 5)
|
||||
```html
|
||||
{% from 'shared/macros/shop/reviews.html' import review_card, review_list, review_form, review_summary_section %}
|
||||
{% from 'shared/macros/storefront/reviews.html' import review_card, review_list, review_form, review_summary_section %}
|
||||
|
||||
{# Single review card with helpful buttons #}
|
||||
{{ review_card(review_var='review', on_helpful='markHelpful(review.id)') }}
|
||||
@@ -592,7 +592,7 @@ Reusable macros for shop/storefront functionality. Located in `app/templates/sha
|
||||
|
||||
### 🛡️ Trust Badges (Priority 5)
|
||||
```html
|
||||
{% from 'shared/macros/shop/trust-badges.html' import trust_badges, trust_banner, payment_icons, guarantee_badge, security_seals, checkout_trust_section %}
|
||||
{% from 'shared/macros/storefront/trust-badges.html' import trust_badges, trust_banner, payment_icons, guarantee_badge, security_seals, checkout_trust_section %}
|
||||
|
||||
{# Trust badges grid #}
|
||||
{{ trust_badges(badges=['secure_payment', 'free_shipping', 'easy_returns', 'support_24_7'], layout='grid') }}
|
||||
|
||||
@@ -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
|
||||
══════════════════════════════════════════════════════════════════
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Shop Authentication Pages
|
||||
# Storefront Authentication Pages
|
||||
|
||||
## Overview
|
||||
|
||||
This document details the implementation of customer authentication pages in the shop frontend. All pages use Tailwind CSS, Alpine.js, and integrate with the multi-theme system for a branded, consistent experience across all stores.
|
||||
This document details the implementation of customer authentication pages in the storefront frontend. All pages use Tailwind CSS, Alpine.js, and integrate with the multi-theme system for a branded, consistent experience across all stores.
|
||||
|
||||
## Implementation Date
|
||||
2025-11-24
|
||||
@@ -12,8 +12,8 @@ This document details the implementation of customer authentication pages in the
|
||||
## 📄 Available Pages
|
||||
|
||||
### 1. Login Page
|
||||
**Location:** `app/templates/shop/account/login.html`
|
||||
**Route:** `/shop/account/login`
|
||||
**Location:** `app/templates/storefront/account/login.html`
|
||||
**Route:** `/storefront/account/login`
|
||||
|
||||
#### Features
|
||||
- Two-column layout with store branding on the left
|
||||
@@ -41,7 +41,7 @@ function customerLogin() {
|
||||
|
||||
async handleLogin() {
|
||||
// Validates input
|
||||
// Calls POST /api/v1/shop/auth/login
|
||||
// Calls POST /api/v1/storefront/auth/login
|
||||
// Stores token in localStorage
|
||||
// Redirects to account page or return URL
|
||||
}
|
||||
@@ -50,15 +50,15 @@ function customerLogin() {
|
||||
```
|
||||
|
||||
#### API Integration
|
||||
- **Endpoint:** `POST /api/v1/shop/auth/login`
|
||||
- **Endpoint:** `POST /api/v1/storefront/auth/login`
|
||||
- **Request:** `{ email_or_username: string, password: string }`
|
||||
- **Response:** `{ access_token: string, user: object }`
|
||||
|
||||
---
|
||||
|
||||
### 2. Register Page
|
||||
**Location:** `app/templates/shop/account/register.html`
|
||||
**Route:** `/shop/account/register`
|
||||
**Location:** `app/templates/storefront/account/register.html`
|
||||
**Route:** `/storefront/account/register`
|
||||
|
||||
#### Features
|
||||
- Two-column layout with store branding
|
||||
@@ -110,7 +110,7 @@ function customerRegistration() {
|
||||
|
||||
async handleRegister() {
|
||||
// Validates form
|
||||
// Calls POST /api/v1/shop/auth/register
|
||||
// Calls POST /api/v1/storefront/auth/register
|
||||
// Shows success message
|
||||
// Redirects to login with ?registered=true
|
||||
}
|
||||
@@ -119,15 +119,15 @@ function customerRegistration() {
|
||||
```
|
||||
|
||||
#### API Integration
|
||||
- **Endpoint:** `POST /api/v1/shop/auth/register`
|
||||
- **Endpoint:** `POST /api/v1/storefront/auth/register`
|
||||
- **Request:** `{ first_name: string, last_name: string, email: string, phone?: string, password: string, marketing_consent: boolean }`
|
||||
- **Response:** `{ message: string }`
|
||||
|
||||
---
|
||||
|
||||
### 3. Forgot Password Page
|
||||
**Location:** `app/templates/shop/account/forgot-password.html`
|
||||
**Route:** `/shop/account/forgot-password`
|
||||
**Location:** `app/templates/storefront/account/forgot-password.html`
|
||||
**Route:** `/storefront/account/forgot-password`
|
||||
|
||||
#### Features
|
||||
- Two-column layout with store branding
|
||||
@@ -142,7 +142,7 @@ function customerRegistration() {
|
||||
- Instructions to check inbox
|
||||
- Option to retry if email not received
|
||||
- Theme-aware styling
|
||||
- Links back to login and shop homepage
|
||||
- Links back to login and storefront homepage
|
||||
- Dark mode support
|
||||
- Mobile responsive
|
||||
|
||||
@@ -159,7 +159,7 @@ function forgotPassword() {
|
||||
|
||||
async handleSubmit() {
|
||||
// Validates email
|
||||
// Calls POST /api/v1/shop/auth/forgot-password
|
||||
// Calls POST /api/v1/storefront/auth/forgot-password
|
||||
// Sets emailSent = true on success
|
||||
// Shows confirmation message
|
||||
}
|
||||
@@ -168,7 +168,7 @@ function forgotPassword() {
|
||||
```
|
||||
|
||||
#### API Integration
|
||||
- **Endpoint:** `POST /api/v1/shop/auth/forgot-password`
|
||||
- **Endpoint:** `POST /api/v1/storefront/auth/forgot-password`
|
||||
- **Request:** `{ email: string }`
|
||||
- **Response:** `{ message: string }`
|
||||
|
||||
@@ -214,7 +214,7 @@ All authentication pages inject the store's theme CSS variables for consistent b
|
||||
|
||||
### Benefits
|
||||
- ✅ Each store's auth pages automatically match their brand
|
||||
- ✅ Consistent with main shop design
|
||||
- ✅ Consistent with main storefront design
|
||||
- ✅ Dark mode adapts to store colors
|
||||
- ✅ Professional, polished appearance
|
||||
- ✅ No custom CSS needed per store
|
||||
@@ -303,7 +303,7 @@ All authentication pages inject the store's theme CSS variables for consistent b
|
||||
## 🔗 Navigation Flow
|
||||
|
||||
```
|
||||
Shop Homepage
|
||||
Storefront Homepage
|
||||
↓
|
||||
Login Page ←→ Register Page
|
||||
↓ ↓
|
||||
@@ -314,16 +314,16 @@ Check Email Account/Cart
|
||||
|
||||
### Link Structure
|
||||
- **Login Page:**
|
||||
- "Forgot password?" → `/shop/account/forgot-password`
|
||||
- "Create an account" → `/shop/account/register`
|
||||
- "← Continue shopping" → `/shop/`
|
||||
- "Forgot password?" → `/storefront/account/forgot-password`
|
||||
- "Create an account" → `/storefront/account/register`
|
||||
- "← Continue shopping" → `/storefront/`
|
||||
|
||||
- **Register Page:**
|
||||
- "Already have an account? Sign in instead" → `/shop/account/login`
|
||||
- "Already have an account? Sign in instead" → `/storefront/account/login`
|
||||
|
||||
- **Forgot Password Page:**
|
||||
- "Remember your password? Sign in" → `/shop/account/login`
|
||||
- "← Continue shopping" → `/shop/`
|
||||
- "Remember your password? Sign in" → `/storefront/account/login`
|
||||
- "← Continue shopping" → `/storefront/`
|
||||
|
||||
All links use `{{ base_url }}` for multi-access routing support.
|
||||
|
||||
@@ -386,12 +386,12 @@ No code changes needed - all controlled via theme configuration.
|
||||
|
||||
```
|
||||
app/
|
||||
├── templates/shop/account/
|
||||
├── templates/storefront/account/
|
||||
│ ├── login.html ← Customer login page
|
||||
│ ├── register.html ← Customer registration page
|
||||
│ └── forgot-password.html ← Password reset page
|
||||
│
|
||||
└── api/v1/shop/
|
||||
└── api/v1/storefront/
|
||||
└── auth.py ← Authentication endpoints
|
||||
|
||||
static/shared/css/
|
||||
@@ -463,7 +463,7 @@ Possible additions:
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- [Shop Frontend Architecture](./architecture.md)
|
||||
- [Storefront Frontend Architecture](./architecture.md)
|
||||
- [Page Template Guide](./page-templates.md)
|
||||
- [Theme System Overview](../../architecture/theme-system/overview.md)
|
||||
- [Theme Presets](../../architecture/theme-system/presets.md)
|
||||
|
||||
@@ -28,7 +28,7 @@ This document proposes a comprehensive set of reusable Jinja macro components fo
|
||||
### Priority 1: Core Shopping Components
|
||||
|
||||
#### 1.1 Product Card
|
||||
**File:** `app/templates/shared/macros/shop/product-card.html`
|
||||
**File:** `app/templates/shared/macros/storefront/product-card.html`
|
||||
|
||||
A versatile product card for grids, carousels, and lists.
|
||||
|
||||
@@ -63,7 +63,7 @@ A versatile product card for grids, carousels, and lists.
|
||||
---
|
||||
|
||||
#### 1.2 Product Grid
|
||||
**File:** `app/templates/shared/macros/shop/product-grid.html`
|
||||
**File:** `app/templates/shared/macros/storefront/product-grid.html`
|
||||
|
||||
Responsive grid layout for product listings.
|
||||
|
||||
@@ -85,7 +85,7 @@ Responsive grid layout for product listings.
|
||||
---
|
||||
|
||||
#### 1.3 Add to Cart Button
|
||||
**File:** `app/templates/shared/macros/shop/add-to-cart.html`
|
||||
**File:** `app/templates/shared/macros/storefront/add-to-cart.html`
|
||||
|
||||
Standardized add-to-cart functionality.
|
||||
|
||||
@@ -115,7 +115,7 @@ Standardized add-to-cart functionality.
|
||||
Shop-specific wrapper with stock validation:
|
||||
|
||||
```jinja
|
||||
{{ shop_quantity_selector(
|
||||
{{ storefront_quantity_selector(
|
||||
model='quantity',
|
||||
max='product.stock',
|
||||
disabled_var='addingToCart',
|
||||
@@ -128,7 +128,7 @@ Shop-specific wrapper with stock validation:
|
||||
### Priority 2: Cart Components
|
||||
|
||||
#### 2.1 Mini Cart (Header Dropdown)
|
||||
**File:** `app/templates/shared/macros/shop/mini-cart.html`
|
||||
**File:** `app/templates/shared/macros/storefront/mini-cart.html`
|
||||
|
||||
Dropdown cart preview in the header.
|
||||
|
||||
@@ -151,7 +151,7 @@ Dropdown cart preview in the header.
|
||||
---
|
||||
|
||||
#### 2.2 Cart Item Row
|
||||
**File:** `app/templates/shared/macros/shop/cart-item.html`
|
||||
**File:** `app/templates/shared/macros/storefront/cart-item.html`
|
||||
|
||||
Individual cart line item.
|
||||
|
||||
@@ -177,7 +177,7 @@ Individual cart line item.
|
||||
---
|
||||
|
||||
#### 2.3 Cart Summary
|
||||
**File:** `app/templates/shared/macros/shop/cart-summary.html`
|
||||
**File:** `app/templates/shared/macros/storefront/cart-summary.html`
|
||||
|
||||
Order summary sidebar/section.
|
||||
|
||||
@@ -205,7 +205,7 @@ Order summary sidebar/section.
|
||||
### Priority 3: Product Detail Components
|
||||
|
||||
#### 3.1 Product Gallery
|
||||
**File:** `app/templates/shared/macros/shop/product-gallery.html`
|
||||
**File:** `app/templates/shared/macros/storefront/product-gallery.html`
|
||||
|
||||
Image gallery with thumbnails and zoom.
|
||||
|
||||
@@ -229,7 +229,7 @@ Image gallery with thumbnails and zoom.
|
||||
---
|
||||
|
||||
#### 3.2 Variant Selector
|
||||
**File:** `app/templates/shared/macros/shop/variant-selector.html`
|
||||
**File:** `app/templates/shared/macros/storefront/variant-selector.html`
|
||||
|
||||
Product variant selection (size, color, etc.).
|
||||
|
||||
@@ -255,7 +255,7 @@ Product variant selection (size, color, etc.).
|
||||
---
|
||||
|
||||
#### 3.3 Product Info Block
|
||||
**File:** `app/templates/shared/macros/shop/product-info.html`
|
||||
**File:** `app/templates/shared/macros/storefront/product-info.html`
|
||||
|
||||
Product details section.
|
||||
|
||||
@@ -280,7 +280,7 @@ Product details section.
|
||||
---
|
||||
|
||||
#### 3.4 Product Tabs
|
||||
**File:** `app/templates/shared/macros/shop/product-tabs.html`
|
||||
**File:** `app/templates/shared/macros/storefront/product-tabs.html`
|
||||
|
||||
Tabbed product information.
|
||||
|
||||
@@ -303,7 +303,7 @@ Tabbed product information.
|
||||
### Priority 4: Navigation & Discovery
|
||||
|
||||
#### 4.1 Category Navigation
|
||||
**File:** `app/templates/shared/macros/shop/category-nav.html`
|
||||
**File:** `app/templates/shared/macros/storefront/category-nav.html`
|
||||
|
||||
Category browsing sidebar/menu.
|
||||
|
||||
@@ -326,12 +326,12 @@ Category browsing sidebar/menu.
|
||||
---
|
||||
|
||||
#### 4.2 Breadcrumbs
|
||||
**File:** `app/templates/shared/macros/shop/breadcrumbs.html`
|
||||
**File:** `app/templates/shared/macros/storefront/breadcrumbs.html`
|
||||
|
||||
Navigation breadcrumb trail.
|
||||
|
||||
```jinja
|
||||
{{ shop_breadcrumbs(
|
||||
{{ storefront_breadcrumbs(
|
||||
items=[
|
||||
{'label': 'Home', 'url': '/'},
|
||||
{'label': 'Electronics', 'url': '/category/electronics'},
|
||||
@@ -343,7 +343,7 @@ Navigation breadcrumb trail.
|
||||
---
|
||||
|
||||
#### 4.3 Search Bar
|
||||
**File:** `app/templates/shared/macros/shop/search-bar.html`
|
||||
**File:** `app/templates/shared/macros/storefront/search-bar.html`
|
||||
|
||||
Product search with autocomplete.
|
||||
|
||||
@@ -365,7 +365,7 @@ Product search with autocomplete.
|
||||
---
|
||||
|
||||
#### 4.4 Filter Sidebar
|
||||
**File:** `app/templates/shared/macros/shop/filter-sidebar.html`
|
||||
**File:** `app/templates/shared/macros/storefront/filter-sidebar.html`
|
||||
|
||||
Product filtering panel.
|
||||
|
||||
@@ -390,7 +390,7 @@ Product filtering panel.
|
||||
### Priority 5: Social Proof & Trust
|
||||
|
||||
#### 5.1 Star Rating
|
||||
**File:** `app/templates/shared/macros/shop/star-rating.html`
|
||||
**File:** `app/templates/shared/macros/storefront/star-rating.html`
|
||||
|
||||
Reusable star rating display.
|
||||
|
||||
@@ -407,7 +407,7 @@ Reusable star rating display.
|
||||
---
|
||||
|
||||
#### 5.2 Review Card
|
||||
**File:** `app/templates/shared/macros/shop/review-card.html`
|
||||
**File:** `app/templates/shared/macros/storefront/review-card.html`
|
||||
|
||||
Individual product review.
|
||||
|
||||
@@ -431,7 +431,7 @@ Individual product review.
|
||||
---
|
||||
|
||||
#### 5.3 Trust Badges
|
||||
**File:** `app/templates/shared/macros/shop/trust-badges.html`
|
||||
**File:** `app/templates/shared/macros/storefront/trust-badges.html`
|
||||
|
||||
Trust and security indicators.
|
||||
|
||||
@@ -454,7 +454,7 @@ Trust and security indicators.
|
||||
### Priority 6: Promotional Components
|
||||
|
||||
#### 6.1 Sale Banner
|
||||
**File:** `app/templates/shared/macros/shop/sale-banner.html`
|
||||
**File:** `app/templates/shared/macros/storefront/sale-banner.html`
|
||||
|
||||
Promotional banner with countdown.
|
||||
|
||||
@@ -472,7 +472,7 @@ Promotional banner with countdown.
|
||||
---
|
||||
|
||||
#### 6.2 Product Badge
|
||||
**File:** `app/templates/shared/macros/shop/product-badge.html`
|
||||
**File:** `app/templates/shared/macros/storefront/product-badge.html`
|
||||
|
||||
Product overlay badges.
|
||||
|
||||
@@ -486,7 +486,7 @@ Product overlay badges.
|
||||
---
|
||||
|
||||
#### 6.3 Recently Viewed
|
||||
**File:** `app/templates/shared/macros/shop/recently-viewed.html`
|
||||
**File:** `app/templates/shared/macros/storefront/recently-viewed.html`
|
||||
|
||||
Recently viewed products carousel.
|
||||
|
||||
@@ -578,7 +578,7 @@ All shop components will use these CSS variables set by the store theme:
|
||||
## File Structure
|
||||
|
||||
```
|
||||
app/templates/shared/macros/shop/
|
||||
app/templates/shared/macros/storefront/
|
||||
├── product-card.html
|
||||
├── product-grid.html
|
||||
├── add-to-cart.html
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
# Shop Navigation Flow
|
||||
# Storefront Navigation Flow
|
||||
|
||||
Complete guide to navigation structure and URL hierarchy with landing pages.
|
||||
|
||||
## URL Hierarchy
|
||||
|
||||
```
|
||||
/ (Store Root) → Landing Page (if exists) OR redirect to /shop/
|
||||
├── /shop/ → E-commerce Homepage (Product Catalog)
|
||||
│ ├── /shop/products → Product Catalog (same as /shop/)
|
||||
│ ├── /shop/products/{id} → Product Detail Page
|
||||
│ ├── /shop/cart → Shopping Cart
|
||||
│ ├── /shop/checkout → Checkout Process
|
||||
│ ├── /shop/account/login → Customer Login
|
||||
│ ├── /shop/account/register → Customer Registration
|
||||
│ ├── /shop/account/dashboard → Customer Dashboard (auth required)
|
||||
│ ├── /shop/about → CMS Content Page
|
||||
│ ├── /shop/contact → CMS Content Page
|
||||
│ └── /shop/{slug} → Other CMS Pages
|
||||
/ (Store Root) → Landing Page (if exists) OR redirect to /storefront/
|
||||
├── /storefront/ → E-commerce Homepage (Product Catalog)
|
||||
│ ├── /storefront/products → Product Catalog (same as /storefront/)
|
||||
│ ├── /storefront/products/{id} → Product Detail Page
|
||||
│ ├── /storefront/cart → Shopping Cart
|
||||
│ ├── /storefront/checkout → Checkout Process
|
||||
│ ├── /storefront/account/login → Customer Login
|
||||
│ ├── /storefront/account/register → Customer Registration
|
||||
│ ├── /storefront/account/dashboard → Customer Dashboard (auth required)
|
||||
│ ├── /storefront/about → CMS Content Page
|
||||
│ ├── /storefront/contact → CMS Content Page
|
||||
│ └── /storefront/{slug} → Other CMS Pages
|
||||
```
|
||||
|
||||
## Navigation Patterns
|
||||
@@ -26,13 +26,13 @@ Complete guide to navigation structure and URL hierarchy with landing pages.
|
||||
**URL Structure:**
|
||||
```
|
||||
customdomain.com/ → Landing Page (marketing/brand)
|
||||
customdomain.com/shop/ → E-commerce Shop
|
||||
customdomain.com/shop/products → Product Catalog
|
||||
customdomain.com/storefront/ → E-commerce Storefront
|
||||
customdomain.com/storefront/products → Product Catalog
|
||||
```
|
||||
|
||||
**Navigation Flow:**
|
||||
1. User visits store domain → **Landing Page**
|
||||
2. Clicks "Shop Now" → **/shop/** (product catalog)
|
||||
2. Clicks "Shop Now" → **/storefront/** (product catalog)
|
||||
3. Clicks "Home" in breadcrumb → **/** (back to landing page)
|
||||
4. Clicks logo → **/** (back to landing page)
|
||||
|
||||
@@ -47,46 +47,46 @@ Home > Products
|
||||
|
||||
**URL Structure:**
|
||||
```
|
||||
customdomain.com/ → Redirects to /shop/
|
||||
customdomain.com/shop/ → E-commerce Shop
|
||||
customdomain.com/shop/products → Product Catalog
|
||||
customdomain.com/ → Redirects to /storefront/
|
||||
customdomain.com/storefront/ → E-commerce Storefront
|
||||
customdomain.com/storefront/products → Product Catalog
|
||||
```
|
||||
|
||||
**Navigation Flow:**
|
||||
1. User visits store domain → **Redirects to /shop/**
|
||||
2. User browses shop
|
||||
3. Clicks "Home" in breadcrumb → **/** (redirects to /shop/)
|
||||
4. Clicks logo → **/** (redirects to /shop/)
|
||||
1. User visits store domain → **Redirects to /storefront/**
|
||||
2. User browses storefront
|
||||
3. Clicks "Home" in breadcrumb → **/** (redirects to /storefront/)
|
||||
4. Clicks logo → **/** (redirects to /storefront/)
|
||||
|
||||
**Breadcrumb Example (on Products page):**
|
||||
```
|
||||
Home > Products
|
||||
↓
|
||||
/ → /shop/ (redirects)
|
||||
/ → /storefront/ (redirects)
|
||||
```
|
||||
|
||||
## Link References
|
||||
|
||||
### Base URL Calculation
|
||||
|
||||
The `base_url` variable is calculated in `shop_pages.py:get_shop_context()`:
|
||||
The `base_url` variable is calculated in `storefront_pages.py:get_storefront_context()`:
|
||||
|
||||
```python
|
||||
# For domain/subdomain access
|
||||
base_url = "/"
|
||||
# Result: /shop/products, /shop/cart, etc.
|
||||
# Result: /storefront/products, /storefront/cart, etc.
|
||||
|
||||
# For path-based access
|
||||
base_url = "/stores/orion/"
|
||||
# Result: /stores/orion/shop/products, /stores/orion/shop/cart, etc.
|
||||
base_url = "/storefront/orion/"
|
||||
# Result: /storefront/orion/products, /storefront/orion/cart, etc.
|
||||
```
|
||||
|
||||
### Template Links
|
||||
|
||||
**Logo / Home Link (Header):**
|
||||
```jinja2
|
||||
{# Points to store root (landing page or shop) #}
|
||||
<a href="{{ base_url }}shop/">{{ store.name }}</a>
|
||||
{# Points to store root (landing page or storefront) #}
|
||||
<a href="{{ base_url }}storefront/">{{ store.name }}</a>
|
||||
```
|
||||
|
||||
**Breadcrumb Home Link:**
|
||||
@@ -95,20 +95,20 @@ base_url = "/stores/orion/"
|
||||
<a href="{{ base_url }}">Home</a>
|
||||
```
|
||||
|
||||
**Shop Links:**
|
||||
**Storefront Links:**
|
||||
```jinja2
|
||||
{# All shop pages include /shop/ prefix #}
|
||||
<a href="{{ base_url }}shop/products">Products</a>
|
||||
<a href="{{ base_url }}shop/cart">Cart</a>
|
||||
<a href="{{ base_url }}shop/checkout">Checkout</a>
|
||||
{# All storefront pages include /storefront/ prefix #}
|
||||
<a href="{{ base_url }}storefront/products">Products</a>
|
||||
<a href="{{ base_url }}storefront/cart">Cart</a>
|
||||
<a href="{{ base_url }}storefront/checkout">Checkout</a>
|
||||
```
|
||||
|
||||
**CMS Page Links:**
|
||||
```jinja2
|
||||
{# CMS pages are under /shop/ #}
|
||||
<a href="{{ base_url }}shop/about">About</a>
|
||||
<a href="{{ base_url }}shop/contact">Contact</a>
|
||||
<a href="{{ base_url }}shop/{{ page.slug }}">{{ page.title }}</a>
|
||||
{# CMS pages are under /storefront/ #}
|
||||
<a href="{{ base_url }}storefront/about">About</a>
|
||||
<a href="{{ base_url }}storefront/contact">Contact</a>
|
||||
<a href="{{ base_url }}storefront/{{ page.slug }}">{{ page.title }}</a>
|
||||
```
|
||||
|
||||
## Complete URL Examples
|
||||
@@ -116,46 +116,46 @@ base_url = "/stores/orion/"
|
||||
### Path-Based Access (Development)
|
||||
|
||||
```
|
||||
http://localhost:8000/stores/orion/
|
||||
├── / (root) → Landing Page OR redirect to shop
|
||||
├── /shop/ → Shop Homepage
|
||||
├── /shop/products → Product Catalog
|
||||
├── /shop/products/4 → Product Detail
|
||||
├── /shop/cart → Shopping Cart
|
||||
├── /shop/checkout → Checkout
|
||||
├── /shop/account/login → Customer Login
|
||||
├── /shop/about → About Page (CMS)
|
||||
└── /shop/contact → Contact Page (CMS)
|
||||
http://localhost:8000/storefront/orion/
|
||||
├── / (root) → Landing Page OR redirect to storefront
|
||||
├── /storefront/ → Storefront Homepage
|
||||
├── /storefront/products → Product Catalog
|
||||
├── /storefront/products/4 → Product Detail
|
||||
├── /storefront/cart → Shopping Cart
|
||||
├── /storefront/checkout → Checkout
|
||||
├── /storefront/account/login → Customer Login
|
||||
├── /storefront/about → About Page (CMS)
|
||||
└── /storefront/contact → Contact Page (CMS)
|
||||
```
|
||||
|
||||
### Subdomain Access (Production)
|
||||
|
||||
```
|
||||
https://orion.platform.com/
|
||||
├── / (root) → Landing Page OR redirect to shop
|
||||
├── /shop/ → Shop Homepage
|
||||
├── /shop/products → Product Catalog
|
||||
├── /shop/products/4 → Product Detail
|
||||
├── /shop/cart → Shopping Cart
|
||||
├── /shop/checkout → Checkout
|
||||
├── /shop/account/login → Customer Login
|
||||
├── /shop/about → About Page (CMS)
|
||||
└── /shop/contact → Contact Page (CMS)
|
||||
├── / (root) → Landing Page OR redirect to storefront
|
||||
├── /storefront/ → Storefront Homepage
|
||||
├── /storefront/products → Product Catalog
|
||||
├── /storefront/products/4 → Product Detail
|
||||
├── /storefront/cart → Shopping Cart
|
||||
├── /storefront/checkout → Checkout
|
||||
├── /storefront/account/login → Customer Login
|
||||
├── /storefront/about → About Page (CMS)
|
||||
└── /storefront/contact → Contact Page (CMS)
|
||||
```
|
||||
|
||||
### Custom Domain Access (Production)
|
||||
|
||||
```
|
||||
https://customdomain.com/
|
||||
├── / (root) → Landing Page OR redirect to shop
|
||||
├── /shop/ → Shop Homepage
|
||||
├── /shop/products → Product Catalog
|
||||
├── /shop/products/4 → Product Detail
|
||||
├── /shop/cart → Shopping Cart
|
||||
├── /shop/checkout → Checkout
|
||||
├── /shop/account/login → Customer Login
|
||||
├── /shop/about → About Page (CMS)
|
||||
└── /shop/contact → Contact Page (CMS)
|
||||
├── / (root) → Landing Page OR redirect to storefront
|
||||
├── /storefront/ → Storefront Homepage
|
||||
├── /storefront/products → Product Catalog
|
||||
├── /storefront/products/4 → Product Detail
|
||||
├── /storefront/cart → Shopping Cart
|
||||
├── /storefront/checkout → Checkout
|
||||
├── /storefront/account/login → Customer Login
|
||||
├── /storefront/about → About Page (CMS)
|
||||
└── /storefront/contact → Contact Page (CMS)
|
||||
```
|
||||
|
||||
## User Journeys
|
||||
@@ -164,26 +164,26 @@ https://customdomain.com/
|
||||
|
||||
1. Visit `customdomain.com/` → **Landing Page**
|
||||
- Sees brand story, features, CTA
|
||||
2. Clicks "Shop Now" → `/shop/` → **Product Catalog**
|
||||
2. Clicks "Shop Now" → `/storefront/` → **Product Catalog**
|
||||
- Browses products
|
||||
3. Clicks product → `/shop/products/4` → **Product Detail**
|
||||
3. Clicks product → `/storefront/products/4` → **Product Detail**
|
||||
- Views product
|
||||
4. Clicks "Home" in breadcrumb → `/` → **Back to Landing Page**
|
||||
5. Clicks logo → `/` → **Back to Landing Page**
|
||||
|
||||
### Journey 2: Returning Customer (Direct to Shop)
|
||||
### Journey 2: Returning Customer (Direct to Storefront)
|
||||
|
||||
1. Visit `customdomain.com/shop/` → **Product Catalog**
|
||||
- Already knows the brand, goes straight to shop
|
||||
2. Adds to cart → `/shop/cart` → **Shopping Cart**
|
||||
3. Checkout → `/shop/checkout` → **Checkout**
|
||||
1. Visit `customdomain.com/storefront/` → **Product Catalog**
|
||||
- Already knows the brand, goes straight to storefront
|
||||
2. Adds to cart → `/storefront/cart` → **Shopping Cart**
|
||||
3. Checkout → `/storefront/checkout` → **Checkout**
|
||||
4. Clicks "Home" → `/` → **Landing Page** (brand homepage)
|
||||
|
||||
### Journey 3: Customer Account Management
|
||||
|
||||
1. Visit `customdomain.com/shop/account/login` → **Login**
|
||||
2. After login → `/shop/account/dashboard` → **Dashboard**
|
||||
3. View orders → `/shop/account/orders` → **Order History**
|
||||
1. Visit `customdomain.com/storefront/account/login` → **Login**
|
||||
2. After login → `/storefront/account/dashboard` → **Dashboard**
|
||||
3. View orders → `/storefront/account/orders` → **Order History**
|
||||
4. Clicks logo → `/` → **Back to Landing Page**
|
||||
|
||||
## Navigation Components
|
||||
@@ -192,32 +192,32 @@ https://customdomain.com/
|
||||
|
||||
```jinja2
|
||||
{# Logo - always points to store root #}
|
||||
<a href="{{ base_url }}shop/">
|
||||
<a href="{{ base_url }}storefront/">
|
||||
<img src="{{ theme.branding.logo }}" alt="{{ store.name }}">
|
||||
</a>
|
||||
|
||||
{# Main Navigation #}
|
||||
<nav>
|
||||
<a href="{{ base_url }}shop/">Home</a>
|
||||
<a href="{{ base_url }}shop/products">Products</a>
|
||||
<a href="{{ base_url }}shop/about">About</a>
|
||||
<a href="{{ base_url }}shop/contact">Contact</a>
|
||||
<a href="{{ base_url }}storefront/">Home</a>
|
||||
<a href="{{ base_url }}storefront/products">Products</a>
|
||||
<a href="{{ base_url }}storefront/about">About</a>
|
||||
<a href="{{ base_url }}storefront/contact">Contact</a>
|
||||
</nav>
|
||||
|
||||
{# Actions #}
|
||||
<a href="{{ base_url }}shop/cart">Cart</a>
|
||||
<a href="{{ base_url }}shop/account">Account</a>
|
||||
<a href="{{ base_url }}storefront/cart">Cart</a>
|
||||
<a href="{{ base_url }}storefront/account">Account</a>
|
||||
```
|
||||
|
||||
### Footer Navigation (base.html)
|
||||
|
||||
```jinja2
|
||||
{# Quick Links #}
|
||||
<a href="{{ base_url }}shop/products">Products</a>
|
||||
<a href="{{ base_url }}storefront/products">Products</a>
|
||||
|
||||
{# CMS Pages (dynamic) #}
|
||||
{% for page in footer_pages %}
|
||||
<a href="{{ base_url }}shop/{{ page.slug }}">{{ page.title }}</a>
|
||||
<a href="{{ base_url }}storefront/{{ page.slug }}">{{ page.title }}</a>
|
||||
{% endfor %}
|
||||
```
|
||||
|
||||
@@ -233,39 +233,39 @@ https://customdomain.com/
|
||||
### ✅ DO:
|
||||
|
||||
1. **Use Landing Pages**: Create engaging landing pages at store root
|
||||
2. **Clear Navigation**: Make it easy to get from landing to shop and back
|
||||
2. **Clear Navigation**: Make it easy to get from landing to storefront and back
|
||||
3. **Consistent "Home"**: Logo and "Home" breadcrumb both point to `/` (landing)
|
||||
4. **Shop Links**: All shop-related links include `/shop/` prefix
|
||||
5. **CMS Under Shop**: Keep CMS pages under `/shop/` for consistency
|
||||
4. **Storefront Links**: All storefront-related links include `/storefront/` prefix
|
||||
5. **CMS Under Storefront**: Keep CMS pages under `/storefront/` for consistency
|
||||
|
||||
### ❌ DON'T:
|
||||
|
||||
1. **Hardcode URLs**: Always use `{{ base_url }}` for store-aware links
|
||||
2. **Skip /shop/**: Don't link directly to `/products`, use `/shop/products`
|
||||
3. **Mix Landing & Shop**: Keep landing page separate from shop catalog
|
||||
2. **Skip /storefront/**: Don't link directly to `/products`, use `/storefront/products`
|
||||
3. **Mix Landing & Storefront**: Keep landing page separate from storefront catalog
|
||||
4. **Forget Breadcrumbs**: Always provide "Home" link to go back
|
||||
|
||||
## Migration Notes
|
||||
|
||||
### Before Landing Pages
|
||||
|
||||
All links pointed to `/shop/`:
|
||||
All links pointed to `/storefront/`:
|
||||
```jinja2
|
||||
<a href="{{ base_url }}shop/">Home</a> {# Logo #}
|
||||
<a href="{{ base_url }}shop/">Home</a> {# Breadcrumb #}
|
||||
<a href="{{ base_url }}storefront/">Home</a> {# Logo #}
|
||||
<a href="{{ base_url }}storefront/">Home</a> {# Breadcrumb #}
|
||||
```
|
||||
|
||||
### After Landing Pages
|
||||
|
||||
Separation of concerns:
|
||||
```jinja2
|
||||
<a href="{{ base_url }}shop/">Home</a> {# Logo - still goes to shop #}
|
||||
<a href="{{ base_url }}storefront/">Home</a> {# Logo - still goes to storefront #}
|
||||
<a href="{{ base_url }}">Home</a> {# Breadcrumb - goes to landing #}
|
||||
```
|
||||
|
||||
This allows:
|
||||
- Landing page at `/` for marketing/branding
|
||||
- Shop catalog at `/shop/` for e-commerce
|
||||
- Storefront catalog at `/storefront/` for e-commerce
|
||||
- Clean navigation between the two
|
||||
|
||||
## Technical Implementation
|
||||
@@ -273,27 +273,27 @@ This allows:
|
||||
### Route Handlers (main.py)
|
||||
|
||||
```python
|
||||
# Store root - serves landing page or redirects to shop
|
||||
# Store root - serves landing page or redirects to storefront
|
||||
@app.get("/")
|
||||
@app.get("/stores/{store_code}/")
|
||||
@app.get("/storefront/{store_code}/")
|
||||
async def root(request: Request):
|
||||
if has_landing_page():
|
||||
return render_landing_page()
|
||||
else:
|
||||
return redirect_to_shop()
|
||||
return redirect_to_storefront()
|
||||
|
||||
# Shop routes
|
||||
@app.include_router(shop_pages.router, prefix="/shop")
|
||||
@app.include_router(shop_pages.router, prefix="/stores/{store_code}/shop")
|
||||
# Storefront routes
|
||||
@app.include_router(storefront_pages.router, prefix="/storefront")
|
||||
@app.include_router(storefront_pages.router, prefix="/storefront/{store_code}")
|
||||
```
|
||||
|
||||
### Context Calculation (shop_pages.py)
|
||||
### Context Calculation (storefront_pages.py)
|
||||
|
||||
```python
|
||||
def get_shop_context(request: Request):
|
||||
def get_storefront_context(request: Request):
|
||||
base_url = "/"
|
||||
if access_method == "path":
|
||||
base_url = f"/stores/{store.subdomain}/"
|
||||
base_url = f"/storefront/{store.subdomain}/"
|
||||
|
||||
return {
|
||||
"base_url": base_url,
|
||||
@@ -308,11 +308,11 @@ def get_shop_context(request: Request):
|
||||
The navigation system creates a **two-tier structure**:
|
||||
|
||||
1. **Landing Page** (`/`) - Marketing, branding, store story
|
||||
2. **Shop** (`/shop/`) - E-commerce, products, cart, checkout
|
||||
2. **Storefront** (`/storefront/`) - E-commerce, products, cart, checkout
|
||||
|
||||
This gives stores flexibility to:
|
||||
- Have a marketing homepage separate from their store
|
||||
- Choose different landing page designs (minimal, modern, full)
|
||||
- Or skip the landing page and go straight to the shop
|
||||
- Or skip the landing page and go straight to the storefront
|
||||
|
||||
All while maintaining clean, consistent navigation throughout the experience.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Shop Frontend - Alpine.js/Jinja2 Page Template Guide
|
||||
# Storefront Frontend - Alpine.js/Jinja2 Page Template Guide
|
||||
|
||||
## 📋 Overview
|
||||
|
||||
This guide provides complete templates for creating new customer-facing shop pages using the established Alpine.js + Jinja2 + Multi-Theme architecture. Follow these patterns to ensure consistency across all store shops while maintaining unique branding.
|
||||
This guide provides complete templates for creating new customer-facing storefront pages using the established Alpine.js + Jinja2 + Multi-Theme architecture. Follow these patterns to ensure consistency across all store storefronts while maintaining unique branding.
|
||||
|
||||
---
|
||||
|
||||
@@ -10,9 +10,9 @@ This guide provides complete templates for creating new customer-facing shop pag
|
||||
|
||||
Three fully-implemented authentication pages are available for reference:
|
||||
|
||||
- **Login** (`app/templates/shop/account/login.html`) - Customer sign-in with email/password
|
||||
- **Register** (`app/templates/shop/account/register.html`) - New customer account creation
|
||||
- **Forgot Password** (`app/templates/shop/account/forgot-password.html`) - Password reset flow
|
||||
- **Login** (`app/templates/storefront/account/login.html`) - Customer sign-in with email/password
|
||||
- **Register** (`app/templates/storefront/account/register.html`) - New customer account creation
|
||||
- **Forgot Password** (`app/templates/storefront/account/forgot-password.html`) - Password reset flow
|
||||
|
||||
All authentication pages feature:
|
||||
- ✅ Tailwind CSS styling
|
||||
@@ -24,7 +24,7 @@ All authentication pages feature:
|
||||
- ✅ Loading states
|
||||
- ✅ Error handling
|
||||
|
||||
See the [Shop Architecture Documentation](./architecture.md) (Authentication Pages section) for complete details.
|
||||
See the [Storefront Architecture Documentation](./architecture.md) (Authentication Pages section) for complete details.
|
||||
|
||||
---
|
||||
|
||||
@@ -33,16 +33,16 @@ See the [Shop Architecture Documentation](./architecture.md) (Authentication Pag
|
||||
### File Structure for New Page
|
||||
```
|
||||
app/
|
||||
├── templates/shop/
|
||||
├── templates/storefront/
|
||||
│ └── [page-name].html # Jinja2 template
|
||||
├── static/shop/js/
|
||||
├── static/storefront/js/
|
||||
│ └── [page-name].js # Alpine.js component
|
||||
└── api/v1/shop/
|
||||
└── api/v1/storefront/
|
||||
└── pages.py # Route registration
|
||||
```
|
||||
|
||||
### Checklist for New Page
|
||||
- [ ] Create Jinja2 template extending shop/base.html
|
||||
- [ ] Create Jinja2 template extending storefront/base.html
|
||||
- [ ] Create Alpine.js JavaScript component
|
||||
- [ ] Register route in pages.py
|
||||
- [ ] Test with multiple store themes
|
||||
@@ -58,11 +58,11 @@ app/
|
||||
|
||||
### 1. Jinja2 Template
|
||||
|
||||
**File:** `app/templates/shop/[page-name].html`
|
||||
**File:** `app/templates/storefront/[page-name].html`
|
||||
|
||||
```jinja2
|
||||
{# app/templates/shop/[page-name].html #}
|
||||
{% extends "shop/base.html" %}
|
||||
{# app/templates/storefront/[page-name].html #}
|
||||
{% extends "storefront/base.html" %}
|
||||
|
||||
{# Page title for browser tab - includes store name #}
|
||||
{% block title %}[Page Name] - {{ store.name }}{% endblock %}
|
||||
@@ -174,7 +174,7 @@ app/
|
||||
|
||||
<!-- Item Image -->
|
||||
<div class="aspect-w-1 aspect-h-1 w-full overflow-hidden rounded-t-lg bg-gray-100 dark:bg-gray-700">
|
||||
<img :src="item.image || '/static/shop/img/placeholder-product.png'"
|
||||
<img :src="item.image || '/static/storefront/img/placeholder-product.png'"
|
||||
:alt="item.name"
|
||||
class="w-full h-full object-cover object-center hover:scale-105 transition-transform"
|
||||
loading="lazy">
|
||||
@@ -247,7 +247,7 @@ app/
|
||||
|
||||
{# Page-specific JavaScript #}
|
||||
{% block extra_scripts %}
|
||||
<script src="{{ url_for('static', path='shop/js/[page-name].js') }}"></script>
|
||||
<script src="{{ url_for('static', path='storefront/js/[page-name].js') }}"></script>
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
@@ -255,10 +255,10 @@ app/
|
||||
|
||||
### 2. Alpine.js Component
|
||||
|
||||
**File:** `app/static/shop/js/[page-name].js`
|
||||
**File:** `app/static/storefront/js/[page-name].js`
|
||||
|
||||
```javascript
|
||||
// static/shop/js/[page-name].js
|
||||
// static/storefront/js/[page-name].js
|
||||
/**
|
||||
* [Page Name] Component
|
||||
* Handles [describe functionality]
|
||||
@@ -333,7 +333,7 @@ function shop[PageName]() {
|
||||
});
|
||||
|
||||
const response = await fetch(
|
||||
`/api/v1/shop/${this.storeCode}/items?${params}`
|
||||
`/api/v1/storefront/${this.storeCode}/items?${params}`
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -444,14 +444,14 @@ function shop[PageName]() {
|
||||
addToCart(item, quantity = 1) {
|
||||
pageLog.info('Adding to cart:', item.name);
|
||||
|
||||
// Get cart from shop layout
|
||||
// Get cart from storefront layout
|
||||
const shopLayout = Alpine.store('shop') || window.storefrontLayoutData();
|
||||
|
||||
if (shopLayout && typeof shopLayout.addToCart === 'function') {
|
||||
shopLayout.addToCart(item, quantity);
|
||||
this.showToast(`${item.name} added to cart`, 'success');
|
||||
} else {
|
||||
pageLog.error('Shop layout not available');
|
||||
pageLog.error('Storefront layout not available');
|
||||
}
|
||||
},
|
||||
|
||||
@@ -513,7 +513,7 @@ pageLog.info('[PageName] module loaded');
|
||||
|
||||
### 3. Route Registration
|
||||
|
||||
**File:** `app/api/v1/shop/pages.py`
|
||||
**File:** `app/api/v1/storefront/pages.py`
|
||||
|
||||
```python
|
||||
from fastapi import APIRouter, Request, Depends
|
||||
@@ -536,7 +536,7 @@ async def [page_name]_page(
|
||||
theme = request.state.theme
|
||||
|
||||
return templates.TemplateResponse(
|
||||
"shop/[page-name].html",
|
||||
"storefront/[page-name].html",
|
||||
{
|
||||
"request": request,
|
||||
"store": store,
|
||||
@@ -562,7 +562,7 @@ async loadProducts() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/v1/shop/${this.storeCode}/products?category=${this.category}`
|
||||
`/api/v1/storefront/${this.storeCode}/products?category=${this.category}`
|
||||
);
|
||||
const data = await response.json();
|
||||
this.products = data.products || [];
|
||||
@@ -578,7 +578,7 @@ async loadProducts() {
|
||||
```html
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<template x-for="product in products" :key="product.id">
|
||||
{% include 'shop/partials/product-card.html' %}
|
||||
{% include 'storefront/partials/product-card.html' %}
|
||||
</template>
|
||||
</div>
|
||||
```
|
||||
@@ -598,7 +598,7 @@ async init() {
|
||||
|
||||
async loadProduct(id) {
|
||||
const product = await fetch(
|
||||
`/api/v1/shop/${this.storeCode}/products/${id}`
|
||||
`/api/v1/storefront/${this.storeCode}/products/${id}`
|
||||
).then(r => r.json());
|
||||
|
||||
this.product = product;
|
||||
@@ -713,7 +713,7 @@ async performSearch() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/v1/shop/${this.storeCode}/search`,
|
||||
`/api/v1/storefront/${this.storeCode}/search`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -750,10 +750,10 @@ Always use CSS variables for store colors:
|
||||
|
||||
### 2. Cart Integration
|
||||
|
||||
Always use the shop layout's cart methods:
|
||||
Always use the storefront layout's cart methods:
|
||||
|
||||
```javascript
|
||||
// ✅ GOOD: Uses shop layout
|
||||
// ✅ GOOD: Uses storefront layout
|
||||
const shopLayout = window.storefrontLayoutData();
|
||||
shopLayout.addToCart(product, quantity);
|
||||
|
||||
@@ -881,7 +881,7 @@ Add proper ARIA labels and keyboard navigation:
|
||||
|
||||
### Reusable Partials
|
||||
|
||||
Create reusable components in `templates/shop/partials/`:
|
||||
Create reusable components in `templates/storefront/partials/`:
|
||||
|
||||
**product-card.html:**
|
||||
```html
|
||||
@@ -945,12 +945,12 @@ Create reusable components in `templates/shop/partials/`:
|
||||
|
||||
```bash
|
||||
# Create new page files
|
||||
touch app/templates/shop/new-page.html
|
||||
touch app/static/shop/js/new-page.js
|
||||
touch app/templates/storefront/new-page.html
|
||||
touch app/static/storefront/js/new-page.js
|
||||
|
||||
# Copy templates
|
||||
cp template.html app/templates/shop/new-page.html
|
||||
cp template.js app/static/shop/js/new-page.js
|
||||
cp template.html app/templates/storefront/new-page.html
|
||||
cp template.js app/static/storefront/js/new-page.js
|
||||
|
||||
# Update placeholders:
|
||||
# - Replace [page-name] with actual name
|
||||
@@ -969,7 +969,7 @@ cp template.js app/static/shop/js/new-page.js
|
||||
- **Logo**: Available in both light and dark versions
|
||||
- **Custom CSS**: Store-specific styles automatically injected
|
||||
|
||||
### Shop Layout Functions
|
||||
### Storefront Layout Functions
|
||||
- `addToCart(product, quantity)`: Add item to cart
|
||||
- `showToast(message, type)`: Show notification
|
||||
- `formatPrice(amount)`: Format as currency
|
||||
@@ -991,4 +991,4 @@ await apiClient.post('/endpoint', { data });
|
||||
|
||||
---
|
||||
|
||||
This template provides a complete, theme-aware pattern for building shop pages with consistent structure, store branding, cart integration, and excellent user experience across all devices.
|
||||
This template provides a complete, theme-aware pattern for building storefront pages with consistent structure, store branding, cart integration, and excellent user experience across all devices.
|
||||
|
||||
@@ -21,7 +21,7 @@ Tailwind Standalone CLI (single binary, no npm)
|
||||
│
|
||||
├── static/admin/css/tailwind.css → tailwind.output.css (Admin)
|
||||
├── static/store/css/tailwind.css → tailwind.output.css (Store)
|
||||
├── static/shop/css/tailwind.css → tailwind.output.css (Shop)
|
||||
├── static/storefront/css/tailwind.css → tailwind.output.css (Shop)
|
||||
└── static/public/css/tailwind.css → tailwind.output.css (Platform)
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user