Files
orion/docs/troubleshooting/shop-frontend.md
Samir Boulahtit e9253fbd84 refactor: rename Wizamart to Orion across entire codebase
Replace all ~1,086 occurrences of Wizamart/wizamart/WIZAMART/WizaMart
with Orion/orion/ORION across 184 files. This includes database
identifiers, email addresses, domain references, R2 bucket names,
DNS prefixes, encryption salt, Celery app name, config defaults,
Docker configs, CI configs, documentation, seed data, and templates.

Renames homepage-wizamart.html template to homepage-orion.html.
Fixes duplicate file_pattern key in api.yaml architecture rule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:46:56 +01:00

9.7 KiB

Shop Frontend Troubleshooting

Common issues and solutions for the store shop frontend.

Cart and Product Issues

Products Cannot Be Added to Cart

Symptoms:

  • "Add to Cart" button is disabled
  • No response when clicking "Add to Cart"
  • Console shows canAddToCart: false

Root Cause: Products have available_inventory: 0 because the inventory table is empty.

How it Works:

  • Product's available_inventory is a calculated property
  • It sums quantity - reserved_quantity from all inventory_entries
  • If there are no inventory entries, available_inventory = 0
  • The canAddToCart check fails when available_inventory <= 0

Solution:

# Create inventory entries for all products
python scripts/create_inventory.py

This script:

  • Finds all products without inventory entries
  • Creates inventory with 100 units in "Main Warehouse"
  • Can be run multiple times (only creates missing entries)

Verify Fix:

# Check a product's inventory
from app.core.database import SessionLocal
from models.database.product import Product

db = SessionLocal()
product = db.query(Product).first()
print(f"Available inventory: {product.available_inventory}")
# Should show: Available inventory: 100

Cart is Empty After Adding Products

Symptoms:

  • Success toast appears: "1 item(s) added to cart!"
  • Cart count in header doesn't update
  • Cart page shows 0 items
  • Console shows session_1234_abc but API returns empty cart

Root Cause: Session ID not properly initialized in Alpine.js components.

How it Works:

  • Cart uses session ID stored in localStorage as cart_session_id
  • shopLayoutData() base component initializes sessionId in its init() method
  • Child components (product, cart) must call parent init() to get sessionId
  • If parent init isn't called, sessionId is undefined

Solution Already Implemented: The product and cart pages now properly call parent init:

// In product.html and cart.html
async init() {
    // Call parent init to set up sessionId
    if (baseData.init) {
        baseData.init.call(this);
    }
    // Now sessionId is available
    await this.loadCart();
}

Verify Fix: Open browser console and check for:

🔍 [SHOP] Session ID: session_1763765104510_zc866tt5d

If you see undefined, the parent init isn't being called properly.

Styling and Layout Issues

Page Has No Styling / CSS 404 Errors

Symptoms:

  • Page displays with no styling
  • Console shows 404 errors:
    • /static/css/shared/base.css not found
    • /static/css/store/store.css not found
  • Page is just plain HTML

Root Cause: Template doesn't extend shop/base.html and has hardcoded non-existent CSS references.

How it Works:

  • All shop pages should extend shop/base.html
  • Base template includes Tailwind CSS and shop styles
  • Standalone HTML pages with <link> tags won't work

Solution: Refactor template to extend base:

{# BEFORE: Standalone HTML #}
<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="/static/css/shared/base.css">  ❌
</head>
<body>
    <!-- content -->
</body>
</html>

{# AFTER: Extends base #}
{% extends "shop/base.html" %}

{% block title %}My Page{% endblock %}

{% block alpine_data %}myComponent(){% endblock %}

{% block content %}
    <!-- content -->
{% endblock %}

Templates Already Fixed:

  • shop/product.html - Refactored to extend base
  • shop/cart.html - Refactored to extend base
  • shop/products.html - Already extends base
  • shop/home.html - Already extends base

Images Not Loading / Placeholder Not Showing

Symptoms:

  • Product images show broken image icon
  • Console shows 404: /static/shop/img/placeholder.jpg
  • OR images point to fake URLs like https://orion.example.com/images/product-1.jpg

Root Cause:

  1. Test data has fake image URLs
  2. Placeholder file was .jpg but contained SVG content

How it Works:

  • Products have marketplace_product.image_link URLs
  • Template uses fallback: :src="image || '/static/shop/img/placeholder.svg'"
  • @error handler switches to placeholder when image fails to load
  • Browsers won't render SVG content from .jpg files

Solution Already Implemented:

  • Created proper /static/shop/img/placeholder.svg
  • Added @error handlers to all image tags:
<img
    :src="product.image_link || '/static/shop/img/placeholder.svg'"
    @error="$el.src = '/static/shop/img/placeholder.svg'"
    alt="Product image"
>

Update Test Data (Optional):

# Replace fake URLs with real placeholder images
import sqlite3
conn = sqlite3.connect('orion.db')
cursor = conn.cursor()

cursor.execute("""
    UPDATE marketplace_products
    SET image_link = NULL
    WHERE image_link LIKE '%example.com%'
""")
conn.commit()

Navigation and Routing Issues

Product Detail Page Returns 404

Symptoms:

  • Clicking product shows 404 error
  • URL is: /stores/orion/shop/shop/products/4 (double /shop/)
  • Server log shows route not found

Root Cause: Duplicate /shop prefix in route definitions when router already has prefix.

How it Works:

# Router is mounted with prefix
app.include_router(shop_pages.router, prefix="/shop")

# Route decorator should NOT repeat the prefix
@router.get("/products/{id}")  # ✅ Correct
@router.get("/shop/products/{id}")  # ❌ Wrong - creates /shop/shop/products/{id}

Solution Already Implemented: All routes in shop_pages.py have been fixed to remove duplicate /shop/ prefix.

Symptoms:

  • Links go to /stores/orion/products instead of /stores/orion/shop/products
  • 404 errors on navigation
  • Footer/header links broken

Root Cause: Template links missing /shop/ prefix after {{ base_url }}.

Solution:

{# WRONG #}
<a href="{{ base_url }}products">Products</a>

{# CORRECT #}
<a href="{{ base_url }}shop/products">Products</a>

All Templates Fixed:

  • shop/base.html - Header, footer, navigation
  • shop/products.html - Product links
  • shop/product.html - Breadcrumbs, related products
  • shop/cart.html - Continue shopping, checkout
  • shop/errors/404.html - All fallback links

Landing Page Issues

Store Root Shows 404

Symptoms:

  • http://localhost:8000/stores/orion/ returns 404
  • / path not found

Root Cause: No landing page created for store.

How it Works:

# Root handler checks for landing page
if has_landing_page():
    return render_landing_page()
else:
    return redirect("/shop/")  # Fallback

Solution:

# Create landing page
python scripts/create_landing_page.py
# Choose store and template

Or Accept Redirect: The system auto-redirects to /shop/ if no landing page exists. This is normal behavior.

Breadcrumb "Home" Points to Wrong Place

Symptoms:

  • Clicking "Home" in breadcrumb goes to shop instead of landing page
  • Want "Home" to point to store root (/)

Solution Already Implemented:

{# Breadcrumb Home link points to store root #}
<a href="{{ base_url }}">Home</a>

{# Shop homepage link #}
<a href="{{ base_url }}shop/">Shop</a>

Navigation pattern:

  • Logo click/shop/ (stays in shop for convenience)
  • Breadcrumb "Home"/ (returns to landing page/root)
  • Header "Home" link/ (returns to landing page/root)

Alpine.js / JavaScript Issues

Component Data Not Available

Symptoms:

  • this.sessionId is undefined
  • this.cartCount doesn't work
  • Console: "Cannot read property of undefined"

Root Cause: Child component doesn't call parent init() method.

Solution:

// Store reference to parent
const baseData = shopLayoutData();

return {
    ...baseData,

    // Child properties
    items: [],

    // Call parent init
    async init() {
        if (baseData.init) {
            baseData.init.call(this);
        }
        // Now parent properties are initialized
        await this.loadData();
    }
};

Product ID is Undefined

Symptoms:

  • API call: /api/v1/shop/products/undefined
  • Console: productId: undefined

Root Cause: Product ID not accessible from this.$el.dataset when x-data is on <html> tag.

Solution Already Implemented: Pass via window globals:

{% block extra_scripts %}
<script>
window.PRODUCT_ID = {{ product_id }};
window.STORE_ID = {{ store.id }};

Alpine.data('productDetail', () => ({
    productId: window.PRODUCT_ID,
    storeId: window.STORE_ID,
    // ...
}));
</script>
{% endblock %}

Debugging Tips

Enable Verbose Logging

// In shop-layout.js, the shopLog is already configured
// Check browser console for:
🛒 [SHOP] Shop layout initializing...
🔍 [SHOP] Session ID: session_xxx
[SHOP] Adding to cart: {...}
[SHOP] Cart loaded: 3 items

Check Session ID

// In browser console
localStorage.getItem('cart_session_id')
// Should show: "session_1763765104510_zc866tt5d"

Inspect Product Data

// In browser console on product page
Alpine.$data(document.querySelector('[x-data]')).product
// Shows full product object with inventory

Check API Responses

In browser Network tab, filter by "shop" and check:

  • GET /api/v1/shop/products - Should return products array
  • GET /api/v1/shop/cart/{session_id} - Should return cart items
  • POST /api/v1/shop/cart/{session_id}/items - Should return success

Getting Help

  1. Check this guide first
  2. Check browser console for errors
  3. Check server logs for API errors
  4. Verify database has inventory entries
  5. Ensure all templates extend shop/base.html
  6. Check that session ID is initialized

If still stuck, provide:

  • Browser console output
  • Server log excerpt
  • Network tab showing failed requests
  • Steps to reproduce