# NGBVD Permission Enforcement Patch

This patch closes the two permission gaps raised during backend stabilization:

1. Navigation items now evaluate assigned role permissions before being displayed.
2. Direct URL access is blocked by middleware, even when a user pastes a protected URL manually.

## Main files

- `app/Http/Middleware/EnforceNgbvdRoutePermissions.php`
- `app/Http/Middleware/CheckNgbvdPermission.php`
- `app/Services/AccessControl/DataScopeService.php`
- `app/Services/AccessControl/PermissionRegistry.php`
- `app/Models/User.php`
- `app/Http/Kernel.php`
- `config/ngbvd_permissions.php`
- `resources/views/layouts/navigation.blade.php`

## How it works

### Functional permissions

The middleware checks URL patterns against `config/ngbvd_permissions.route_permissions`.

Example:

```php
'dataentry/list*' => ['profiled_cases.view'],
'roles/*' => ['roles.configure'],
'integrations/api-clients*' => ['api_integrations.manage_clients'],
```

If the user lacks the required permission, the request is denied with 403 or redirected to `/error/access`.

### Navigation permissions

The sidebar uses the same permission keys. If a role does not have permission, the menu item is hidden.

### Record-level scope

For case routes such as:

```text
dataentry/update*
dataentry/report*
```

The middleware also checks whether the signed-in user can access the referenced case record based on:

- national scope
- assigned district
- assigned partner organisation
- own-record access

### Administrator bypass

The following remain full-access administrators to avoid lockout:

- `admin@mglsd.go.ug`
- `administrator@mglsd.go.ug`
- username `admin`
- username `administrator`
- `userrole = 1`

## After applying

Run:

```powershell
composer dump-autoload
php artisan optimize:clear
php artisan config:clear
php artisan route:clear
php artisan view:clear
php artisan cache:clear
```

## Test

1. Assign a role only `dashboard.view` and `profiled_cases.view`.
2. Login as a user with that role.
3. Confirm hidden menus are not visible.
4. Paste `/roles/list` directly. It should block access.
5. Paste `/integrations/api-clients` directly. It should block access.
6. Test `/dataentry/update?id=<case_id>` for a case outside the user's district/partner. It should block access.
