Files
orion/docs/architecture/menu-management.md
Samir Boulahtit e3cab29c1a docs: add module system and menu management architecture documentation
Add comprehensive documentation for:
- Module system architecture (three-tier classification, registry, events, migrations)
- Menu management system (registry, visibility config, module integration)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 22:21:23 +01:00

404 lines
14 KiB
Markdown

# Menu Management Architecture
The Wizamart platform provides a flexible menu system that supports per-platform and per-user customization. This document explains the menu architecture, configuration options, and how menus integrate with the module system.
## Overview
```
┌─────────────────────────────────────────────────────────────────────────┐
│ MENU REGISTRY (Source of Truth) │
│ app/config/menu_registry.py │
│ │
│ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │
│ │ ADMIN_MENU_REGISTRY │ │ VENDOR_MENU_REGISTRY │ │
│ │ (Admin panel menus) │ │ (Vendor dashboard menus) │ │
│ └─────────────────────────────┘ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ VISIBILITY CONFIGURATION │
│ models/database/admin_menu_config.py │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ AdminMenuConfig Table │ │
│ │ Stores visibility overrides (hidden items only) │ │
│ │ - Platform scope: applies to platform admins/vendors │ │
│ │ - User scope: applies to specific super admin │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ FILTERED MENU OUTPUT │
│ │
│ Registry - Hidden Items - Disabled Modules = Visible Menu Items │
└─────────────────────────────────────────────────────────────────────────┘
```
## Frontend Types
The system supports two distinct frontend types:
| Frontend | Description | Users |
|----------|-------------|-------|
| `ADMIN` | Admin panel | Super admins, platform admins |
| `VENDOR` | Vendor dashboard | Vendors on a platform |
```python
from models.database.admin_menu_config import FrontendType
# Use in code
FrontendType.ADMIN # "admin"
FrontendType.VENDOR # "vendor"
```
## Menu Registry
The menu registry (`app/config/menu_registry.py`) is the **single source of truth** for menu structure. The database only stores visibility overrides.
### Admin Menu Structure
```python
ADMIN_MENU_REGISTRY = {
"frontend_type": FrontendType.ADMIN,
"sections": [
{
"id": "main",
"label": None, # No header
"items": [
{"id": "dashboard", "label": "Dashboard", "icon": "home", "url": "/admin/dashboard"},
],
},
{
"id": "superAdmin",
"label": "Super Admin",
"super_admin_only": True, # Only visible to super admins
"items": [
{"id": "admin-users", "label": "Admin Users", "icon": "shield", "url": "/admin/admin-users"},
],
},
# ... more sections
],
}
```
### Admin Menu Sections
| Section ID | Label | Description |
|------------|-------|-------------|
| `main` | (none) | Dashboard - always at top |
| `superAdmin` | Super Admin | Super admin only tools |
| `platformAdmin` | Platform Administration | Companies, vendors, messages |
| `vendorOps` | Vendor Operations | Products, customers, inventory, orders |
| `marketplace` | Marketplace | Letzshop integration |
| `billing` | Billing & Subscriptions | Tiers, subscriptions, billing history |
| `contentMgmt` | Content Management | Platforms, content pages, themes |
| `devTools` | Developer Tools | Components, icons |
| `platformHealth` | Platform Health | Capacity, testing, code quality |
| `monitoring` | Platform Monitoring | Imports, tasks, logs, notifications |
| `settingsSection` | Platform Settings | General settings, email templates, my menu |
### Vendor Menu Sections
| Section ID | Label | Description |
|------------|-------|-------------|
| `main` | (none) | Dashboard, analytics |
| `products` | Products & Inventory | Products, inventory, marketplace import |
| `sales` | Sales & Orders | Orders, Letzshop orders, invoices |
| `customers` | Customers | Customers, messages, notifications |
| `shop` | Shop & Content | Content pages, media library |
| `account` | Account & Settings | Team, profile, billing, settings |
### Menu Item Properties
Each menu item has these properties:
| Property | Type | Description |
|----------|------|-------------|
| `id` | string | Unique identifier (used for config and access control) |
| `label` | string | Display text |
| `icon` | string | Heroicons icon name |
| `url` | string | Route URL |
| `super_admin_only` | boolean | (Optional) Only visible to super admins |
## Visibility Configuration
### Opt-Out Model
The system uses an **opt-out model**:
- All menu items are **visible by default**
- Only **hidden** items are stored in the database
- This keeps the database small and makes the default state explicit
### Mandatory Items
Certain menu items cannot be hidden:
```python
MANDATORY_MENU_ITEMS = {
FrontendType.ADMIN: frozenset({
"dashboard", # Landing page
"companies", # Platform admin core
"vendors", # Platform admin core
"admin-users", # Super admin core
"settings", # Configuration access
"my-menu", # Must be able to undo changes
}),
FrontendType.VENDOR: frozenset({
"dashboard", # Landing page
"settings", # Configuration access
}),
}
```
### Scope Types
Menu configuration supports two scopes:
| Scope | Field | Description | Use Case |
|-------|-------|-------------|----------|
| Platform | `platform_id` | Applies to all users on platform | Hide features not used by platform |
| User | `user_id` | Applies to specific super admin | Personal preference customization |
**Important Rules:**
- Exactly one scope must be set (platform XOR user)
- User scope is only allowed for admin frontend (super admins only)
- Vendor frontend only supports platform scope
### Resolution Order
**Admin Frontend:**
```
Platform admin → Check platform config → Fall back to default (all visible)
Super admin → Check user config → Fall back to default (all visible)
```
**Vendor Frontend:**
```
Vendor → Check platform config → Fall back to default (all visible)
```
## Database Model
### AdminMenuConfig Table
```sql
CREATE TABLE admin_menu_configs (
id SERIAL PRIMARY KEY,
frontend_type VARCHAR(10) NOT NULL, -- 'admin' or 'vendor'
platform_id INTEGER REFERENCES platforms(id),
user_id INTEGER REFERENCES users(id),
menu_item_id VARCHAR(50) NOT NULL,
is_visible BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP,
updated_at TIMESTAMP,
-- Constraints
CONSTRAINT uq_frontend_platform_menu_config
UNIQUE (frontend_type, platform_id, menu_item_id),
CONSTRAINT uq_frontend_user_menu_config
UNIQUE (frontend_type, user_id, menu_item_id),
CONSTRAINT ck_admin_menu_config_scope
CHECK ((platform_id IS NOT NULL AND user_id IS NULL) OR
(platform_id IS NULL AND user_id IS NOT NULL)),
CONSTRAINT ck_user_scope_admin_only
CHECK ((user_id IS NULL) OR (frontend_type = 'admin'))
);
```
### Examples
```python
# Platform "OMS" hides inventory from admin panel
AdminMenuConfig(
frontend_type=FrontendType.ADMIN,
platform_id=1,
menu_item_id="inventory",
is_visible=False
)
# Platform "OMS" hides letzshop from vendor dashboard
AdminMenuConfig(
frontend_type=FrontendType.VENDOR,
platform_id=1,
menu_item_id="letzshop",
is_visible=False
)
# Super admin "john" hides code-quality from their admin panel
AdminMenuConfig(
frontend_type=FrontendType.ADMIN,
user_id=5,
menu_item_id="code-quality",
is_visible=False
)
```
## Module Integration
Menu items are associated with modules. When a module is disabled for a platform, its menu items are automatically hidden.
### Module to Menu Item Mapping
Each module defines its menu items per frontend:
```python
# In module definition
billing_module = ModuleDefinition(
code="billing",
menu_items={
FrontendType.ADMIN: ["subscription-tiers", "subscriptions", "billing-history"],
FrontendType.VENDOR: ["billing", "invoices"],
},
)
```
### Menu Filtering Logic
```python
from app.modules.service import module_service
# Get available menu items (module-aware)
available_items = module_service.get_module_menu_items(
db, platform_id, FrontendType.ADMIN
)
# Check if specific menu item's module is enabled
is_available = module_service.is_menu_item_module_enabled(
db, platform_id, "subscription-tiers", FrontendType.ADMIN
)
```
### Three-Layer Filtering
The final visible menu is computed by three layers:
1. **Registry**: All possible menu items
2. **Module Enablement**: Items from disabled modules are hidden
3. **Visibility Config**: Explicitly hidden items are removed
```
Final Menu = Registry Items
- Items from Disabled Modules
- Items with is_visible=False in config
- Items not matching user role (super_admin_only)
```
## Helper Functions
### Getting Menu Items
```python
from app.config.menu_registry import (
get_all_menu_item_ids,
get_menu_item,
is_super_admin_only_item,
ADMIN_MENU_REGISTRY,
VENDOR_MENU_REGISTRY,
)
# Get all item IDs for a frontend
admin_items = get_all_menu_item_ids(FrontendType.ADMIN)
# Returns: {'dashboard', 'admin-users', 'companies', ...}
# Get specific item details
item = get_menu_item(FrontendType.ADMIN, "subscription-tiers")
# Returns: {
# 'id': 'subscription-tiers',
# 'label': 'Subscription Tiers',
# 'icon': 'tag',
# 'url': '/admin/subscription-tiers',
# 'section_id': 'billing',
# 'section_label': 'Billing & Subscriptions'
# }
# Check if item requires super admin
is_restricted = is_super_admin_only_item("admin-users") # True
```
### Menu Enums
```python
from app.config.menu_registry import AdminMenuItem, VendorMenuItem
# Use enums for type safety
AdminMenuItem.DASHBOARD.value # "dashboard"
AdminMenuItem.INVENTORY.value # "inventory"
VendorMenuItem.PRODUCTS.value # "products"
VendorMenuItem.ANALYTICS.value # "analytics"
```
## Access Control
### Route Protection
```python
from app.api.deps import require_menu_access
@router.get("/admin/inventory")
async def inventory_page(
_access: bool = Depends(require_menu_access("inventory", FrontendType.ADMIN))
):
# Only accessible if menu item is visible for user's context
pass
```
### Sidebar Rendering
The sidebar template filters items based on:
1. Module enablement
2. Visibility configuration
3. User role (super admin check)
```jinja2
{% for section in menu_sections %}
{% if not section.super_admin_only or current_user.is_super_admin %}
{% for item in section.items %}
{% if item.id in visible_menu_items %}
<a href="{{ item.url }}">{{ item.label }}</a>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
```
## UI for Menu Configuration
### Platform Admin Menu Config
Located at `/admin/platform-menu-config` (accessible by super admins):
- Configure which menu items are visible for platform admins
- Configure which menu items are visible for vendors on this platform
- Mandatory items cannot be unchecked
### Personal Menu Config (Super Admins)
Located at `/admin/my-menu`:
- Super admins can customize their own admin panel menu
- Personal preferences that don't affect other users
- Useful for hiding rarely-used features
## Best Practices
### Do
- Use menu item enums (`AdminMenuItem`, `VendorMenuItem`) for type safety
- Check module enablement before showing module-specific menu items
- Respect mandatory items - don't try to hide them
- Use `require_menu_access` dependency to protect routes
### Don't
- Hardcode menu item IDs as strings (use enums)
- Store `is_visible=True` in database (default state, wastes space)
- Allow hiding mandatory items via API
- Create menu items without registering them in the registry
## Related Documentation
- [Module System](module-system.md) - Module architecture and menu item mapping
- [Multi-Tenant System](multi-tenant.md) - Platform isolation
- [Feature Gating](../implementation/feature-gating-system.md) - Tier-based access