Files
orion/app/modules/tenancy/definition.py
Samir Boulahtit 0984ff7d17 feat(tenancy): add merchant-level domain with store override
Merchants can now register domains (e.g., myloyaltyprogram.lu) that all
their stores inherit. Individual stores can override with their own custom
domain. Resolution priority: StoreDomain > MerchantDomain > subdomain.

- Add MerchantDomain model, schema, service, and admin API endpoints
- Add merchant domain fallback in platform and store context middleware
- Add Merchant.primary_domain and Store.effective_domain properties
- Add Alembic migration for merchant_domains table
- Update loyalty user journey docs with subscription & domain setup flow
- Add unit tests (50 passing) and integration tests (15 passing)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 22:04:49 +01:00

194 lines
6.2 KiB
Python

# app/modules/tenancy/definition.py
"""
Tenancy Management module definition.
Platform, merchant, store, and admin user management.
Required for multi-tenant operation - cannot be disabled.
"""
from app.modules.base import (
MenuItemDefinition,
MenuSectionDefinition,
ModuleDefinition,
PermissionDefinition,
)
from app.modules.enums import FrontendType
def _get_metrics_provider():
"""Lazy import of metrics provider to avoid circular imports."""
from app.modules.tenancy.services.tenancy_metrics import tenancy_metrics_provider
return tenancy_metrics_provider
def _get_widget_provider():
"""Lazy import of widget provider to avoid circular imports."""
from app.modules.tenancy.services.tenancy_widgets import tenancy_widget_provider
return tenancy_widget_provider
def _get_feature_provider():
"""Lazy import of feature provider to avoid circular imports."""
from app.modules.tenancy.services.tenancy_features import tenancy_feature_provider
return tenancy_feature_provider
tenancy_module = ModuleDefinition(
code="tenancy",
name="Tenancy Management",
description="Platform, merchant, store, and admin user management. Required for multi-tenant operation.",
version="1.0.0",
is_core=True,
is_self_contained=True,
# Module-driven permissions
permissions=[
PermissionDefinition(
id="team.view",
label_key="tenancy.permissions.team_view",
description_key="tenancy.permissions.team_view_desc",
category="team",
),
PermissionDefinition(
id="team.invite",
label_key="tenancy.permissions.team_invite",
description_key="tenancy.permissions.team_invite_desc",
category="team",
is_owner_only=True,
),
PermissionDefinition(
id="team.edit",
label_key="tenancy.permissions.team_edit",
description_key="tenancy.permissions.team_edit_desc",
category="team",
is_owner_only=True,
),
PermissionDefinition(
id="team.remove",
label_key="tenancy.permissions.team_remove",
description_key="tenancy.permissions.team_remove_desc",
category="team",
is_owner_only=True,
),
],
features=[
"platform_management",
"merchant_management",
"store_management",
"admin_user_management",
],
# Legacy menu_items
menu_items={
FrontendType.ADMIN: [
"platforms",
"merchants",
"stores",
"admin-users",
"merchant-users",
],
FrontendType.STORE: [
"team",
],
},
# New module-driven menu definitions
menus={
FrontendType.ADMIN: [
MenuSectionDefinition(
id="userManagement",
label_key="tenancy.menu.user_management",
icon="users",
order=10,
items=[
MenuItemDefinition(
id="admin-users",
label_key="tenancy.menu.admin_users",
icon="shield",
route="/admin/admin-users",
order=10,
is_mandatory=True,
is_super_admin_only=True,
),
MenuItemDefinition(
id="merchant-users",
label_key="tenancy.menu.merchant_users",
icon="user-group",
route="/admin/merchant-users",
order=20,
is_mandatory=True,
),
],
),
MenuSectionDefinition(
id="platformAdmin",
label_key="tenancy.menu.platform_admin",
icon="office-building",
order=20,
items=[
MenuItemDefinition(
id="merchants",
label_key="tenancy.menu.merchants",
icon="office-building",
route="/admin/merchants",
order=10,
is_mandatory=True,
),
MenuItemDefinition(
id="stores",
label_key="tenancy.menu.stores",
icon="shopping-bag",
route="/admin/stores",
order=20,
is_mandatory=True,
),
],
),
MenuSectionDefinition(
id="contentMgmt",
label_key="tenancy.menu.content_management",
icon="globe-alt",
order=70,
items=[
MenuItemDefinition(
id="platforms",
label_key="tenancy.menu.platforms",
icon="globe-alt",
route="/admin/platforms",
order=10,
),
],
),
],
FrontendType.STORE: [
MenuSectionDefinition(
id="account",
label_key="tenancy.menu.account_settings",
icon="user-group",
order=900,
items=[
MenuItemDefinition(
id="team",
label_key="tenancy.menu.team",
icon="user-group",
route="/store/{store_code}/team",
order=5,
),
],
),
],
},
migrations_path="migrations",
services_path="app.modules.tenancy.services",
models_path="app.modules.tenancy.models",
schemas_path="app.modules.tenancy.schemas",
exceptions_path="app.modules.tenancy.exceptions",
# Metrics provider for dashboard statistics
metrics_provider=_get_metrics_provider,
# Widget provider for dashboard widgets
widget_provider=_get_widget_provider,
feature_provider=_get_feature_provider,
)
__all__ = ["tenancy_module"]