# Module Onboarding Guide

How to take a new module from registration to a visible sidebar link for users.

**Audience:** Platform admins and developers  
**Related:** [IMPLEMENTATION_PHASES.md](../IMPLEMENTATION_PHASES.md)

---

## At a glance

```mermaid
flowchart LR
    A[Action Types] --> B[Module Registry]
    B --> C[Permissions auto-sync]
    C --> D[Menu Builder]
    D --> E[Role Matrix]
    E --> F[Assign User Roles]
    F --> G[Sidebar visible]
    G --> H[Frontend Route optional]
```

| Step | Admin UI | Required? | Result |
|------|----------|-----------|--------|
| 1 | Action Types | Optional | New action slugs (`cancel`, `publish`) |
| 2 | Module Registry | **Yes** | Module + linked actions |
| 3 | *(automatic)* | **Yes** | Permission keys in DB |
| 4 | Menu Builder | **Yes** | Sidebar link candidate |
| 5 | Roles → Permissions | **Yes** | Who can access |
| 6 | Users → Assign Roles | **Yes** | User gets access |
| 7 | *(automatic)* | — | Sidebar via `/me/navigation` |
| 8 | Frontend routes | For pages | Click opens page (not 404) |

> **Common mistake:** Module + Role alone does **not** show the sidebar. Step 4 (Menu) is mandatory.

---

## System architecture

### Three separate layers

```mermaid
flowchart TB
    subgraph define ["Define capabilities"]
        M[modules]
        MA[module_actions]
        P[permissions]
    end

    subgraph navigate ["Navigation UI"]
        MN[menus]
        NAV["GET /me/navigation"]
        SB[Sidebar]
    end

    subgraph authorize ["Who can access"]
        R[roles]
        RP[role_permissions]
        UR[user_roles]
        U[users]
    end

    M --> MA --> P
    MN --> NAV --> SB
    P --> RP --> R
    R --> UR --> U
    P -.->|permission_key match| MN
    U -.->|permission check| NAV
```

| Layer | Question it answers |
|-------|---------------------|
| **Module + permissions** | What *can* be done? (`siams-airgurd.view`) |
| **Menu** | What appears in the sidebar? |
| **Role + user** | Who is allowed to see/act? |

---

## End-to-end flow (detailed)

```mermaid
sequenceDiagram
    participant Admin
    participant ModuleUI as Module Registry
    participant DB as Database
    participant MenuUI as Menu Builder
    participant RoleUI as Roles
    participant UserUI as Users
    participant API as /me/navigation
    participant Sidebar

    Admin->>ModuleUI: Create module + link actions
    ModuleUI->>DB: modules, module_actions
    ModuleUI->>DB: permissions sync

    Admin->>MenuUI: Create menu item
    MenuUI->>DB: menus (route, permission_key)

    Admin->>RoleUI: Assign permissions in matrix
    RoleUI->>DB: role_permissions

    Admin->>UserUI: Assign role to user
    UserUI->>DB: user_roles

    Sidebar->>API: Fetch navigation
    API->>DB: Active menus + permission filter
    API->>Sidebar: Filtered menu tree
```

---

## Step-by-step

### Step 1 — Action types (optional)

**Path:** Admin → Module Registry → **Action Types** → Add Action  
**URL:** `/admin/actions/create`

Use when you need actions beyond the seeded set (`view`, `create`, `update`, `delete`, …).

| Field | Example |
|-------|---------|
| Name | Cancel |
| Slug | `cancel` |

Creates a row in `actions`. Does **not** create permissions until linked to a module.

---

### Step 2 — Register module

**Path:** Admin → **Module Registry** → Add Module  
**URL:** `/admin/modules/create`

| Field | Example | Notes |
|-------|---------|-------|
| Name | Siam's Airgurd | Display name |
| Slug | `siams-airgurd` | Used in permission keys |
| Status | **enabled** | Disabled modules hidden from permission matrix |
| Link Actions | view, delete, … | Checkboxes |

**Database effect:**

```
modules          → 1 row
module_actions   → 1 row per action (e.g. siams-airgurd.view)
permissions      → auto-synced from module_actions
```

---

### Step 3 — Permissions (automatic)

Permission key pattern:

```
{module_slug}.{action_slug}
```

Examples:

- `siams-airgurd.view`
- `siams-airgurd.delete`
- `platform.create`

Verify in **Roles → Permissions** matrix — module row should appear when status is `enabled`.

---

### Step 4 — Create menu (sidebar link)

**Path:** Admin → **Menu Builder** → Add Menu  
**URL:** `/admin/menus/create`

| Field | Example | Notes |
|-------|---------|-------|
| Title | Siam's Airgurd | Sidebar label |
| Type | `item` | Use `group` for section headers |
| Status | **active** | Inactive = hidden from navigation |
| Route | `/siams-airgurd` | Frontend path |
| Module | siams-airgurd | Optional link |
| Permission Key | `siams-airgurd.view` | See below |
| Parent Menu | **None** | Avoid orphan child issues |

#### Permission key on menus

```mermaid
flowchart TD
    MK[Menu permission_key]
    MK -->|empty| ALL[All users see menu]
    MK -->|siams-airgurd.view| CHECK{User has key?}
    CHECK -->|Yes| SHOW[Show in sidebar]
    CHECK -->|No| HIDE[Hidden from sidebar]
```

| Permission key | Effect |
|----------------|--------|
| *(empty)* | Everyone logged in sees the link |
| `siams-airgurd.view` | Only users with that permission in current company |

> Menu permission key controls **sidebar visibility only**. It does not protect API routes or React pages by itself.

---

### Step 5 — Role + permissions

**Path:** Admin → **Roles** → Create → **Permissions** (matrix)  
**URLs:** `/admin/roles/create`, `/admin/roles/{uuid}/permissions`

1. Create role (e.g. ABCS)
2. Open permission matrix
3. Tick module actions (e.g. `view`, `delete`)
4. Save

**Database effect:** `role_permissions` links role to permission IDs.

> **System roles** (e.g. Administrator) are read-only in the matrix UI.

---

### Step 6 — Assign role to user

**Path:** Admin → **Users** → Assign Roles  
**URL:** `/admin/users/{uuid}/roles`

Select role(s) for the user in the **current company**. Permissions are company-scoped.

---

### Step 7 — Sidebar appears

On login, the frontend calls:

```
GET /api/v1/me/navigation
Authorization: Bearer {token}
X-Company-Id: {company_uuid}
```

Backend logic:

1. Load active menus from `menus`
2. Filter by user's effective permissions (`permission_key` on each menu)
3. Build tree, return JSON
4. Sidebar renders links

After menu or role changes: **hard refresh** or logout/login (navigation is cached ~60s on frontend).

---

### Step 8 — Frontend route (optional but needed for pages)

Register a React route so clicking the menu does not 404.

**Today (static):** add module to `frontend/src/app/registerModules.ts`

**Future (Phase 12):** dynamic loading from plugin `frontend_routes` in `module.json`

**Backend API protection (optional):**

```php
Route::get('/items', [ItemController::class, 'index'])
    ->middleware('permission:siams-airgurd.view');
```

---

## Plugin path (alternative)

For filesystem plugins under `backend/Modules/{slug}/`:

```mermaid
flowchart LR
    JSON[module.json] --> SYNC[platform:sync]
    SYNC --> M[modules]
    SYNC --> MA[module_actions]
    SYNC --> MN[menus]
    SYNC --> P[permissions]
```

`module.json` example:

```json
{
  "slug": "example",
  "actions": ["view", "create"],
  "menus": [
    {
      "key": "example.home",
      "label": "Example",
      "icon": "bi-box",
      "route": "/example",
      "sort_order": 99
    }
  ]
}
```

Then run:

```bash
docker compose exec backend php artisan platform:sync
```

You still need **Step 5–6** (role + user assignment) unless the user already has all permissions.

---

## API reference (quick)

| Purpose | Endpoint | Used by |
|---------|----------|---------|
| Admin menu list | `GET /menus?tree=true` | Menu Builder |
| User sidebar | `GET /me/navigation` | Sidebar |
| User permissions | `GET /me/permissions` | PermissionGuard, debugging |
| Permission matrix | `GET /permissions/matrix` | Role matrix UI |
| Sync role perms | `PUT /roles/{uuid}/permissions` | Role matrix save |

**Important:** `/menus` shows all menus (admin). `/me/navigation` applies status + permission filters.

---

## Launch checklist

Copy before shipping a new module:

```
[ ] Action types created (if needed)
[ ] Module registered and enabled
[ ] Actions linked on module (at least view)
[ ] Permissions visible in role matrix
[ ] Menu item created (active, route, permission key)
[ ] Parent menu = None (or parent also accessible)
[ ] Role created with correct permissions
[ ] Role assigned to target users
[ ] /me/navigation returns the menu item
[ ] Sidebar shows link after refresh
[ ] Frontend route registered (page works)
[ ] API routes protected with permission middleware (optional)
```

---

## Troubleshooting

```mermaid
flowchart TD
    START[Sidebar missing?] --> Q1{/me/navigation has item?}
    Q1 -->|No| Q2{Menu exists in /menus?}
    Q2 -->|No| FIX1[Create menu in Menu Builder]
    Q2 -->|Yes| Q3{Menu status active?}
    Q3 -->|No| FIX2[Set status = active]
    Q3 -->|Yes| Q4{permission_key matches user role?}
    Q4 -->|No| FIX3[Fix key or assign permission]
    Q4 -->|Yes| Q5{Parent menu accessible?}
    Q5 -->|No| FIX4[Set parent = None]
    Q1 -->|Yes| FIX5[Hard refresh / clear cache]
```

| Symptom | Likely cause | Fix |
|---------|--------------|-----|
| In `/menus` but not sidebar | Wrong API checked, or cache | Check `/me/navigation`; refresh |
| Permission added, still hidden | No menu row | Create menu (Step 4) |
| Menu exists, not in navigation | `inactive` or permission mismatch | Active + matching key |
| Child menu missing | Parent filtered out | Root menu or fix parent key |
| Link shows, 404 on click | No frontend route | Step 8 |

---

## Database tables (reference)

```mermaid
erDiagram
    modules ||--o{ module_actions : defines
    actions ||--o{ module_actions : used_by
    module_actions ||--o| permissions : generates
    modules ||--o{ menus : optional
    permissions ||--o{ role_permissions : granted_via
    roles ||--o{ role_permissions : has
    roles ||--o{ user_roles : assigned
    users ||--o{ user_roles : has
    menus {
        string title
        string route
        string permission_key
        enum status
        int parent_id
    }
```

---

*Last updated: reflects Phase 5–6 platform (Module Registry, Menu Builder, Role Matrix, dynamic sidebar).*
