# ERPFlow Module Development Guide

End-to-end guide for creating a business module with **nwidart/laravel-modules**, Admin UI permissions, central sidebar navigation, and frontend routes.

Related: [IMPLEMENTATION_PHASES_NWIDART.md](../IMPLEMENTATION_PHASES_NWIDART.md)

---

## Table of Contents

1. [Big Picture](#big-picture)
2. [Prerequisites](#prerequisites)
3. [Step 1 — Create nwidart Module](#step-1--create-nwidart-module)
4. [Step 2 — Backend API (Routes + Service)](#step-2--backend-api-routes--service)
5. [Step 3 — Permissions (Admin UI)](#step-3--permissions-admin-ui)
6. [Step 4 — Roles & Permission Matrix](#step-4--roles--permission-matrix)
7. [Step 5 — Central Sidebar Menu](#step-5--central-sidebar-menu)
8. [Step 6 — Frontend Routes](#step-6--frontend-routes)
9. [Step 7 — Activity Log & Approval (optional)](#step-7--activity-log--approval-optional)
10. [Permission Model](#permission-model)
11. [Checklist](#checklist)

---

## Big Picture

```
┌─────────────────────────────────────────────────────────────┐
│  nwidart Module (filesystem)                                │
│    Routes · Controllers · Services · Repositories           │
└──────────────────────────┬──────────────────────────────────┘
                           │ API (JWT + X-Company-Id)
                           ▼
┌─────────────────────────────────────────────────────────────┐
│  Platform (Admin UI + code)                                 │
│    Roles · Permissions · Approval · Activity Log            │
└──────────────────────────┬──────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│  Frontend                                                   │
│    core/config/navigation.ts  →  sidebar menu               │
│    modules/{slug}/index.tsx   →  routes only                │
│    can() + RequirePermissionRoute + PermissionGuard         │
└─────────────────────────────────────────────────────────────┘
```

| Layer | Controls | Does **not** control |
|-------|----------|----------------------|
| Admin → Modules/Roles | Permission keys | Sidebar structure |
| `navigation.ts` | Sidebar visibility | API access |
| Frontend routes | URL → React page | Sidebar items |
| Backend routes + middleware | API access | Sidebar items |

> **Do not use** `platform:sync`, ERPFlow `module.json` actions/menus, or Menu Builder for sidebar. Permissions are configured manually in Admin UI.

---

## Prerequisites

- Docker stack running (`docker compose up -d`)
- Admin login (`admin@erpflow.local` / `password`)
- API: `http://localhost:8010/api/v1`
- Frontend: `http://localhost:3000`

---

## Step 1 — Create nwidart Module

```bash
docker compose exec backend php artisan module:make HRMS
docker compose exec backend php artisan module:enable HRMS
```

This creates `backend/Modules/HRMS/` with nwidart structure:

| Path | Purpose |
|------|---------|
| `app/Http/Controllers/` | API controllers |
| `app/Providers/` | `HrmsServiceProvider`, `RouteServiceProvider` |
| `app/Services/` | Business logic |
| `routes/api.php` | Module API routes |
| `module.json` | nwidart metadata (minimal) |
| `composer.json` | PSR-4 autoload for module |

Enable/disable modules via `modules_statuses.json` or:

```bash
php artisan module:enable HRMS
php artisan module:disable HRMS
php artisan module:list
```

---

## Step 2 — Backend API (Routes + Service)

### RouteServiceProvider

Customize prefix to match ERPFlow API convention:

```php
protected function mapApiRoutes(): void
{
    Route::middleware('api')
        ->prefix('api/v1/hrms')
        ->name('api.hrms.')
        ->group(module_path($this->name, 'routes/api.php'));
}
```

### routes/api.php

```php
Route::middleware(['auth:api', 'onboarding.access', 'onboarding.document'])
    ->group(function () {
        Route::middleware('permission:hrms.view')
            ->get('/health', [HrmsController::class, 'health']);
    });
```

### Service provider bindings

```php
$this->app->bind(HrmsServiceInterface::class, HrmsService::class);
$this->app->bind(HrmsRepositoryInterface::class, HrmsRepository::class);
```

**API example:** `GET http://localhost:8010/api/v1/hrms/health`

Headers:

```http
Authorization: Bearer {token}
X-Company-Id: {company_uuid}
Accept: application/json
```

---

## Step 3 — Permissions (Admin UI)

Permission key format: `{group_slug}.{action_slug}`

**Manual setup (no `platform:sync`):**

1. **Admin → Actions** — create action slugs if needed (`view`, `create`, `employee`, …)
2. **Admin → Modules** — create module group `HRMS`, link actions
3. Permissions are auto-generated as `hrms.view`, `hrms.create`, etc.

---

## Step 4 — Roles & Permission Matrix

1. **Admin → Roles → Create** (e.g. `hr-staff`)
2. **Roles → {role} → Permissions** — assign `hrms.*` keys
3. **Admin → Users → {user} → Roles** — attach role for company

Frontend reads assigned keys via `GET /me/permissions`.

---

## Step 5 — Central Sidebar Menu

Add entries to `frontend/src/modules/core/config/navigation.ts`:

```ts
{
  id: 'hrms',
  title: 'HRMS',
  icon: 'bi-people',
  path: '#',
  permission: 'hrms.view',
  children: [
    {
      id: 'hrms-home',
      title: 'Home',
      path: '/hrms',
      permission: 'hrms.view',
    },
  ],
},
```

Sidebar is filtered by `can()` in `useNavigation.ts`. **Do not** add `navigation` to `modules/{slug}/index.tsx`.

Menu Builder (`/admin/menus`) remains for audit/reference only — not used for sidebar.

---

## Step 6 — Frontend Routes

Create `frontend/src/modules/hrms/index.tsx` (routes only):

```tsx
const moduleDefinition: AppModule = {
  id: 'hrms',
  name: 'HRMS',
  version: '1.0.0',
  routes: [
    {
      element: <ProtectedRoute />,
      children: [
        {
          element: <AppLayout />,
          children: [
            {
              element: <RequirePermissionRoute permission="hrms.view" />,
              children: [
                { path: '/hrms', element: <HrmsHomePage /> },
              ],
            },
          ],
        },
      ],
    },
  ],
};
```

Register in `frontend/src/app/registerModules.ts`.

Page-level buttons:

```tsx
<PermissionGuard permission="hrms.create">
  <button>Create</button>
</PermissionGuard>
```

---

## Step 7 — Activity Log & Approval (optional)

### Activity log (sensitive actions)

```php
$this->activityLogService->log(LogActivityData::make('employee.created', [
    'moduleId' => $moduleId,
    'actionKey' => 'hrms.create',
    'subjectType' => 'employee',
    'subjectId' => (string) $model->id,
    'properties' => ['name' => $model->name],
]));
```

### Approval (CUD only, when Admin workflow ON)

```php
return $this->approvalGateway->submit(new ApprovalSubmissionData(
    moduleSlug: 'hrms',
    actionSlug: 'create',
    companyId: $companyId,
    requesterId: $userId,
    operation: ApprovalOperation::Create,
    entityType: 'employee',
    title: 'Create employee',
    payloadAfter: $data,
    onApproved: fn () => $this->repository->create($data),
));
```

Register executor in module service provider:

```php
Platform::registerApprovalExecutor('employee', EmployeeExecutor::class);
```

---

## Permission Model

| Check | Backend | Frontend |
|-------|---------|----------|
| API route | `middleware('permission:hrms.view')` | — |
| Page route | — | `RequirePermissionRoute` |
| Sidebar | — | `navigation.ts` + `can()` |
| Button | — | `PermissionGuard` |

**Never** send permission keys in request body or headers. Only `Authorization` + `X-Company-Id`.

---

## Checklist

```
□ php artisan module:make {Name}
□ Routes + auth + onboarding + permission middleware
□ Admin → Actions (new slugs if needed)
□ Admin → Modules → link actions
□ Admin → Roles → assign permissions
□ core/config/navigation.ts → menu entry
□ frontend/src/modules/{slug}/index.tsx (routes only)
□ registerModules.ts import
□ ActivityLogService in services (sensitive actions)
□ ApprovalGateway (only if approval workflow needed)
```

---

## Reference: Configuration Module

Pilot implementation: `backend/Modules/Configuration/`

- Routes: `GET /api/v1/configuration/health`, `/employee`
- Frontend: `frontend/src/modules/configuration/`
- Navigation: `frontend/src/modules/core/config/navigation.ts`
