feat: storefront subscription access guard + module-driven nav + URL rename

Add StorefrontAccessMiddleware that blocks storefront access for stores
without an active subscription, returning a multilingual unavailable page
(en/fr/de/lb) for page requests and JSON 403 for API requests. Multi-platform
aware: resolves subscription for detected platform with fallback to primary.

Also includes yesterday's session work:
- Module-driven storefront navigation via FrontendType.STOREFRONT menu declarations
- shop/ → storefront/ URL rename across 30+ templates
- Subscription context (tier_code) passed to storefront templates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-18 13:27:31 +01:00
parent 682213fdee
commit 2c710ad416
46 changed files with 1484 additions and 231 deletions

34
main.py
View File

@@ -76,6 +76,7 @@ from middleware.logging import LoggingMiddleware
# Import REFACTORED class-based middleware
from middleware.platform_context import PlatformContextMiddleware
from middleware.store_context import StoreContextMiddleware
from middleware.storefront_access import StorefrontAccessMiddleware
from middleware.theme_context import ThemeContextMiddleware
logger = logging.getLogger(__name__)
@@ -120,20 +121,22 @@ app.add_middleware(
# So we add them in REVERSE order of desired execution:
#
# Desired execution order:
# 0. ProxyHeadersMiddleware (trust X-Forwarded-Proto from Caddy)
# 1. PlatformContextMiddleware (detect platform from domain/path)
# 2. StoreContextMiddleware (detect store, uses platform_clean_path)
# 3. FrontendTypeMiddleware (detect frontend type using FrontendDetector)
# 4. LanguageMiddleware (detect language based on frontend type)
# 5. ThemeContextMiddleware (load theme)
# 6. LoggingMiddleware (log all requests)
# 0. ProxyHeadersMiddleware (trust X-Forwarded-Proto from Caddy)
# 1. PlatformContextMiddleware (detect platform from domain/path)
# 2. StoreContextMiddleware (detect store, uses platform_clean_path)
# 3. FrontendTypeMiddleware (detect frontend type using FrontendDetector)
# 4. LanguageMiddleware (detect language based on frontend type)
# 5. StorefrontAccessMiddleware (block unsubscribed storefronts)
# 6. ThemeContextMiddleware (load theme)
# 7. LoggingMiddleware (log all requests)
#
# Therefore we add them in REVERSE:
# - Add ThemeContextMiddleware FIRST (runs LAST in request)
# - Add LanguageMiddleware SECOND
# - Add FrontendTypeMiddleware THIRD
# - Add StoreContextMiddleware FOURTH
# - Add PlatformContextMiddleware FIFTH
# - Add StorefrontAccessMiddleware SECOND (runs after Language)
# - Add LanguageMiddleware THIRD
# - Add FrontendTypeMiddleware FOURTH
# - Add StoreContextMiddleware FIFTH
# - Add PlatformContextMiddleware SIXTH
# - Add LoggingMiddleware LAST (runs FIRST for timing)
# ============================================================================
@@ -149,6 +152,10 @@ app.add_middleware(LoggingMiddleware)
logger.info("Adding ThemeContextMiddleware (detects and loads theme)")
app.add_middleware(ThemeContextMiddleware)
# Add storefront access guard (blocks unsubscribed storefronts)
logger.info("Adding StorefrontAccessMiddleware (subscription gate for storefronts)")
app.add_middleware(StorefrontAccessMiddleware)
# Add language middleware (detects language after context is determined)
logger.info("Adding LanguageMiddleware (detects language based on context)")
app.add_middleware(LanguageMiddleware)
@@ -180,8 +187,9 @@ logger.info(" 2. PlatformContextMiddleware (platform detection)")
logger.info(" 3. StoreContextMiddleware (store detection)")
logger.info(" 4. FrontendTypeMiddleware (frontend type detection)")
logger.info(" 5. LanguageMiddleware (language detection)")
logger.info(" 6. ThemeContextMiddleware (theme loading)")
logger.info(" 7. FastAPI Router")
logger.info(" 6. StorefrontAccessMiddleware (subscription gate)")
logger.info(" 7. ThemeContextMiddleware (theme loading)")
logger.info(" 8. FastAPI Router")
logger.info("=" * 80)
# ========================================