feat: production routing support for subdomain and custom domain modes
Some checks failed
CI / ruff (push) Successful in 10s
CI / pytest (push) Failing after 45m18s
CI / validate (push) Successful in 24s
CI / dependency-scanning (push) Successful in 30s
CI / docs (push) Has been skipped
CI / deploy (push) Has been skipped

Double-mount store routes at /store/* and /store/{store_code}/* so the
same handlers work in dev path-based, prod path-based, prod subdomain,
and prod custom-domain modes.  Wire StorePlatform.custom_subdomain into
StoreContextMiddleware for per-platform subdomain overrides.  Add admin
custom-domain management UI, fix stale /shop/ reset link, add
/merchants/ to reserved paths, and server-render window.STORE_CODE for
JS that previously parsed the URL.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 00:15:06 +01:00
parent 6a82d7c12d
commit ce5b54f27b
36 changed files with 822 additions and 151 deletions

View File

@@ -39,7 +39,7 @@ The cookie path restrictions prevent cross-context cookie leakage:
import logging
from datetime import UTC
from fastapi import Cookie, Depends, Request
from fastapi import Cookie, Depends, HTTPException, Request
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from sqlalchemy.orm import Session
@@ -73,6 +73,19 @@ logger = logging.getLogger(__name__)
# ============================================================================
async def get_resolved_store_code(request: Request) -> str:
"""Get store code from path parameter (path-based) or middleware (subdomain/custom domain)."""
# Path parameter from double-mount prefix (/store/{store_code}/...)
store_code = request.path_params.get("store_code")
if store_code:
return store_code
# Middleware-resolved store (subdomain or custom domain)
store = getattr(request.state, "store", None)
if store:
return store.store_code
raise HTTPException(status_code=404, detail="Store not found")
def _get_token_from_request(
credentials: HTTPAuthorizationCredentials | None,
cookie_value: str | None,