diff --git a/.env.example b/.env.example index 4d5cc5f9..63bcb6a0 100644 --- a/.env.example +++ b/.env.example @@ -67,10 +67,10 @@ LOG_LEVEL=INFO LOG_FILE=logs/app.log # ============================================================================= -# PLATFORM DOMAIN CONFIGURATION +# MAIN DOMAIN CONFIGURATION # ============================================================================= # Your main platform domain -PLATFORM_DOMAIN=wizard.lu +MAIN_DOMAIN=wizard.lu # Custom domain features # Enable/disable custom domains diff --git a/app/core/config.py b/app/core/config.py index 6eebafc1..d8c83bdd 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -6,7 +6,7 @@ This module provides classes and functions for: - Configuration management via environment variables - Database settings - JWT and authentication configuration -- Platform domain and multi-tenancy settings +- Main domain and multi-tenancy settings - Admin initialization settings Note: Environment detection is handled by app.core.environment module. @@ -94,9 +94,9 @@ class Settings(BaseSettings): log_file: str | None = None # ============================================================================= - # PLATFORM DOMAIN CONFIGURATION + # MAIN DOMAIN CONFIGURATION # ============================================================================= - platform_domain: str = "wizard.lu" + main_domain: str = "wizard.lu" # Custom domain features allow_custom_domains: bool = True @@ -353,7 +353,7 @@ def print_environment_info(): print(f" Database: {settings.database_url}") print(f" Debug mode: {settings.debug}") print(f" API port: {settings.api_port}") - print(f" Platform: {settings.platform_domain}") + print(f" Platform: {settings.main_domain}") print(f" Secure cookies: {should_use_secure_cookies()}") print("=" * 70 + "\n") diff --git a/app/modules/billing/routes/api/store_addons.py b/app/modules/billing/routes/api/store_addons.py index 4f3c7345..1ea08bcc 100644 --- a/app/modules/billing/routes/api/store_addons.py +++ b/app/modules/billing/routes/api/store_addons.py @@ -144,7 +144,7 @@ def purchase_addon( store = billing_service.get_store(db, store_id) # Build URLs - base_url = f"https://{settings.platform_domain}" + base_url = f"https://{settings.main_domain}" success_url = f"{base_url}/store/{store.store_code}/billing?addon_success=true" cancel_url = f"{base_url}/store/{store.store_code}/billing?addon_cancelled=true" diff --git a/app/modules/billing/routes/api/store_checkout.py b/app/modules/billing/routes/api/store_checkout.py index 89d1aa2d..5e86e104 100644 --- a/app/modules/billing/routes/api/store_checkout.py +++ b/app/modules/billing/routes/api/store_checkout.py @@ -59,7 +59,7 @@ def create_checkout_session( store_code = subscription_service.get_store_code(db, store_id) - base_url = f"https://{settings.platform_domain}" + base_url = f"https://{settings.main_domain}" success_url = f"{base_url}/store/{store_code}/billing?success=true" cancel_url = f"{base_url}/store/{store_code}/billing?cancelled=true" @@ -87,7 +87,7 @@ def create_portal_session( merchant_id, platform_id = subscription_service.resolve_store_to_merchant(db, store_id, current_user.token_platform_id) store_code = subscription_service.get_store_code(db, store_id) - return_url = f"https://{settings.platform_domain}/store/{store_code}/billing" + return_url = f"https://{settings.main_domain}/store/{store_code}/billing" result = billing_service.create_portal_session(db, merchant_id, platform_id, return_url) diff --git a/app/modules/billing/services/signup_service.py b/app/modules/billing/services/signup_service.py index 03984fee..dfe92e60 100644 --- a/app/modules/billing/services/signup_service.py +++ b/app/modules/billing/services/signup_service.py @@ -617,7 +617,7 @@ class SignupService: # Build login URL login_url = ( - f"https://{settings.platform_domain}" + f"https://{settings.main_domain}" f"/store/{store.store_code}/dashboard" ) diff --git a/app/modules/core/utils/page_context.py b/app/modules/core/utils/page_context.py index 60fdb0a6..eb25b9ff 100644 --- a/app/modules/core/utils/page_context.py +++ b/app/modules/core/utils/page_context.py @@ -205,7 +205,7 @@ def _build_base_context( "request": request, "platform": platform, "platform_name": settings.project_name, - "platform_domain": settings.platform_domain, + "main_domain": settings.main_domain, } # Add i18n globals diff --git a/app/modules/tenancy/models/store.py b/app/modules/tenancy/models/store.py index 9a9e2715..3ec8c586 100644 --- a/app/modules/tenancy/models/store.py +++ b/app/modules/tenancy/models/store.py @@ -335,19 +335,19 @@ class Store(Base, TimestampMixin): Domain Resolution Priority: 1. Store-specific custom domain (StoreDomain) -> highest priority 2. Merchant domain (MerchantDomain) -> inherited default - 3. Store subdomain ({store.subdomain}.{platform_domain}) -> fallback + 3. Store subdomain ({store.subdomain}.{main_domain}) -> fallback """ if self.primary_domain: return self.primary_domain if self.merchant and self.merchant.primary_domain: return self.merchant.primary_domain - return f"{self.subdomain}.{settings.platform_domain}" + return f"{self.subdomain}.{settings.main_domain}" @property def all_domains(self): """Get all active domains (subdomain + custom domains).""" domains = [ - f"{self.subdomain}.{settings.platform_domain}" + f"{self.subdomain}.{settings.main_domain}" ] # Start with the main subdomain for domain in self.domains: if domain.is_active: diff --git a/docs/architecture/middleware.md b/docs/architecture/middleware.md index a93af380..c98b621c 100644 --- a/docs/architecture/middleware.md +++ b/docs/architecture/middleware.md @@ -92,12 +92,15 @@ INFO Response: 200 for GET /admin/dashboard (0.143s) **Purpose**: Detect which store's storefront the request is for (multi-tenant core) **What it does**: -- Detects store from: - - Custom domain (e.g., `customdomain.com`) — via `StoreDomain` lookup (optionally scoped to a platform via `StoreDomain.platform_id`) - - Subdomain with two-step lookup: - 1. `StorePlatform.custom_subdomain` — per-platform subdomain overrides (e.g., `wizatech-rewards.rewardflow.lu`) - 2. `Store.subdomain` — standard subdomain fallback (e.g., `wizatech.omsflow.lu`) - - Path prefix (e.g., `/store/store1/` or `/stores/store1/`) +- Guards based on platform domain awareness: + - When `host == platform.domain` (e.g., `rewardflow.lu`): Methods 1 & 2 are skipped (the platform's own domain is not a store) + - When host is a subdomain of `platform.domain` (e.g., `acme.rewardflow.lu`): Method 1 (custom domain) is skipped +- Detects store from (in priority order): + 1. Custom domain (e.g., `customdomain.com`) — via `StoreDomain` lookup (skipped on platform domains) + 2. Subdomain with two-step lookup: + - `StorePlatform.custom_subdomain` — per-platform subdomain overrides (e.g., `wizatech-rewards.rewardflow.lu`) + - `Store.subdomain` — standard subdomain fallback (e.g., `wizatech.omsflow.lu`) + 3. Path prefix (e.g., `/store/store1/` or `/stores/store1/`) — always runs as fallback - Queries database to find store by domain or code - Injects store object and platform into `request.state.store` - Extracts "clean path" (path without store prefix) diff --git a/docs/architecture/module-system.md b/docs/architecture/module-system.md index dc03409c..a75357f4 100644 --- a/docs/architecture/module-system.md +++ b/docs/architecture/module-system.md @@ -563,7 +563,7 @@ Every context includes these base variables regardless of modules: | `request` | FastAPI Request object | | `platform` | Platform model (may be None) | | `platform_name` | From settings.project_name | -| `platform_domain` | From settings.platform_domain | +| `main_domain` | From settings.main_domain | | `_` | Translation function (gettext style) | | `t` | Translation function (key-value style) | | `current_language` | Current language code | diff --git a/docs/architecture/multi-tenant.md b/docs/architecture/multi-tenant.md index 5318ee29..4efb6858 100644 --- a/docs/architecture/multi-tenant.md +++ b/docs/architecture/multi-tenant.md @@ -113,26 +113,37 @@ platform.com/storefront/store3 → Store 3 Storefront ### Store Detection Logic -The `StoreContextMiddleware` detects stores using this priority: +The `StoreContextMiddleware` detects stores via `_detect_store_from_host_and_path()`. +Before trying the three detection methods, two guards determine which methods apply: + +- **`is_platform_domain`**: `host == platform.domain` (e.g., `rewardflow.lu` itself) — skips Methods 1 & 2 +- **`is_subdomain_of_platform`**: host is a subdomain of `platform.domain` (e.g., `acme.rewardflow.lu`) — skips Method 1 ```python -def detect_store(request): - host = request.headers.get("host") +def detect_store(host, path, platform): + platform_own_domain = platform.domain # e.g. "rewardflow.lu" + is_platform_domain = (host == platform_own_domain) + is_subdomain_of_platform = ( + host != platform_own_domain + and host.endswith(f".{platform_own_domain}") + ) - # 1. Try custom domain first - store = find_by_custom_domain(host) - if store: - return store, "custom_domain" + # 1. Custom domain — skipped when host is platform domain or subdomain of it + if not is_platform_domain and not is_subdomain_of_platform: + main_domain = settings.main_domain # e.g. "wizard.lu" + if host != main_domain and not host.endswith(f".{main_domain}"): + store = find_by_custom_domain(host) + if store: + return store, "custom_domain" - # 2. Try subdomain - if host != settings.platform_domain: - store_code = host.split('.')[0] - store = find_by_code(store_code) + # 2. Subdomain — skipped when host IS the platform domain + if not is_platform_domain and "." in host: + subdomain = host.split('.')[0] + store = find_by_code(subdomain) if store: return store, "subdomain" - # 3. Try path-based - path = request.url.path + # 3. Path-based — always runs as fallback if path.startswith("/store/") or path.startswith("/storefront/"): store_code = extract_code_from_path(path) store = find_by_code(store_code) diff --git a/docs/architecture/request-flow.md b/docs/architecture/request-flow.md index 1d918022..923e4633 100644 --- a/docs/architecture/request-flow.md +++ b/docs/architecture/request-flow.md @@ -78,6 +78,7 @@ logger.info(f"Request: GET /storefront/products from 192.168.1.100") **What happens**: - Analyzes host header and path +- Checks platform domain guards: if host matches `platform.domain`, Methods 1 & 2 are skipped; if host is a subdomain of `platform.domain`, Method 1 is skipped - Determines routing mode (custom domain / subdomain / path-based) - Queries database for store - Extracts clean path diff --git a/docs/backend/middleware-reference.md b/docs/backend/middleware-reference.md index 2e3af19a..3bc6eeb0 100644 --- a/docs/backend/middleware-reference.md +++ b/docs/backend/middleware-reference.md @@ -43,9 +43,10 @@ The core authentication manager handling JWT tokens, password hashing, and role- Detects and manages store context from custom domains, subdomains, or path-based routing. This is the foundation of the multi-tenant system. **Key Features:** +- Platform domain awareness: skips custom domain / subdomain detection when host is the platform's own domain - Custom domain routing (customdomain.com → Store) - Subdomain routing (store1.platform.com → Store) -- Path-based routing (/store/store1/ → Store) +- Path-based routing (/store/store1/ → Store) — always runs as fallback - Clean path extraction for nested routing ::: middleware.store_context.StoreContextManager diff --git a/docs/deployment/environment.md b/docs/deployment/environment.md index 228f16fb..20d75da0 100644 --- a/docs/deployment/environment.md +++ b/docs/deployment/environment.md @@ -123,7 +123,7 @@ Controls the base domain for store subdomains and custom-domain features. | Variable | Description | Default | Required | |---|---|---|---| -| `PLATFORM_DOMAIN` | Root domain under which store subdomains are created | `wizard.lu` | No | +| `MAIN_DOMAIN` | Root domain under which store subdomains are created | `wizard.lu` | No | | `ALLOW_CUSTOM_DOMAINS` | Allow stores to use their own domain names | `True` | No | | `REQUIRE_DOMAIN_VERIFICATION` | Require DNS verification before activating a custom domain | `True` | No | | `SSL_PROVIDER` | SSL certificate provider (`letsencrypt`, `cloudflare`, `manual`) | `letsencrypt` | No | diff --git a/docs/development/database-seeder/database-init-guide.md b/docs/development/database-seeder/database-init-guide.md index 382d1c47..3c6f4fd6 100644 --- a/docs/development/database-seeder/database-init-guide.md +++ b/docs/development/database-seeder/database-init-guide.md @@ -911,7 +911,7 @@ settings.invitation_expiry_days # int settings.database_url # str # Platform -settings.platform_domain # str +settings.main_domain # str settings.project_name # str ``` diff --git a/middleware/store_context.py b/middleware/store_context.py index 234a99ce..6e756537 100644 --- a/middleware/store_context.py +++ b/middleware/store_context.py @@ -37,57 +37,80 @@ class StoreContextManager: """ Detect store context from request. - Priority order: - 1. Custom domain (customdomain1.com) - 2. Subdomain (store1.platform.com) - 3. Path-based (/store/store1/ or /stores/store1/) - - Uses platform_clean_path from PlatformContextMiddleware when available. - This path has the platform prefix stripped (e.g., /oms/stores/foo → /stores/foo). + Thin wrapper around _detect_store_from_host_and_path() that extracts + host, path, and platform from the request object. Returns dict with store info or None if not found. """ host = request.headers.get("host", "") # Use platform_clean_path if available (set by PlatformContextMiddleware) path = getattr(request.state, "platform_clean_path", None) or request.url.path + platform = getattr(request.state, "platform", None) + + return StoreContextManager._detect_store_from_host_and_path(host, path, platform) + + @staticmethod + def _detect_store_from_host_and_path(host: str, path: str, platform=None) -> dict | None: + """ + Core store detection logic from host and path. + + Priority order: + 1. Custom domain (customdomain1.com) — skipped on platform domains + 2. Subdomain (store1.platform.com) — skipped on platform domains + 3. Path-based (/store/store1/ or /stores/store1/) — always runs as fallback + + Args: + host: The request host header (may include port) + path: The clean path (platform prefix already stripped) + platform: Optional platform object from middleware state + + Returns dict with store info or None if not found. + """ + original_host = host # Remove port from host if present (e.g., localhost:8000 -> localhost) if ":" in host: host = host.split(":")[0] - # Method 1: Custom domain detection (HIGHEST PRIORITY) - # Check if this is a custom domain (not platform.com and not localhost) - platform_domain = getattr(settings, "platform_domain", "platform.com") - - # Skip custom domain detection if host is already a platform domain + # Determine if host is the platform's own domain or a subdomain of it # (e.g. rewardflow.lu is the loyalty platform, not a store) - platform = getattr(request.state, "platform", None) + # (e.g. acme.rewardflow.lu is a subdomain OF the platform, not a custom domain) + platform_own_domain = getattr(platform, "domain", None) if platform else None is_platform_domain = ( - platform and getattr(platform, "domain", None) - and host == platform.domain + platform_own_domain and host == platform_own_domain + ) + is_subdomain_of_platform = ( + platform_own_domain + and host != platform_own_domain + and host.endswith(f".{platform_own_domain}") ) - is_custom_domain = ( - host - and not is_platform_domain - and not host.endswith(f".{platform_domain}") - and host != platform_domain - and host - not in ["localhost", "127.0.0.1", "admin.localhost", "admin.127.0.0.1"] - and not host.startswith("admin.") - ) + # Method 1: Custom domain detection (HIGHEST PRIORITY) + # Skip if host is a platform domain or a subdomain of one + if not is_platform_domain and not is_subdomain_of_platform: + main_domain = getattr(settings, "main_domain", "platform.com") - if is_custom_domain: - normalized_domain = StoreDomain.normalize_domain(host) - return { - "domain": normalized_domain, - "detection_method": "custom_domain", - "host": host, - "original_host": request.headers.get("host", ""), - } + is_custom_domain = ( + host + and not host.endswith(f".{main_domain}") + and host != main_domain + and host + not in ["localhost", "127.0.0.1", "admin.localhost", "admin.127.0.0.1"] + and not host.startswith("admin.") + ) - # Method 2: Subdomain detection (store1.platform.com) - if "." in host: + if is_custom_domain: + normalized_domain = StoreDomain.normalize_domain(host) + return { + "domain": normalized_domain, + "detection_method": "custom_domain", + "host": host, + "original_host": original_host, + } + + # Method 2: Subdomain detection (acme.rewardflow.lu → "acme") + # Runs for subdomains of the platform domain, skipped for exact platform domain + if not is_platform_domain and "." in host: parts = host.split(".") # Check if it's a valid subdomain (not www, admin, api) if len(parts) >= 2 and parts[0] not in ["www", "admin", "api"]: @@ -349,12 +372,12 @@ class StoreContextManager: # Method 2: Subdomain detection from referer host # orion.platform.com → orion - platform_domain = getattr(settings, "platform_domain", "platform.com") + main_domain = getattr(settings, "main_domain", "platform.com") if "." in referer_host: parts = referer_host.split(".") if len(parts) >= 2 and parts[0] not in ["www", "admin", "api"]: - # Check if it's a subdomain of platform domain - if referer_host.endswith(f".{platform_domain}"): + # Check if it's a subdomain of main domain + if referer_host.endswith(f".{main_domain}"): subdomain = parts[0] logger.debug( f"[STORE] Extracted store from Referer subdomain: {subdomain}", @@ -374,8 +397,8 @@ class StoreContextManager: # custom-shop.com → custom-shop.com is_custom_domain = ( referer_host - and not referer_host.endswith(f".{platform_domain}") - and referer_host != platform_domain + and not referer_host.endswith(f".{main_domain}") + and referer_host != main_domain and referer_host not in ["localhost", "127.0.0.1"] and not referer_host.startswith("admin.") ) diff --git a/scripts/seed/init_production.py b/scripts/seed/init_production.py index d38ce0c4..be78df76 100644 --- a/scripts/seed/init_production.py +++ b/scripts/seed/init_production.py @@ -390,14 +390,14 @@ def create_admin_settings(db: Session) -> int: }, { "key": "platform_url", - "value": f"https://{settings.platform_domain}", + "value": f"https://{settings.main_domain}", "value_type": "string", "description": "Main platform URL", "is_public": True, }, { "key": "support_email", - "value": f"support@{settings.platform_domain}", + "value": f"support@{settings.main_domain}", "value_type": "string", "description": "Platform support email", "is_public": True, diff --git a/scripts/seed/install.py b/scripts/seed/install.py index f99d7f87..104f971f 100755 --- a/scripts/seed/install.py +++ b/scripts/seed/install.py @@ -339,7 +339,7 @@ def validate_configuration(env_vars: dict) -> dict: # ------------------------------------------------------------------------- # Platform Domain # ------------------------------------------------------------------------- - domain = env_vars.get("PLATFORM_DOMAIN", "orion.lu") + domain = env_vars.get("MAIN_DOMAIN", "orion.lu") if domain != "orion.lu": results["domain"] = { "status": "ok", @@ -350,7 +350,7 @@ def validate_configuration(env_vars: dict) -> dict: results["domain"] = { "status": "warning", "message": "Using default domain", - "items": ["Set PLATFORM_DOMAIN for your deployment"] + "items": ["Set MAIN_DOMAIN for your deployment"] } # ------------------------------------------------------------------------- diff --git a/scripts/seed/seed_demo.py b/scripts/seed/seed_demo.py index d5e27990..7adf4a52 100644 --- a/scripts/seed/seed_demo.py +++ b/scripts/seed/seed_demo.py @@ -1445,7 +1445,7 @@ def print_summary(db: Session): print("\n🏪 Demo Stores:") for store in stores: print(f"\n {store.name} ({store.store_code})") - print(f" Subdomain: {store.subdomain}.{settings.platform_domain}") + print(f" Subdomain: {store.subdomain}.{settings.main_domain}") # Show per-platform custom subdomains from app.modules.tenancy.models import Platform diff --git a/scripts/show_urls.py b/scripts/show_urls.py index 7a745a95..aa556ca4 100644 --- a/scripts/show_urls.py +++ b/scripts/show_urls.py @@ -235,19 +235,19 @@ def print_dev_urls(platforms, stores, store_domains, store_platform_map): def print_prod_urls(platforms, stores, store_domains): """Print all production URLs.""" - platform_domain = settings.platform_domain + main_domain = settings.main_domain print() print("PRODUCTION URLS") - print(f"Platform domain: {platform_domain}") + print(f"Platform domain: {main_domain}") print(SEPARATOR) # Admin print() print(" ADMIN PANEL") - print(f" Login: https://admin.{platform_domain}/admin/login") - print(f" Dashboard: https://admin.{platform_domain}/admin/") - print(f" API: https://admin.{platform_domain}/api/v1/admin/") + print(f" Login: https://admin.{main_domain}/admin/login") + print(f" Dashboard: https://admin.{main_domain}/admin/") + print(f" API: https://admin.{main_domain}/api/v1/admin/") # Platforms print() @@ -259,10 +259,10 @@ def print_prod_urls(platforms, stores, store_domains): print(f" Home: https://{p.domain}/") elif p.code == "main": print(f" {p.name}{tag}") - print(f" Home: https://{platform_domain}/") + print(f" Home: https://{main_domain}/") else: print(f" {p.name} ({p.code}){tag}") - print(f" Home: https://{p.code}.{platform_domain}/") + print(f" Home: https://{p.code}.{main_domain}/") # Group domains by store domains_by_store = {} @@ -280,7 +280,7 @@ def print_prod_urls(platforms, stores, store_domains): tag = f" [{status_badge(v.is_active)}]" if not v.is_active else "" print(f" {v.name} ({v.store_code}){tag}") - print(f" Dashboard: https://{v.subdomain}.{platform_domain}/store/{v.store_code}/") + print(f" Dashboard: https://{v.subdomain}.{main_domain}/store/{v.store_code}/") # Storefronts print() @@ -295,7 +295,7 @@ def print_prod_urls(platforms, stores, store_domains): print(f" {v.name} ({v.store_code}){tag}") # Subdomain URL - print(f" Subdomain: https://{v.subdomain}.{platform_domain}/") + print(f" Subdomain: https://{v.subdomain}.{main_domain}/") # Custom domains vd_list = domains_by_store.get(v.id, []) diff --git a/scripts/verify-server.sh b/scripts/verify-server.sh index 9857c304..0075f017 100755 --- a/scripts/verify-server.sh +++ b/scripts/verify-server.sh @@ -63,7 +63,7 @@ if [ "$MODE" = "dev" ]; then fail ".env file not found — copy from .env.example" fi - REQUIRED_KEYS="DATABASE_URL REDIS_URL JWT_SECRET_KEY ADMIN_EMAIL PLATFORM_DOMAIN" + REQUIRED_KEYS="DATABASE_URL REDIS_URL JWT_SECRET_KEY ADMIN_EMAIL MAIN_DOMAIN" for key in $REQUIRED_KEYS; do val=$(env_val "$key") if [ -n "$val" ]; then diff --git a/tests/integration/middleware/README.md b/tests/integration/middleware/README.md index db43b324..844de6cf 100644 --- a/tests/integration/middleware/README.md +++ b/tests/integration/middleware/README.md @@ -37,7 +37,7 @@ def client(db): with patch("middleware.store_context.get_db", override_get_db): with patch("middleware.theme_context.get_db", override_get_db): with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" client = TestClient(app) yield client ``` diff --git a/tests/integration/middleware/conftest.py b/tests/integration/middleware/conftest.py index 19a16f0e..def67e08 100644 --- a/tests/integration/middleware/conftest.py +++ b/tests/integration/middleware/conftest.py @@ -49,7 +49,7 @@ def client(db): This patches: 1. get_db in both middleware modules to use the test database - 2. settings.platform_domain in store_context to use 'platform.com' for testing + 2. settings.main_domain in store_context to use 'platform.com' for testing This ensures middleware can see test fixtures and detect subdomains correctly. """ @@ -64,7 +64,7 @@ def client(db): # Patch get_db in middleware modules - they have their own imports # The middleware calls: db_gen = get_db(); db = next(db_gen) - # Also patch settings.platform_domain so subdomain detection works with test hosts + # Also patch settings.main_domain so subdomain detection works with test hosts # Also bypass StorefrontAccessMiddleware subscription check for test routes — # these tests verify store context detection, not subscription access. from middleware.storefront_access import SKIP_PATH_PREFIXES @@ -76,7 +76,7 @@ def client(db): with patch("middleware.theme_context.get_db", override_get_db): with patch("middleware.store_context.settings") as mock_settings: with patch("middleware.storefront_access.SKIP_PATH_PREFIXES", test_skip_prefixes): - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" client = TestClient(app) yield client diff --git a/tests/integration/middleware/middleware_test_routes.py b/tests/integration/middleware/middleware_test_routes.py index 31013bfc..ba0d8a4a 100644 --- a/tests/integration/middleware/middleware_test_routes.py +++ b/tests/integration/middleware/middleware_test_routes.py @@ -102,7 +102,7 @@ async def test_inactive_store_detection(request: Request): @router.get("/platform-domain") -async def test_platform_domain(request: Request): +async def test_main_domain(request: Request): """Test platform domain without subdomain.""" store = getattr(request.state, "store", None) return {"store_detected": store is not None} diff --git a/tests/integration/middleware/test_store_context_flow.py b/tests/integration/middleware/test_store_context_flow.py index ff1e2f47..84eca7f7 100644 --- a/tests/integration/middleware/test_store_context_flow.py +++ b/tests/integration/middleware/test_store_context_flow.py @@ -7,7 +7,7 @@ for all routing modes: subdomain, custom domain, and path-based. Note: These tests require the middleware conftest.py which patches: 1. get_db in middleware modules to use the test database session -2. settings.platform_domain to use 'platform.com' for testing subdomain detection +2. settings.main_domain to use 'platform.com' for testing subdomain detection """ import pytest @@ -137,7 +137,7 @@ class TestStoreContextFlow: data = response.json() assert data["store_detected"] is False - def test_platform_domain_without_subdomain_no_store(self, client): + def test_main_domain_without_subdomain_no_store(self, client): """Test that platform domain without subdomain doesn't detect store.""" response = client.get( "/middleware-test/platform-domain", headers={"host": "platform.com"} diff --git a/tests/unit/middleware/test_store_context.py b/tests/unit/middleware/test_store_context.py index 0e60fb51..e3de2ec3 100644 --- a/tests/unit/middleware/test_store_context.py +++ b/tests/unit/middleware/test_store_context.py @@ -43,7 +43,7 @@ class TestStoreContextManager: request.url = Mock(path="/") with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.detect_store_context(request) @@ -59,7 +59,7 @@ class TestStoreContextManager: request.url = Mock(path="/") with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.detect_store_context(request) @@ -75,7 +75,7 @@ class TestStoreContextManager: request.url = Mock(path="/") with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.detect_store_context(request) @@ -91,7 +91,7 @@ class TestStoreContextManager: request.url = Mock(path="/") with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.detect_store_context(request) @@ -155,7 +155,7 @@ class TestStoreContextManager: request.state.platform_clean_path = None with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.detect_store_context(request) @@ -170,7 +170,7 @@ class TestStoreContextManager: request.state.platform_clean_path = None with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.detect_store_context(request) @@ -185,7 +185,7 @@ class TestStoreContextManager: request.state.platform_clean_path = None with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.detect_store_context(request) @@ -200,7 +200,7 @@ class TestStoreContextManager: request.state.platform_clean_path = None with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.detect_store_context(request) @@ -441,7 +441,7 @@ class TestStoreContextManager: request.headers = {"referer": "http://orion.platform.com/storefront/products"} # noqa: SEC034 with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.extract_store_from_referer(request) @@ -456,7 +456,7 @@ class TestStoreContextManager: request.headers = {"referer": "http://my-custom-shop.com/storefront/products"} # noqa: SEC034 with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.extract_store_from_referer(request) @@ -490,7 +490,7 @@ class TestStoreContextManager: request.headers = {"referer": "http://admin.platform.com/dashboard"} # noqa: SEC034 with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.extract_store_from_referer(request) @@ -503,7 +503,7 @@ class TestStoreContextManager: request.headers = {"referer": "http://www.platform.com/storefront"} # noqa: SEC034 with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.extract_store_from_referer(request) @@ -515,7 +515,7 @@ class TestStoreContextManager: request.headers = {"referer": "http://localhost:8000/storefront"} with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.extract_store_from_referer(request) @@ -996,7 +996,7 @@ class TestEdgeCases: request.url = Mock(path="/") with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "platform.com" + mock_settings.main_domain = "platform.com" context = StoreContextManager.detect_store_context(request) diff --git a/tests/unit/middleware/test_store_context_custom_subdomain.py b/tests/unit/middleware/test_store_context_custom_subdomain.py index 9647e30e..3082c4e3 100644 --- a/tests/unit/middleware/test_store_context_custom_subdomain.py +++ b/tests/unit/middleware/test_store_context_custom_subdomain.py @@ -207,7 +207,7 @@ class TestPlatformInjectionIntoStoreContext: mock_request.url = Mock(path="/store/login") with patch("middleware.store_context.settings") as mock_settings: - mock_settings.platform_domain = "omsflow.lu" + mock_settings.main_domain = "omsflow.lu" context = StoreContextManager.detect_store_context(mock_request)