Files
orion/docs/architecture/frontend-detection.md
Samir Boulahtit aad18c27ab
Some checks failed
CI / ruff (push) Successful in 11s
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / pytest (push) Has started running
refactor: remove all backward compatibility code across 70 files
Clean up 28 backward compatibility instances identified in the codebase.
The app is not live, so all shims are replaced with the target architecture:

- Remove legacy Inventory.location column (use bin_location exclusively)
- Remove dashboard _extract_metric_value helper (use flat metrics dict)
- Remove legacy stat field duplicates (total_stores, total_imports, etc.)
- Remove 13 re-export shims and class aliases across modules
- Remove module-enabling JSON fallback (use PlatformModule junction table)
- Remove menu_to_legacy_format() conversion (return dataclasses directly)
- Remove title/description from MarketplaceProductBase schema
- Clean billing convenience method docstrings
- Clean test fixtures and backward-compat comments
- Add PlatformModule seeding to init_production.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 13:20:29 +01:00

8.4 KiB

Frontend Detection Architecture

This document describes the centralized frontend detection system that identifies which frontend (ADMIN, STORE, STOREFRONT, or PLATFORM) a request targets.

Overview

The application serves multiple frontends from a single codebase:

Frontend Description Example URLs
ADMIN Platform administration /admin/*, /api/v1/admin/*, admin.omsflow.lu/*
STORE Store dashboard /store/*, /api/v1/store/*
STOREFRONT Customer-facing shop /storefront/*, /stores/*, orion.omsflow.lu/*
PLATFORM Marketing pages /, /pricing, /about

The FrontendDetector class provides centralized, consistent detection of which frontend a request targets.

Architecture

Components

┌─────────────────────────────────────────────────────────────────┐
│                     Request Processing                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                   │
│  1. PlatformContextMiddleware  → Sets request.state.platform     │
│                                                                   │
│  2. StoreContextMiddleware    → Sets request.state.store       │
│                                                                   │
│  3. FrontendTypeMiddleware     → Sets request.state.frontend_type│
│           │                                                       │
│           └──→ Uses FrontendDetector.detect()                    │
│                                                                   │
│  4. LanguageMiddleware         → Uses frontend_type for language │
│                                                                   │
│  5. ThemeContextMiddleware     → Uses frontend_type for theming  │
│                                                                   │
│  6. FastAPI Router             → Handles request                 │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

Key Files

File Purpose
app/core/frontend_detector.py Centralized detection logic
middleware/frontend_type.py Middleware that sets request.state.frontend_type
app/modules/enums.py Defines FrontendType enum

FrontendType Enum

class FrontendType(str, Enum):
    PLATFORM = "platform"    # Marketing pages (/, /pricing, /about)
    ADMIN = "admin"          # Admin panel (/admin/*)
    STORE = "store"        # Store dashboard (/store/*)
    STOREFRONT = "storefront"  # Customer shop (/storefront/*, /stores/*)

Detection Priority

The FrontendDetector uses the following priority order:

1. Admin subdomain (admin.omsflow.lu)           → ADMIN
2. Path-based detection:
   - /admin/* or /api/v1/admin/*            → ADMIN
   - /store/* or /api/v1/store/*          → STORE
   - /storefront/*, /shop/*, /stores/*     → STOREFRONT
   - /api/v1/platform/*                     → PLATFORM
3. Store subdomain (orion.omsflow.lu)       → STOREFRONT
4. Store context set by middleware         → STOREFRONT
5. Default                                  → PLATFORM

Path Patterns

# Admin paths
ADMIN_PATH_PREFIXES = ("/admin", "/api/v1/admin")

# Store dashboard paths
STORE_PATH_PREFIXES = ("/store/", "/api/v1/store")

# Storefront paths
STOREFRONT_PATH_PREFIXES = (
    "/storefront",
    "/api/v1/storefront",
    "/shop",           # Legacy support
    "/api/v1/shop",    # Legacy support
    "/stores/",       # Path-based store access
)

# Platform paths
PLATFORM_PATH_PREFIXES = ("/api/v1/platform",)

Reserved Subdomains

These subdomains are NOT treated as store storefronts:

RESERVED_SUBDOMAINS = {"www", "admin", "api", "store", "portal"}

Usage

In Middleware/Routes

from middleware.frontend_type import get_frontend_type
from app.modules.enums import FrontendType

@router.get("/some-route")
async def some_route(request: Request):
    frontend_type = get_frontend_type(request)

    if frontend_type == FrontendType.ADMIN:
        # Admin-specific logic
        pass
    elif frontend_type == FrontendType.STOREFRONT:
        # Storefront-specific logic
        pass

Direct Detection (without request)

from app.core.frontend_detector import FrontendDetector
from app.modules.enums import FrontendType

# Full detection
frontend_type = FrontendDetector.detect(
    host="orion.omsflow.lu",
    path="/products",
    has_store_context=True
)
# Returns: FrontendType.STOREFRONT

# Convenience methods
if FrontendDetector.is_admin(host, path):
    # Admin logic
    pass

if FrontendDetector.is_storefront(host, path, has_store_context=True):
    # Storefront logic
    pass

Detection Scenarios

Development Mode (localhost)

Request Host Path Frontend
Admin page localhost /admin/stores ADMIN
Admin API localhost /api/v1/admin/users ADMIN
Store dashboard localhost /store/settings STORE
Store API localhost /api/v1/store/products STORE
Storefront localhost /storefront/products STOREFRONT
Storefront (path-based) localhost /stores/orion/products STOREFRONT
Marketing localhost /pricing PLATFORM

Production Mode (domains)

Request Host Path Frontend
Admin subdomain admin.omsflow.lu /dashboard ADMIN
Store subdomain orion.omsflow.lu /products STOREFRONT
Custom domain mybakery.lu /products STOREFRONT
Platform root omsflow.lu /pricing PLATFORM

Request State

After FrontendTypeMiddleware runs, the following is available:

request.state.frontend_type  # FrontendType enum value

This is used by:

  • LanguageMiddleware - to determine language resolution strategy
  • ErrorRenderer - to select appropriate error templates
  • ExceptionHandler - to redirect to correct login page
  • Route handlers - for frontend-specific logic

Testing

Unit Tests

Tests are located in:

  • tests/unit/core/test_frontend_detector.py - FrontendDetector tests
  • tests/unit/middleware/test_frontend_type.py - Middleware tests

Running Tests

# Run all frontend detection tests
pytest tests/unit/core/test_frontend_detector.py tests/unit/middleware/test_frontend_type.py -v

# Run with coverage
pytest tests/unit/core/test_frontend_detector.py tests/unit/middleware/test_frontend_type.py --cov=app.core.frontend_detector --cov=middleware.frontend_type

Best Practices

DO

  1. Use get_frontend_type(request) in route handlers
  2. Use FrontendDetector.detect() when you have host/path but no request
  3. Use convenience methods like is_admin(), is_storefront() for boolean checks
  4. Import from the correct location:
    from app.modules.enums import FrontendType
    from middleware.frontend_type import get_frontend_type
    from app.core.frontend_detector import FrontendDetector
    

DON'T

  1. Don't duplicate path detection logic - use FrontendDetector
  2. Don't hardcode path patterns in middleware - they're centralized in FrontendDetector
  3. Don't check request.state.context_type - use request.state.frontend_type

Architecture Rules

These rules are enforced by scripts/validate/validate_architecture.py:

Rule Description
MID-001 Use FrontendDetector for frontend detection
MID-002 Don't hardcode path patterns in middleware
MID-003 Use FrontendType enum, not RequestContext