feat(subscriptions): migrate subscription management to merchant level and seed tiers

Move subscription create/edit from store detail (broken endpoint) to merchant
detail page with proper modal UI. Seed 4 subscription tiers (Essential,
Professional, Business, Enterprise) in init_production.py. Also includes
cross-module dependency declarations, store domain platform_id migration,
platform context middleware, CMS route fixes, and migration backups.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-09 21:04:04 +01:00
parent 7feacd5af8
commit 68493dc6cb
97 changed files with 13286 additions and 77 deletions

View File

@@ -108,7 +108,10 @@ class PlatformContextManager:
# Method 3: Default platform for localhost without /platforms/ prefix
# This serves the main marketing site
# Store routes require explicit platform via /platforms/{code}/store/...
if host_without_port in ["localhost", "127.0.0.1"]:
if path.startswith(("/store/", "/stores/")):
return None # No platform — handlers will show appropriate error
return {
"path_prefix": DEFAULT_PLATFORM_CODE,
"detection_method": "default",
@@ -138,6 +141,7 @@ class PlatformContextManager:
if context.get("detection_method") == "domain":
domain = context.get("domain")
if domain:
# Try Platform.domain first
platform = (
db.query(Platform)
.filter(Platform.domain == domain)
@@ -150,6 +154,26 @@ class PlatformContextManager:
f"[PLATFORM] Platform found via domain: {domain}{platform.name}"
)
return platform
# Fallback: Check StoreDomain for custom store domains
from app.modules.tenancy.models import StoreDomain
store_domain = (
db.query(StoreDomain)
.filter(StoreDomain.domain == domain, StoreDomain.is_active.is_(True))
.first()
)
if store_domain and store_domain.platform_id:
platform = (
db.query(Platform)
.filter(Platform.id == store_domain.platform_id, Platform.is_active.is_(True))
.first()
)
if platform:
logger.debug(
f"[PLATFORM] Platform found via store domain: {domain}{platform.name}"
)
return platform
logger.debug(f"[PLATFORM] No platform found for domain: {domain}")
# Method 2: Path-prefix lookup
@@ -399,7 +423,10 @@ class PlatformContextMiddleware:
}
# Method 3: Default for localhost - serves main marketing site
# Store routes require explicit platform via /platforms/{code}/store/...
if host_without_port in ["localhost", "127.0.0.1"]:
if path.startswith(("/store/", "/stores/")):
return None # No platform — handlers will show appropriate error
return {
"path_prefix": DEFAULT_PLATFORM_CODE,
"detection_method": "default",