feat(roles): add admin store roles page, permission i18n, and menu integration
Some checks failed
Some checks failed
- 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:
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user