Skip to main content

add-permission

Add a new permission end-to-end — server constant + endpoint gate, and (admin app) mirror it into the permissions catalog + route guard. Use when a new endpoint needs authorization. See modules/identity.md + frontend/admin.md.

معلومات المصدر

المستودع
fullstackhero/dotnet-starter-kit
آخر نشاط في المصدر
١٣ يوليو ٢٠٢٦ في ١٣:٢٨
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٦٬٨١٣
التفرعات
٢٬٠٠٣

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
add-permission
description
Add a new permission end-to-end — server constant + endpoint gate, and (admin app) mirror it into the permissions catalog + route guard. Use when a new endpoint needs authorization. See modules/identity.md + frontend/admin.md.
argument-hint
[ModuleName] [Resource] [Action]
# Add Permission A permission spans server + the admin app. The dashboard app does **not** mirror permissions — it reads them from the JWT and relies on the server's 403. ## Step 1 — Server constant (`Modules.{X}.Contracts/Authorization/{X}Permissions.cs`) Add the constant to the resource group and ensure it's in the module's `All` collection. Convention: `Permissions.{Resource}.{Action}`. ```csharp public static class {X}Permissions { public static class {Resources} { public const string View = "Permissions.{Resources}.View"; public const string Create = "Permissions.{Resources}.Create"; // ← new } public static IReadOnlyList<FshPermission> All { get; } = [ /* … include the new one … */ ]; } ``` The module already calls `PermissionConstants.Register({X}Permissions.All)` in `ConfigureServices`, so a new entry in `All` is picked up automatically. ## Step 2 — Gate the endpoint ```csharp .RequirePermission({X}Permissions.{Resources}.Create); ``` ⚠️ `RequiredPermissionAttribute` implements `IRequiredPermissionMetadata`. **Never let a second/duplicate of that interface exist** — it silently disables **all** `.RequirePermission()` gates app-wide. (See `.agents/rules/modules/identity.md`.) ## Step 3 — (admin only) mirror it `clients/admin/src/lib/permissions.ts` — add the matching string to the frozen tree (no runtime catalog endpoint exists; mirror by hand): ```ts export const {Module}Permissions = Object.freeze({ {Resources}: { View: "Permissions.{Resources}.View", Create: "Permissions.{Resources}.Create" }, } as const); ``` If it should appear in the Role editor UI, add a `PERMISSION_CATALOG` entry (`{ name, description, root?, basic? }` under the right category group). ## Step 4 — (admin only) gate the route ```tsx { path: "{resources}/new", element: <RouteGuard perms={[{Module}Permissions.{Resources}.Create]}><Create{Resource}Page /></RouteGuard> }, ``` ## Step 5 — (admin only) seed it in tests So `RouteGuard` passes on first paint, add the new permission to the test seed set (`ADMIN_PERMS` in `clients/admin/tests/helpers/shell-mocks.ts`, used by `seedAuthedSession`). ## Dashboard No mirror, no `RouteGuard`. The JWT carries only role names — the app fetches the permission list from `GET /api/v1/identity/permissions` at hydration and the server enforces access; a missing permission yields a 403 the UI surfaces. Routes aren't permission-gated; to hide a nav entry, set `perm`/`anyPerm` on the item in `src/components/layout/nav-data.ts`. Permission-gated specs mock `GET /identity/permissions` with the grants they need (shell mocks stub it to `[]`). ## Checklist - [ ] Server constant added to `{X}Permissions` **and** its `All` collection - [ ] Endpoint gated with `.RequirePermission(...)`; no duplicate `IRequiredPermissionMetadata` - [ ] (admin) mirrored in `lib/permissions.ts` (+ `PERMISSION_CATALOG` if role-editor-visible) - [ ] (admin) route wrapped in `<RouteGuard perms={[…]}>`; permission added to `ADMIN_PERMS` test seed - [ ] Build green; admin `test:e2e` green
عرض على GitHub