Files
orion/app/modules/tenancy/routes/api/store.py
Samir Boulahtit 32acc76b49 feat: platform-aware storefront routing and billing improvements
Overhaul storefront URL routing to be platform-aware:
- Dev: /platforms/{code}/storefront/{store_code}/
- Prod: subdomain.platform.lu/ (internally rewritten to /storefront/)
- Add subdomain detection in PlatformContextMiddleware
- Add /storefront/ path rewrite for prod mode (subdomain/custom domain)
- Remove all silent platform fallbacks (platform_id=1)
- Add require_platform dependency for clean endpoint validation
- Update route registration, templates, module definitions, base_url calc
- Update StoreContextMiddleware for /storefront/ path detection
- Remove /stores/ from FrontendDetector STOREFRONT_PATH_PREFIXES

Billing service improvements:
- Add store_platform_sync_service to keep store_platforms in sync
- Make tier lookups platform-aware across billing services
- Add tiers for all platforms in seed data
- Add demo subscriptions to seed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:42:41 +01:00

99 lines
3.3 KiB
Python

# app/modules/tenancy/routes/api/store.py
"""
Tenancy module store API routes.
Aggregates all store tenancy routes:
- /info/{store_code} - Public store info lookup
- /auth/* - Store authentication (login, logout, /me)
- /profile/* - Store profile management
- /team/* - Team member management, roles, permissions
The tenancy module owns identity and organizational hierarchy.
"""
import logging
from fastapi import APIRouter, Depends, Path
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.modules.tenancy.schemas.store import StoreDetailResponse
from app.modules.tenancy.services.store_service import store_service # mod-004
store_router = APIRouter()
logger = logging.getLogger(__name__)
@store_router.get("/info/{store_code}", response_model=StoreDetailResponse)
def get_store_info(
store_code: str = Path(..., description="Store code"),
db: Session = Depends(get_db),
):
"""
Get public store information by store code.
This endpoint is used by the store login page to display store info.
No authentication required - this is public information.
**Use Case:**
- Store login page loads store info to display branding
- Shows store name, description, logo, etc.
**Returns only active stores** to prevent access to disabled accounts.
Args:
store_code: The store's unique code (e.g., 'ORION')
db: Database session
Returns:
StoreResponse: Public store information
Raises:
StoreNotFoundException (404): Store not found or inactive
"""
logger.info(f"Public store info request: {store_code}")
store = store_service.get_active_store_by_code(db, store_code)
logger.info(f"Store info retrieved: {store.name} ({store.store_code})")
return StoreDetailResponse(
# Store fields
id=store.id,
store_code=store.store_code,
subdomain=store.subdomain,
name=store.name,
description=store.description,
merchant_id=store.merchant_id,
letzshop_csv_url_fr=store.letzshop_csv_url_fr,
letzshop_csv_url_en=store.letzshop_csv_url_en,
letzshop_csv_url_de=store.letzshop_csv_url_de,
is_active=store.is_active,
is_verified=store.is_verified,
created_at=store.created_at,
updated_at=store.updated_at,
# Merchant info
merchant_name=store.merchant.name,
merchant_contact_email=store.merchant.contact_email,
merchant_contact_phone=store.merchant.contact_phone,
merchant_website=store.merchant.website,
# Owner details (from merchant)
owner_user_id=store.merchant.owner_user_id,
owner_email=store.merchant.owner.email,
owner_username=store.merchant.owner.username,
)
# ============================================================================
# Aggregate Sub-Routers
# ============================================================================
# Include all tenancy store routes (auth, profile, team)
from .store_auth import store_auth_router
from .store_profile import store_profile_router
from .store_team import store_team_router
store_router.include_router(store_auth_router, tags=["store-auth"])
store_router.include_router(store_profile_router, tags=["store-profile"])
store_router.include_router(store_team_router, tags=["store-team"])