docs: update routing docs and seed script for production routing changes
Some checks failed
CI / ruff (push) Successful in 9s
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 been cancelled

Reflect the production routing refactor (ce5b54f): document store dashboard
double-mounting, per-platform subdomain overrides via StorePlatform.custom_subdomain,
get_resolved_store_code dependency, and /merchants/ reserved path. Update seed
script to populate custom_subdomain and StoreDomain.platform_id for demo data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 11:44:43 +01:00
parent ce5b54f27b
commit d480b59df4
5 changed files with 238 additions and 51 deletions

View File

@@ -152,6 +152,10 @@ DEMO_STORES = [
"description": "Premium electronics and gadgets marketplace",
"theme_preset": "modern",
"custom_domain": "wizatech.shop",
"custom_domain_platform": "oms", # Link domain to OMS platform
"platform_subdomains": { # Per-platform subdomain overrides
"loyalty": "wizatech-rewards", # wizatech-rewards.rewardflow.lu
},
},
{
"merchant_index": 0, # WizaCorp
@@ -179,6 +183,7 @@ DEMO_STORES = [
"description": "Trendy clothing and accessories",
"theme_preset": "vibrant",
"custom_domain": "fashionhub.store",
"custom_domain_platform": "loyalty", # Link domain to Loyalty platform
},
{
"merchant_index": 1, # Fashion Group
@@ -799,12 +804,28 @@ def create_demo_stores(
)
).all()
# Build platform code→id lookup for this store's custom subdomain config
from app.modules.tenancy.models import Platform
platform_code_map = {}
if store_data.get("platform_subdomains") or store_data.get("custom_domain_platform"):
platform_rows = db.execute(select(Platform.id, Platform.code)).all()
platform_code_map = {code: pid for pid, code in platform_rows}
for i, (platform_id,) in enumerate(merchant_subs):
# Per-platform subdomain override for multi-platform stores
# Config uses platform codes; resolve to IDs
custom_sub = None
for pcode, subdomain_val in store_data.get("platform_subdomains", {}).items():
if platform_code_map.get(pcode) == platform_id:
custom_sub = subdomain_val
break
sp = StorePlatform(
store_id=store.id,
platform_id=platform_id,
is_active=True,
is_primary=(i == 0),
custom_subdomain=custom_sub,
)
db.add(sp)
@@ -814,6 +835,9 @@ def create_demo_stores(
f" Linked to {len(merchant_subs)} platform(s): "
f"{[pid for (pid,) in merchant_subs]}"
)
# Report custom subdomains if any
for pcode, subdomain_val in store_data.get("platform_subdomains", {}).items():
print_success(f" Custom subdomain on {pcode}: {subdomain_val}")
# Owner relationship is via Merchant.owner_user_id — no StoreUser needed
@@ -839,11 +863,15 @@ def create_demo_stores(
# Create custom domain if specified
if store_data.get("custom_domain"):
# Resolve platform_id from platform code (if specified)
domain_platform_code = store_data.get("custom_domain_platform")
domain_platform_id = platform_code_map.get(domain_platform_code) if domain_platform_code else None
domain = StoreDomain(
store_id=store.id,
domain=store_data[
"custom_domain"
], # ✅ Field is 'domain', not 'domain_name'
platform_id=domain_platform_id,
is_verified=True, # Auto-verified for demo
is_primary=True,
verification_token=None,
@@ -1290,6 +1318,20 @@ def print_summary(db: Session):
print(f"\n {store.name} ({store.store_code})")
print(f" Subdomain: {store.subdomain}.{settings.platform_domain}")
# Show per-platform custom subdomains
from app.modules.tenancy.models import Platform
store_platforms = (
db.query(StorePlatform, Platform)
.join(Platform, Platform.id == StorePlatform.platform_id)
.filter(StorePlatform.store_id == store.id)
.all()
)
for sp, platform in store_platforms:
if sp.custom_subdomain:
pdomain = getattr(platform, "domain", platform.code)
print(f" [{platform.code}] Custom subdomain: {sp.custom_subdomain}.{pdomain}")
# Query custom domains separately
custom_domain = (
db.query(StoreDomain)
@@ -1305,7 +1347,12 @@ def print_summary(db: Session):
or getattr(custom_domain, "name", None)
)
if domain_value:
print(f" Custom: {domain_value}")
platform_note = ""
if custom_domain.platform_id:
dp = db.query(Platform).filter(Platform.id == custom_domain.platform_id).first()
if dp:
platform_note = f" (linked to {dp.code})"
print(f" Custom: {domain_value}{platform_note}")
print(f" Status: {'✓ Active' if store.is_active else '✗ Inactive'}")
@@ -1375,6 +1422,25 @@ def print_summary(db: Session):
port = settings.api_port
base = f"http://localhost:{port}"
# Build store→platform details (including custom subdomains) for production URLs
from app.modules.tenancy.models import Platform
store_platform_details: dict[int, list[dict]] = {}
sp_detail_rows = db.execute(
select(
StorePlatform.store_id,
Platform.code,
Platform.domain,
StorePlatform.custom_subdomain,
).join(Platform, Platform.id == StorePlatform.platform_id)
.where(StorePlatform.is_active == True) # noqa: E712
.order_by(StorePlatform.store_id, StorePlatform.is_primary.desc())
).all()
for store_id, pcode, pdomain, custom_sub in sp_detail_rows:
store_platform_details.setdefault(store_id, []).append({
"code": pcode, "domain": pdomain, "custom_subdomain": custom_sub,
})
print("\n🏪 Store Access (Development):")
print("" * 70)
for store in stores:
@@ -1388,6 +1454,28 @@ def print_summary(db: Session):
print(f" [{pc}] Staff login: {base}/platforms/{pc}/store/{store.store_code}/login")
else:
print(" (!) No platform assigned")
print("\n🌐 Store Access (Production-style):")
print("" * 70)
for store in stores:
details = store_platform_details.get(store.id, [])
print(f" {store.name} ({store.store_code}):")
for d in details:
subdomain = d["custom_subdomain"] or store.subdomain
pdomain = d["domain"] or f"{d['code']}.example.com"
suffix = " (custom subdomain)" if d["custom_subdomain"] else ""
print(f" [{d['code']}] Storefront: https://{subdomain}.{pdomain}/{suffix}")
print(f" [{d['code']}] Dashboard: https://{subdomain}.{pdomain}/store/dashboard")
# Show custom domain if any
custom_domain = (
db.query(StoreDomain)
.filter(StoreDomain.store_id == store.id, StoreDomain.is_active == True)
.first()
)
if custom_domain:
dv = getattr(custom_domain, "domain", None)
if dv:
print(f" [custom] Storefront: https://{dv}/")
print()
print("⚠️ ALL DEMO CREDENTIALS ARE INSECURE - For development only!")