---
name: 權限管理與實作規範
description: 為新功能實作權限控制的完整流程規範，包含後端 Seeder 設定、Middleware 路由保護與前端權限判斷。
---

# 權限管理與實作規範

本文件說明如何在新增功能時，一併實作完整的權限控制機制。專案採用 `spatie/laravel-permission` 套件進行權限管理。

## 1. 定義權限 (Backend)

所有權限皆定義於 `database/seeders/PermissionSeeder.php`。

### 步驟：

1.  開啟 `database/seeders/PermissionSeeder.php`。
2.  在 `$permissions` 陣列中新增功能對應的權限字串。
    *   **命名慣例**：`{resource}.{action}` (例如：`system.view_logs`, `products.create`)
    *   常用動作：`view`, `create`, `edit`, `delete`, `publish`, `export`
3.  在下方「角色分配」區段，將新權限分配給適合的角色。
    *   `super-admin`：通常擁有所有權限（程式碼中 `Permission::all()` 自動涵蓋，無需手動新增）。
    *   `admin`：通常擁有大部分權限。
    *   其他角色 (`warehouse-manager`, `purchaser`, `viewer`)：依業務邏輯分配。

### 範例：

```php
// 1. 新增權限字串
$permissions = [
    // ... 現有權限
    'system.view_logs', // 新增：檢視系統日誌
];

// ...

// 2. 分配給角色
$admin->givePermissionTo([
    // ... 現有權限
    'system.view_logs',
]);
```

## 2. 套用資料庫變更

修改 Seeder 後，必須重新執行 Seeder 以將權限寫入資料庫。

```bash
# 對於所有租戶執行 Seeder (開發環境)
php artisan tenants:seed --class=PermissionSeeder
```

## 3. 路由保護 (Backend Middleware)

在 `routes/web.php` 中，使用 `permission:{name}` middleware 保護路由。

### 範例：

```php
// 單一權限保護
Route::get('/logs', [LogController::class, 'index'])
    ->middleware('permission:system.view_logs')
    ->name('logs.index');

// 路由群組保護
Route::middleware('permission:products.view')->group(function () {
    // ...
});

// 多重權限 (OR 邏輯：有其一即可)
Route::middleware('permission:products.create|products.edit')->group(function () {
    // ...
});
```

## 4. 前端權限判斷 (React Component)

使用自訂 Hook `usePermission` 來控制 UI 元素的顯示（例如：隱藏沒有權限的按鈕）。

### 引入 Hook：

```tsx
import { usePermission } from "@/hooks/usePermission";
```

### 使用方式：

```tsx
export default function ProductIndex() {
    const { can } = usePermission();

    return (
        <div>
            <h1>商品列表</h1>
            
            {/* 只有擁有 create 權限才顯示按鈕 */}
            {can('products.create') && (
                <Button>新增商品</Button>
            )}

            {/* 組合判斷 */}
            {can('products.edit') && <EditButton />}
        </div>
    );
}
```

### 權限 Hook 介面說明：

- `can(permission: string)`: 檢查當前使用者是否擁有指定權限。
- `canAny(permissions: string[])`: 檢查當前使用者是否擁有陣列中**任一**權限。
- `hasRole(role: string)`: 檢查當前使用者是否擁有指定角色。

## 5. 配置權限群組名稱 (Backend UI Config)

為了讓新權限在「角色與權限」管理介面中顯示正確的中文分組標題，需修改 Controller 設定。

### 步驟：

1.  開啟 `app/Http/Controllers/Admin/RoleController.php`。
2.  找到 `getGroupedPermissions` 方法。
3.  在 `$groupDefinitions` 陣列中，新增 `{resource}` 對應的中文名稱。

### 範例：

```php
$groupDefinitions = [
    'products' => '商品資料管理',
    // ...
    'utility_fees' => '公共事業費管理', // 新增此行
];
```

## 檢核清單

- [ ] `PermissionSeeder.php` 已新增權限字串。
- [ ] `PermissionSeeder.php` 已將新權限分配給對應角色。
- [ ] 已執行 `php artisan tenants:seed --class=PermissionSeeder` 更新資料庫。
- [ ] `RoleController.php` 已新增權限群組的中文名稱映射。
- [ ] 後端路由 (`routes/web.php`) 已加上 middleware 保護。
- [ ] 前端頁面/按鈕已使用 `usePermission` 進行顯示控制。
