# 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
