docs: 整合與優化 Agent Skills 規範及新增技能觸發準則
This commit is contained in:
206
.agents/skills/permission-management/SKILL.md
Normal file
206
.agents/skills/permission-management/SKILL.md
Normal file
@@ -0,0 +1,206 @@
|
||||
---
|
||||
name: 權限管理與實作規範
|
||||
description: 為新功能實作權限控制的完整流程規範,包含後端 Seeder 設定、Middleware 路由保護與前端權限判斷。
|
||||
---
|
||||
|
||||
# 權限管理與實作規範
|
||||
|
||||
本文件說明如何在新增功能時,一併實作完整的權限控制機制。專案採用 `spatie/laravel-permission` 套件進行權限管理。
|
||||
|
||||
---
|
||||
|
||||
## 1. 定義權限 (Backend Seeder)
|
||||
|
||||
所有權限皆定義於 `database/seeders/PermissionSeeder.php`。
|
||||
|
||||
### 步驟:
|
||||
|
||||
1. 開啟 `database/seeders/PermissionSeeder.php`。
|
||||
2. 在 `$permissions` 關聯陣列中新增功能對應的權限。
|
||||
* **命名慣例**:`{resource}.{action}`(例如:`system.view_logs`, `products.create`)
|
||||
* **格式**:`'權限字串' => '中文動作名稱'`
|
||||
* 常用動作:`view`, `create`, `edit`, `delete`, `approve`, `cancel`, `export`
|
||||
3. 在下方「角色分配」區段,將新權限分配給適合的角色。
|
||||
|
||||
### 範例:
|
||||
|
||||
```php
|
||||
// 1. 新增權限(注意:是 key => value 格式)
|
||||
$permissions = [
|
||||
// ... 現有權限
|
||||
'utility_fees.view' => '檢視',
|
||||
'utility_fees.create' => '建立',
|
||||
'utility_fees.edit' => '編輯',
|
||||
'utility_fees.delete' => '刪除',
|
||||
];
|
||||
|
||||
// 2. 分配給角色
|
||||
$admin->givePermissionTo([
|
||||
// ... 現有權限
|
||||
'utility_fees.view', 'utility_fees.create', 'utility_fees.edit', 'utility_fees.delete',
|
||||
]);
|
||||
```
|
||||
|
||||
### 現有角色定義:
|
||||
|
||||
| 角色 | 說明 | 權限範圍 |
|
||||
|---|---|---|
|
||||
| `super-admin` | 系統管理員 | 自動擁有所有權限(`Permission::all()`) |
|
||||
| `admin` | 一般管理員 | 大部分權限(除角色管理外) |
|
||||
| `warehouse-manager` | 倉庫管理員 | 庫存、盤點、調撥、進貨、門市叫貨 |
|
||||
| `purchaser` | 採購人員 | 商品檢視、採購單、退貨、供應商、進貨 |
|
||||
| `viewer` | 檢視人員 | 僅限各模組的 `.view` 權限 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 套用資料庫變更 (Multi-tenancy)
|
||||
|
||||
修改 Seeder 後,必須在**中央與所有租戶**同步執行。
|
||||
|
||||
```bash
|
||||
# 對所有租戶執行 Seeder
|
||||
./vendor/bin/sail php artisan tenants:seed --class=PermissionSeeder
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> 僅執行 `db:seed` 只會更新中央資料庫。務必使用 `tenants:seed` 確保所有租戶同步。
|
||||
|
||||
---
|
||||
|
||||
## 3. 路由保護 (Backend Middleware)
|
||||
|
||||
路由保護定義在各模組自己的 `app/Modules/{ModuleName}/Routes/web.php` 中。
|
||||
|
||||
> [!IMPORTANT]
|
||||
> 路由檔在各模組內(如 `app/Modules/Finance/Routes/web.php`),**不是**全域的 `routes/web.php`。
|
||||
|
||||
### 範例:
|
||||
|
||||
```php
|
||||
// 單一權限保護
|
||||
Route::middleware('permission:utility_fees.view')->group(function () {
|
||||
Route::get('/utility-fees', [UtilityFeeController::class, 'index'])->name('utility-fees.index');
|
||||
Route::get('/utility-fees/{utilityFee}', [UtilityFeeController::class, 'show'])->name('utility-fees.show');
|
||||
});
|
||||
|
||||
// 巢狀權限群組
|
||||
Route::middleware('permission:utility_fees.create')->group(function () {
|
||||
Route::get('/utility-fees/create', [UtilityFeeController::class, 'create'])->name('utility-fees.create');
|
||||
Route::post('/utility-fees', [UtilityFeeController::class, 'store'])->name('utility-fees.store');
|
||||
});
|
||||
|
||||
// 單行 middleware
|
||||
Route::delete('/utility-fees/{utilityFee}', [UtilityFeeController::class, 'destroy'])
|
||||
->middleware('permission:utility_fees.delete')
|
||||
->name('utility-fees.destroy');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 配置權限群組名稱 (Backend UI Config)
|
||||
|
||||
為了讓新權限在「角色與權限」管理介面中正確分組並顯示中文標題,需修改 Controller。
|
||||
|
||||
**位置**: `app/Modules/Core/Controllers/RoleController.php` → `getGroupedPermissions()`
|
||||
|
||||
```php
|
||||
$groupDefinitions = [
|
||||
'products' => '商品資料管理',
|
||||
'warehouses' => '倉庫管理',
|
||||
'inventory' => '庫存資料管理',
|
||||
// ...
|
||||
'utility_fees' => '公共事業費管理', // ✅ 新增此行
|
||||
];
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> 未加入 `$groupDefinitions` 的權限群組仍會顯示,但標題會以原始 key(英文)呈現。
|
||||
|
||||
---
|
||||
|
||||
## 5. 前端權限判斷 (React)
|
||||
|
||||
### 5.1 方式一:`usePermission` Hook(在邏輯中判斷)
|
||||
|
||||
**位置**: `resources/js/hooks/usePermission.ts`
|
||||
|
||||
```tsx
|
||||
import { usePermission } from "@/hooks/usePermission";
|
||||
|
||||
export default function ProductIndex() {
|
||||
const { can, canAny, isSuperAdmin } = usePermission();
|
||||
|
||||
return (
|
||||
<div>
|
||||
{can('products.create') && <Button>新增商品</Button>}
|
||||
{canAny(['products.edit', 'products.delete']) && <ManageDropdown />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### Hook 完整介面:
|
||||
|
||||
| 方法 | 說明 |
|
||||
|---|---|
|
||||
| `can(permission)` | 檢查是否擁有**指定**權限 |
|
||||
| `canAny(permissions[])` | 檢查是否擁有**任一**權限 |
|
||||
| `canAll(permissions[])` | 檢查是否擁有**所有**權限 |
|
||||
| `hasRole(role)` | 檢查是否擁有**指定**角色 |
|
||||
| `hasAnyRole(roles[])` | 檢查是否擁有**任一**角色 |
|
||||
| `hasAllRoles(roles[])` | 檢查是否擁有**所有**角色 |
|
||||
| `isSuperAdmin()` | 是否為超級管理員 |
|
||||
|
||||
> 所有方法對 `super-admin` 角色自動回傳 `true`。
|
||||
|
||||
### 5.2 方式二:`<Can>` / `<HasRole>` / `<CanAll>` 元件(在 JSX 中包裹)
|
||||
|
||||
**位置**: `resources/js/Components/Permission/Can.tsx`
|
||||
|
||||
```tsx
|
||||
import { Can, HasRole, CanAll } from '@/Components/Permission/Can';
|
||||
|
||||
// 單一權限
|
||||
<Can permission="products.create">
|
||||
<Button>新增商品</Button>
|
||||
</Can>
|
||||
|
||||
// 任一權限(OR 邏輯)
|
||||
<Can permission={['products.edit', 'products.delete']}>
|
||||
<ManageDropdown />
|
||||
</Can>
|
||||
|
||||
// 所有權限都必須有(AND 邏輯)
|
||||
<CanAll permissions={['products.edit', 'products.delete']}>
|
||||
<Button>完整管理</Button>
|
||||
</CanAll>
|
||||
|
||||
// 角色判斷
|
||||
<HasRole role="admin">
|
||||
<Link href="/admin">管理後台</Link>
|
||||
</HasRole>
|
||||
|
||||
// Fallback 支援
|
||||
<Can permission="products.delete" fallback={<span className="text-gray-400">無權限</span>}>
|
||||
<Button variant="destructive">刪除</Button>
|
||||
</Can>
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> UI 規範要求:所有可操作按鈕(新增、編輯、刪除)**必須**包裹 `<Can>` 元件或使用 `can()` 判斷。
|
||||
> 詳見 [UI 統一規範](file:///home/mama/projects/star-erp/.agents/skills/ui-consistency/SKILL.md)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 開發檢核清單 (Checklist)
|
||||
|
||||
### 後端
|
||||
- [ ] `PermissionSeeder.php` 已新增權限字串(`'key' => '中文動作名稱'` 格式)。
|
||||
- [ ] `PermissionSeeder.php` 已將新權限分配給 `admin` 及其他適用角色。
|
||||
- [ ] 已執行 `./vendor/bin/sail php artisan tenants:seed --class=PermissionSeeder` 同步所有租戶。
|
||||
- [ ] `RoleController.php` 的 `$groupDefinitions` 已新增權限群組中文名稱。
|
||||
- [ ] 模組路由 (`app/Modules/{ModuleName}/Routes/web.php`) 已加上 `middleware('permission:...')` 保護。
|
||||
|
||||
### 前端
|
||||
- [ ] 頁面按鈕已使用 `usePermission` Hook 或 `<Can>` 元件進行權限控制。
|
||||
- [ ] 所有可操作按鈕都包裹於權限判斷中(符合 UI 統一規範)。
|
||||
Reference in New Issue
Block a user