feat(roles): add admin store roles page, permission i18n, and menu integration
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 started running

- Add admin store roles page with merchant→store cascading for superadmin
  and store-only selection for platform admin
- Add permission catalog API with translated labels/descriptions (en/fr/de/lb)
- Add permission translations to all 15 module locale files (60 files total)
- Add info icon tooltips for permission descriptions in role editor
- Add store roles menu item and admin menu item in module definition
- Fix store-selector.js URL construction bug when apiEndpoint has query params
- Add admin store roles API (CRUD + platform scoping)
- Add integration tests for admin store roles and permission catalog

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 23:31:27 +01:00
parent 2b55e7458b
commit f95db7c0b1
83 changed files with 3491 additions and 513 deletions

View File

@@ -761,3 +761,96 @@ module_rules:
file_pattern: "main.py"
validates:
- "module_locales mount BEFORE module_static mount"
# =========================================================================
# Cross-Module Boundary Rules
# =========================================================================
- id: "MOD-025"
name: "Modules must NOT import models from other modules"
severity: "error"
description: |
Modules must access data from other modules through their SERVICE layer,
never by importing and querying their models directly.
This is the "services over models" principle: if module A needs data
from module B, it MUST call module B's service methods.
WRONG (direct model import):
# app/modules/orders/services/order_service.py
from app.modules.catalog.models import Product # FORBIDDEN
class OrderService:
def get_order_details(self, db, order_id):
product = db.query(Product).filter_by(id=pid).first()
RIGHT (service call):
# app/modules/orders/services/order_service.py
from app.modules.catalog.services import product_service
class OrderService:
def get_order_details(self, db, order_id):
product = product_service.get_product_by_id(db, pid)
ALSO RIGHT (provider protocol for core→optional):
# app/modules/core/services/stats_aggregator.py
from app.modules.contracts.metrics import MetricsProviderProtocol
# Discover providers through registry, no direct imports
EXCEPTIONS:
- Test fixtures may create models from other modules for setup
- TYPE_CHECKING imports for type hints are allowed
- Tenancy models (User, Store, Merchant, Platform) may be imported
as type hints in route signatures where FastAPI requires it,
but queries must go through tenancy services
WHY THIS MATTERS:
- Encapsulation: Modules own their data access patterns
- Refactoring: Module B can change its schema without breaking A
- Testability: Mock services, not database queries
- Consistency: Clear API boundaries between modules
- Decoupling: Modules can evolve independently
pattern:
file_pattern: "app/modules/*/services/**/*.py"
anti_patterns:
- "from app\\.modules\\.(?!<own_module>)\\.models import"
exceptions:
- "TYPE_CHECKING"
- "tests/"
- id: "MOD-026"
name: "Cross-module data access must use service methods"
severity: "error"
description: |
When a module needs data from another module, it must use that
module's public service API. Each module should expose service
methods for common data access patterns.
Service methods a module should expose:
- get_{entity}_by_id(db, id) -> Entity or None
- list_{entities}(db, filters) -> list[Entity]
- get_{entity}_count(db, filters) -> int
- search_{entities}(db, query, filters) -> list[Entity]
WRONG (direct query across module boundary):
# In orders module
count = db.query(func.count(Product.id)).scalar()
RIGHT (call catalog service):
# In orders module
count = product_service.get_product_count(db, store_id=store_id)
This applies to:
- Simple lookups (get by ID)
- List/search queries
- Aggregation queries (count, sum)
- Join queries (should be decomposed into service calls)
WHY THIS MATTERS:
- Single source of truth for data access logic
- Easier to add caching, validation, or access control
- Clear contract between modules
- Simpler testing with service mocks
pattern:
file_pattern: "app/modules/*/services/**/*.py"
check: "cross_module_service_usage"