refactor: rename platform_domain → main_domain to avoid confusion with platform.domain
Some checks failed
CI / ruff (push) Successful in 10s
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

The setting `settings.platform_domain` (the global/main domain like "wizard.lu")
was easily confused with `platform.domain` (per-platform domain like "rewardflow.lu").
Renamed to `settings.main_domain` / `MAIN_DOMAIN` env var across the entire codebase.

Also updated docs to reflect the refactored store detection logic with
`is_platform_domain` / `is_subdomain_of_platform` guards.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-14 04:45:28 +01:00
parent 4a1f71a312
commit c2c0e3c740
26 changed files with 152 additions and 113 deletions

View File

@@ -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.")
)