# Role & Permission Management Guide

## Overview
Sistem ini menggunakan **Spatie Laravel Permission** untuk mengelola roles dan permissions. User model sudah dilengkapi dengan trait `HasRoles` untuk mendukung role-based access control.

## Structure

### Role
Setiap role memiliki:
- `id`: Primary key
- `name`: Nama role (unique)
- `guard_name`: Guard type (default: 'web')
- `permissions`: Many-to-many relationship dengan permissions

### Permission
Setiap permission memiliki:
- `id`: Primary key
- `name`: Nama permission (unique)
- `guard_name`: Guard type (default: 'web')

### User
User dapat memiliki:
- Multiple roles
- Multiple permissions (direct assignment)

## API Endpoints

### 1. List All Roles
**GET** `/api/roles`

**Query Parameters:**
- `per_page` (optional): Items per page (default: 10)
- `search` (optional): Search by role name

**Response:**
```json
{
  "status": true,
  "message": "Roles fetched successfully",
  "data": {
    "current_page": 1,
    "data": [
      {
        "id": 1,
        "name": "Admin",
        "guard_name": "web",
        "permissions": [
          {
            "id": 1,
            "name": "view-users",
            "guard_name": "web"
          }
        ]
      }
    ],
    "total": 3
  }
}
```

### 2. Create Role
**POST** `/api/roles`

**Request Body:**
```json
{
  "name": "Manager",
  "guard_name": "web",
  "permissions": [1, 2, 3]
}
```

**Validation:**
- `name`: required, string, max:255, unique
- `guard_name`: optional, string, max:255 (default: 'web')
- `permissions`: optional, array of permission IDs

**Response:**
```json
{
  "status": true,
  "message": "Role created successfully",
  "data": {
    "id": 2,
    "name": "Manager",
    "guard_name": "web",
    "permissions": [...]
  }
}
```

### 3. Get Single Role
**GET** `/api/roles/{id}`

**Response:**
```json
{
  "status": true,
  "message": "Role fetched successfully",
  "data": {
    "id": 1,
    "name": "Admin",
    "guard_name": "web",
    "permissions": [...]
  }
}
```

### 4. Update Role
**PUT** `/api/roles/{id}`

**Request Body:**
```json
{
  "name": "Super Admin",
  "permissions": [1, 2, 3, 4]
}
```

**Validation:**
- `name`: optional, string, max:255, unique (except current role)
- `guard_name`: optional, string, max:255
- `permissions`: optional, array of permission IDs

**Response:**
```json
{
  "status": true,
  "message": "Role updated successfully",
  "data": {
    "id": 1,
    "name": "Super Admin",
    "permissions": [...]
  }
}
```

### 5. Delete Role
**DELETE** `/api/roles/{id}`

**Note:** Cannot delete role yang masih assigned ke users

**Response:**
```json
{
  "status": true,
  "message": "Role deleted successfully",
  "data": null
}
```

**Error Response (if assigned to users):**
```json
{
  "status": false,
  "message": "Cannot delete role that is assigned to 5 user(s)"
}
```

### 6. Get All Permissions
**GET** `/api/permissions`

**Response:**
```json
{
  "status": true,
  "message": "Permissions fetched successfully",
  "data": [
    {
      "id": 1,
      "name": "view-users",
      "guard_name": "web"
    },
    {
      "id": 2,
      "name": "create-users",
      "guard_name": "web"
    }
  ]
}
```

### 7. Assign Permissions to Role
**POST** `/api/roles/{id}/permissions`

**Request Body:**
```json
{
  "permissions": [1, 2, 3, 4, 5]
}
```

**Validation:**
- `permissions`: required, array of permission IDs

**Response:**
```json
{
  "status": true,
  "message": "Permissions assigned successfully",
  "data": {
    "id": 1,
    "name": "Admin",
    "permissions": [...]
  }
}
```

### 8. Remove Permission from Role
**DELETE** `/api/roles/{id}/permissions`

**Request Body:**
```json
{
  "permission_id": 3
}
```

**Validation:**
- `permission_id`: required, exists in permissions table

**Response:**
```json
{
  "status": true,
  "message": "Permission removed successfully",
  "data": {
    "id": 1,
    "name": "Admin",
    "permissions": [...]
  }
}
```

## Usage in Code

### Check if User has Role
```php
// Single role
if ($user->hasRole('Admin')) {
    // User is admin
}

// Multiple roles (OR)
if ($user->hasAnyRole(['Admin', 'Manager'])) {
    // User has at least one of the roles
}

// Multiple roles (AND)
if ($user->hasAllRoles(['Admin', 'Super Admin'])) {
    // User has all roles
}
```

### Check if User has Permission
```php
// Single permission
if ($user->hasPermissionTo('create-users')) {
    // User can create users
}

// Multiple permissions
if ($user->hasAnyPermission(['create-users', 'edit-users'])) {
    // User has at least one permission
}
```

### Assign Role to User
```php
// Assign single role
$user->assignRole('Admin');

// Assign multiple roles
$user->assignRole(['Admin', 'Manager']);

// Sync roles (remove all existing, add new)
$user->syncRoles(['Admin']);
```

### Assign Permission Directly to User
```php
// Give permission
$user->givePermissionTo('create-users');

// Revoke permission
$user->revokePermissionTo('create-users');

// Sync permissions
$user->syncPermissions(['create-users', 'edit-users']);
```

### Get User's Roles and Permissions
```php
// Get all roles
$roles = $user->roles;

// Get all permissions (including from roles)
$permissions = $user->getAllPermissions();

// Get direct permissions only
$directPermissions = $user->permissions;
```

## Middleware Usage

### Protect Routes by Role
```php
Route::middleware(['role:Admin'])->group(function () {
    // Only Admin can access
});

// Multiple roles (OR)
Route::middleware(['role:Admin|Manager'])->group(function () {
    // Admin or Manager can access
});
```

### Protect Routes by Permission
```php
Route::middleware(['permission:create-users'])->group(function () {
    // Only users with 'create-users' permission
});

// Multiple permissions (OR)
Route::middleware(['permission:create-users|edit-users'])->group(function () {
    // Users with create-users OR edit-users permission
});
```

### Combined (Role AND Permission)
```php
Route::middleware(['role:Admin', 'permission:create-users'])->group(function () {
    // Must be Admin AND have create-users permission
});
```

## Blade Directives (if using Blade)

```blade
@role('Admin')
    <!-- Only visible to Admin -->
@endrole

@hasrole('Admin|Manager')
    <!-- Visible to Admin or Manager -->
@endhasrole

@can('create-users')
    <!-- Only visible to users with create-users permission -->
@endcan
```

## Common Permissions Examples

Here are some common permissions you might want to create:

**User Management:**
- `view-users`
- `create-users`
- `edit-users`
- `delete-users`

**Employee Management:**
- `view-employees`
- `create-employees`
- `edit-employees`
- `delete-employees`

**Attendance Management:**
- `view-attendance`
- `create-attendance`
- `edit-attendance`
- `delete-attendance`
- `bypass-attendance`

**Role Management:**
- `view-roles`
- `create-roles`
- `edit-roles`
- `delete-roles`
- `assign-permissions`

**Company Management:**
- `view-companies`
- `create-companies`
- `edit-companies`
- `delete-companies`

**Department Management:**
- `view-departments`
- `create-departments`
- `edit-departments`
- `delete-departments`

## Creating Permissions via Tinker

```bash
php artisan tinker
```

```php
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

// Create permissions
Permission::create(['name' => 'view-users']);
Permission::create(['name' => 'create-users']);
Permission::create(['name' => 'edit-users']);
Permission::create(['name' => 'delete-users']);

// Create role
$adminRole = Role::create(['name' => 'Admin']);

// Assign permissions to role
$adminRole->givePermissionTo(['view-users', 'create-users', 'edit-users', 'delete-users']);

// Assign role to user
$user = User::find(1);
$user->assignRole('Admin');
```

## Seeding Roles and Permissions

Create a seeder:
```bash
php artisan make:seeder RolePermissionSeeder
```

```php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

class RolePermissionSeeder extends Seeder
{
    public function run()
    {
        // Reset cached roles and permissions
        app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

        // Create permissions
        $permissions = [
            'view-users',
            'create-users',
            'edit-users',
            'delete-users',
            'view-employees',
            'create-employees',
            'edit-employees',
            'delete-employees',
            'view-attendance',
            'bypass-attendance',
        ];

        foreach ($permissions as $permission) {
            Permission::create(['name' => $permission]);
        }

        // Create roles and assign permissions
        $adminRole = Role::create(['name' => 'Admin']);
        $adminRole->givePermissionTo(Permission::all());

        $staffRole = Role::create(['name' => 'Staff']);
        $staffRole->givePermissionTo([
            'view-employees',
            'view-attendance',
        ]);

        $employeeRole = Role::create(['name' => 'Employee']);
        $employeeRole->givePermissionTo([
            'view-attendance',
        ]);
    }
}
```

Run seeder:
```bash
php artisan db:seed --class=RolePermissionSeeder
```

## Migration with id_role

Since you already have `id_role` field in users table, you can use it alongside Spatie roles:

1. Keep `id_role` for simple role identification (1=Admin, 2=Staff, 3=Employee)
2. Use Spatie roles for advanced permission management

**Best Practice:**
- Use `id_role` for basic role checks (quick queries)
- Use Spatie roles/permissions for detailed access control

```php
// Quick check with id_role
if ($user->id_role == 1) {
    // Admin
}

// Detailed check with Spatie
if ($user->hasPermissionTo('create-users')) {
    // Has specific permission
}
```

## Testing

Test the endpoints using curl or Postman:

```bash
# Get all roles
curl -X GET http://localhost:8000/api/roles \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

# Create role
curl -X POST http://localhost:8000/api/roles \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Manager","permissions":[1,2,3]}'

# Assign permissions
curl -X POST http://localhost:8000/api/roles/1/permissions \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"permissions":[1,2,3,4]}'
```

## Notes

1. **Guard Name**: Default adalah 'web', tapi bisa disesuaikan (misal: 'api')
2. **Caching**: Spatie cache permissions, jika ada perubahan run:
   ```bash
   php artisan cache:forget spatie.permission.cache
   ```
3. **Role vs Permission**:
   - Role = kumpulan permissions (Admin, Manager, etc.)
   - Permission = aksi spesifik (create-users, edit-posts, etc.)
4. **Direct Permission**: User bisa punya permission langsung tanpa role

## Troubleshooting

### Table not found error
Run migration yang sudah ada:
```bash
php artisan migrate
```

### Permission denied error
Make sure user has correct role/permission:
```php
$user->assignRole('Admin');
// or
$user->givePermissionTo('create-users');
```

### Cache issues
Clear permission cache:
```bash
php artisan cache:forget spatie.permission.cache
# or
php artisan permission:cache-reset
```
