Skip to main content

admin-page

Adds or changes a server-rendered admin screen in DotNetForge CMS (src/DotNetForge.Web/Areas/Admin): controller deriving AdminControllerBase, attribute route under /admin, role restriction, view model, Razor view built from the Forge design system, POST + antiforgery + audit for mutations, sidebar link, and the matching .docs/pages document. Use when asked to build an admin page/screen, replace one of the module placeholders (Marketplace, Content History, Internationalization), or add an action/form to an existing admin screen.

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

المستودع
Albadit/DotNetForge
آخر نشاط في المصدر
٢٩ أكتوبر ٢٠٢٦ في ١٠:٣٢
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٠
التفرعات
٠

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

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

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

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

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
admin-page
description
Adds or changes a server-rendered admin screen in DotNetForge CMS (src/DotNetForge.Web/Areas/Admin): controller deriving AdminControllerBase, attribute route under /admin, role restriction, view model, Razor view built from the Forge design system, POST + antiforgery + audit for mutations, sidebar link, and the matching .docs/pages document. Use when asked to build an admin page/screen, replace one of the module placeholders (Marketplace, Content History, Internationalization), or add an action/form to an existing admin screen.
# Admin screen Read first: `.docs/architecture/pages.md` (pattern, layouts, conventions), `.docs/architecture/design-system.md` (components, tag helpers, behaviours) and the screen's doc in `.docs/pages/` if it exists. Model screens: `PagesController` (forms + service + audit), `ContentController` (forms generated from data, JSON for pickers), `SettingsController` (simple upsert), `UsersController` / `RolesController` (list + edit form + service with rules, `[RequirePermission]` per action). ## Steps 1. **Route and controller** - `src/DotNetForge.Web/Areas/Admin/Controllers/<Name>Controller.cs`: ```csharp [Route("admin/<slug>")] [RequirePermission(PermissionAreas.X, PermissionActions.Read)] // omit for every admin user; add another per mutating action public sealed class <Name>Controller : AdminControllerBase ``` - Never inherit from `Controller` directly - `AdminControllerBase` carries `[Area("Admin")]`, the `AdminArea` policy, `CurrentUserId` and `Can`/`CanModify`. - Replacing a placeholder: delete its action from `ModulesController` and reuse the **same route** so the sidebar link keeps working. 2. **Reads** - query `DotNetForgeDbContext` with `AsNoTracking()`, project with `Select` into a view model. Put view models in `src/DotNetForge.Web/Areas/Admin/Models/AdminViewModels.cs`. 3. **Rules** - anything beyond a trivial check goes into a `src/DotNetForge.Web/Services/<Thing>Service.cs` (scoped, registered in `src/DotNetForge.Web/Startup/DependencyRegistration.cs`) returning an error message or `Result`, like `PageService.ApplyAsync`. The controller only maps errors to `ModelState`. 4. **Mutations** - `[HttpPost("<verb>")]` + `[ValidateAntiForgeryToken]`; load the entity **by id** (else `NotFound()`); save; `await _audit.LogAsync(AuditActions.<X>, "<EntityType>", id, display)` (add a constant to `src/DotNetForge.Shared/Constants/AuditActions.cs` if needed); `TempData["Success"] = "..."`; `RedirectToAction(...)`. Inject `IAuditService`, not the concrete class. For actions governed by the permission matrix use `Can(area, action)` / `CanModify(area, any, own, createdById)` from `AdminControllerBase` and return `Forbid()` when they fail. Validate string lengths before saving. On validation failure: `ModelState.AddModelError(string.Empty, msg)` and re-render the same view with a model built by a shared private `Build...Async` helper. 5. **View** - `src/DotNetForge.Web/Areas/Admin/Views/<Name>/Index.cshtml`, built from the design system (`.docs/architecture/design-system.md#building-a-screen`; model: `Settings/Index.cshtml`, `Users/Index.cshtml`): - `ViewData["Title"]` (the only `<h1>`, tab title, last breadcrumb), optional `ViewData["Description"]`; header buttons in `@section Actions { }` (primary last). - Content in `.card`s (`.card-header` / `.card-body`). Lists: `.card[data-collection]` > `.toolbar` + `.table-wrap` > `table.table.table-stack` (`data-label` on each cell), `<empty-state>` for "nothing yet", `[data-collection-empty]` for "no match". Status: `<badge tone="Success">`; dates: `<timestamp value="@utc" />`. - Forms: `<form method="post" class="form">` + `@Html.AntiForgeryToken()`, `<form-errors />` at the top (never `asp-validation-summary` - its empty state is an inline style), `.field` > `label.field-label` + control + `span.field-hint`, buttons `.btn` + `.btn-primary` / `.btn-danger`, `.form-actions`. - Feedback: set `TempData["Success"]` / `["Error"]` and redirect - the layout shows a toast; never render flash markup. Destructive actions: `data-confirm="..."` (+ `data-confirm-title`, `data-confirm-action`) on the form - `ui.js` opens the confirm dialog. - Row/card actions: `<action-menu>` with `<menu-link>`, `<menu-post>` (antiforgery + `confirm` built in), `<menu-separator />` (`.docs/architecture/design-system.md#menus`) - never a hand-written dropdown. - **No inline `<script>`, `on*=` attributes, `style=` or `<style>`** - the Content-Security-Policy blocks them in production. New styles go into `wwwroot/css/forge/components.css` (reusable) or `admin.css` (screen layout) using tokens; behaviour as a data attribute in `ui.js` or a page script in `wwwroot/js/forge/` via `@section Scripts`. New icons go into `wwwroot/img/icons.svg`. 6. **Sidebar** - add a `NavLink("Label", "/admin/<slug>", "<icon>", typeof(<Name>Controller))` in the right section/group of `AdminNavigation.Tree` (`src/DotNetForge.Web/Areas/Admin/Navigation/AdminNavigation.cs`); when replacing a placeholder, change its controller type and drop `Planned: true`. Visibility per role (from the controller's `[Authorize]`), active state and breadcrumbs follow - hiding is never the gate. 7. **Tests** - integration test in `tests/DotNetForge.IntegrationTests`: anonymous → 302 `/login`; after `factory.InstallAsync()` + sign-in → 200 (see `.docs/guides/testing.md` for the antiforgery pattern). Add the route to `AdminUiTests.AdminScreens` (CSP, one `<h1>`, skip link). 8. **Docs** - create/update `.docs/pages/<screen>.md` using `.claude/skills/documentation/reference/screen-template.md`; update the route map in `.docs/architecture/pages.md`, the Screens table in `.docs/README.md`, `.docs/implementation-status.md` (and `.docs/pages/module-placeholders.md` when replacing a placeholder). 9. Run the **verify** skill. ## Don't - Return a view for a POST success (use PRG). - Put validation in the view or controller when a service owns the concept. - Add CSS/JS frameworks, web fonts or a client-side fetch layer; progressive enhancement only, like `src/DotNetForge.Web/wwwroot/js/forge/pages.js`. - Hard-code sidebar links or role checks in a view; use `AdminNavigation.Tree` and `AdminNavModel.Allows(href)`. - Write files to disk: runtime files go through `IFileStorage` (the deployment directory is read-only).
عرض على GitHub