feat(storefront): homepage, module gating, widget protocol, i18n fixes
Some checks failed
CI / ruff (push) Successful in 14s
CI / pytest (push) Failing after 2h32m45s
CI / validate (push) Successful in 30s
CI / dependency-scanning (push) Successful in 31s
CI / docs (push) Has been skipped
CI / deploy (push) Has been skipped

Storefront homepage & module gating:
- CMS owns storefront GET / (slug="home" with 3-tier resolution)
- Catalog loses GET / (keeps /products only)
- Store root redirect (GET / → /store/dashboard or /store/login)
- Route gating: non-core modules return 404 when disabled for platform
- Seed store default homepages per platform

Widget protocol for customer dashboard:
- StorefrontDashboardCard contract in widgets.py
- Widget aggregator get_storefront_dashboard_cards()
- Orders and Loyalty module widget providers
- Dashboard template renders contributed cards (no module names)

Landing template module-agnostic:
- CTAs driven by storefront_nav (not hardcoded module names)
- Header actions check nav item IDs (not enabled_modules)
- Remove hardcoded "Add Product" sidebar button
- Remove all enabled_modules checks from storefront templates

i18n fixes:
- Title placeholder resolution ({{store_name}}) for store default pages
- Storefront nav label_keys prefixed with module code
- Add storefront.account.* keys to 6 modules (en/fr/de/lb)
- Header/footer CMS pages use get_translated_title(current_language)
- Footer labels use i18n keys instead of hardcoded English

Icon cleanup:
- Standardize on map-pin (remove location-marker alias)
- Replace all location-marker references across templates and docs

Docs:
- Storefront builder vision proposal (6 phases)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-13 22:53:17 +02:00
parent dd9dc04328
commit adc36246b8
58 changed files with 4691 additions and 3806 deletions

View File

@@ -28,6 +28,71 @@ ROUTE_CONFIG = {
}
# ============================================================================
# STOREFRONT HOMEPAGE
# ============================================================================
@router.get("/", response_class=HTMLResponse, include_in_schema=False)
async def storefront_homepage(
request: Request,
db: Session = Depends(get_db),
):
"""
Storefront homepage handler.
Looks for a CMS page with slug="home" (store override → store default),
and renders the appropriate landing template. Falls back to the default
landing template when no CMS homepage exists.
"""
store = getattr(request.state, "store", None)
platform = getattr(request.state, "platform", None)
store_id = store.id if store else None
if not platform:
raise HTTPException(status_code=400, detail="Platform context required")
# Try to load a homepage from CMS (store override → store default)
page = content_page_service.get_page_for_store(
db,
platform_id=platform.id,
slug="home",
store_id=store_id,
include_unpublished=False,
)
# Resolve placeholders for store default pages (title + content)
page_content = None
page_title = None
if page:
page_content = page.content
page_title = page.title
if page.is_store_default and store:
page_content = content_page_service.resolve_placeholders(
page.content, store
)
page_title = content_page_service.resolve_placeholders(
page.title, store
)
context = get_storefront_context(request, db=db, page=page)
if page_content:
context["page_content"] = page_content
if page_title:
context["page_title"] = page_title
# Select template based on page.template field (or default)
template_map = {
"full": "cms/storefront/landing-full.html",
"modern": "cms/storefront/landing-modern.html",
"minimal": "cms/storefront/landing-minimal.html",
}
template_name = "cms/storefront/landing-default.html"
if page and page.template:
template_name = template_map.get(page.template, template_name)
return templates.TemplateResponse(template_name, context)
# ============================================================================
# DYNAMIC CONTENT PAGES (CMS)
# ============================================================================
@@ -103,10 +168,13 @@ async def generic_content_page(
# Resolve placeholders in store default pages ({{store_name}}, etc.)
page_content = page.content
page_title = page.title
if page.is_store_default and store:
page_content = content_page_service.resolve_placeholders(page.content, store)
page_title = content_page_service.resolve_placeholders(page.title, store)
context = get_storefront_context(request, db=db, page=page)
context["page_title"] = page_title
context["page_content"] = page_content
# Select template based on page.template field