Tighten §5 admin comments + README (todo §5 cleanup); compress the three near-identical admin module headers (drop restatement the README/code already carry), shorten the README Layout views/ run-on + add the missing delete-confirm view. Also bank a pre-existing AGENTS.md tweak: skip the stability-reviewer for purely doc/comment changes. Docs/comments-only — typecheck + 244 units green.

This commit is contained in:
2026-06-18 19:25:02 +02:00
parent c78e95889c
commit 0a5eafd2f8
6 changed files with 24 additions and 26 deletions

View File

@@ -1,11 +1,10 @@
// Built-in Groups admin screen (todo §5): list / create / delete Keto groups and manage their
// membership. A group is a Keto subject set `Group:<name>#members`; a membership tuple's subject is
// a user (`subject_id = user:<id>`) or a nested group (`subject_set = Group:<other>#members`). Writes
// go only to Keto (README "stateless"); there is no group store. Keto has no "create object" — a
// group exists exactly while it has ≥1 member, so creating one writes its first-member tuple and
// deleting one removes every member tuple. The pure builders turn tuples + the request URL into the
// building-block view models; `handleAdminGroups` is the imperative shell app.ts dispatches to — it
// gates (admin only), CSRF-guards every mutation, and maps each action to a RouteResult.
// Built-in Groups admin screen (todo §5): list / create / delete Keto groups and manage membership.
// A group is a Keto subject set `Group:<name>#members`; a member is a user or a nested group (see
// parseSubject). Writes go only to Keto (README "stateless"). Keto has no "create object" — a group
// exists exactly while it has ≥1 member, so create writes its first-member tuple and delete removes
// every member tuple. Pure builders turn tuples + the request URL into view models; `handleAdminGroups`
// is the imperative shell app.ts dispatches to — gated admin-only, CSRF-guarded, mapping each action
// to a RouteResult.
import { ADMIN_GROUPS_BASE, adminNav, buildConfirmModel, guardedForm, requireAdmin } from "./admin-nav.ts";
import type { FieldConfig } from "./admin-users.ts";

View File

@@ -1,13 +1,12 @@
// Built-in Roles & permissions admin screen (todo §5): list / create / delete Keto roles and assign
// them to users and groups. A role is a Keto subject set `Role:<name>#members` (OPL: members are
// users or groups, resolved transitively) — the source of truth for the JWT `roles` claim. It shares
// the user|group membership model of the Groups screen, so the pure helpers (parseSubject, member
// pickers, tuple paging) are reused from admin-groups. The one role-specific piece is the **effective
// access** view: `keto.expand(Role:<name>#members)` returns the membership tree, which we flatten to
// the distinct set of users who hold the role directly or transitively via a group. Login resolves
// the same transitive membership into the JWT `roles` (login.ts readRoles), so this view matches what
// a user's token actually grants. Writes go only to Keto; Kratos is read only to label members.
// `handleAdminRoles` is the imperative shell app.ts dispatches to — gated admin-only, CSRF-guarded.
// them to users and groups. A role is a Keto subject set `Role:<name>#members` (OPL: members are users
// or groups, resolved transitively) — the source of truth for the JWT `roles` claim. It shares the
// Groups screen's membership model, so the pure helpers (parseSubject, member pickers, tuple paging)
// are reused from admin-groups. The role-specific piece is the **effective access** view:
// `keto.expand(Role:<name>#members)` flattened to the distinct users who hold the role directly or via
// a group — matching what login projects into the JWT (login.ts readRoles). Writes go only to Keto;
// Kratos is read only to label members. `handleAdminRoles` is the imperative shell app.ts dispatches
// to — gated admin-only, CSRF-guarded.
import { ADMIN_PERMISSION, ADMIN_ROLES_BASE, adminNav, buildConfirmModel, guardedForm, requireAdmin } from "./admin-nav.ts";
import {

View File

@@ -1,9 +1,8 @@
// Built-in Users admin screen (todo §5): list Kratos identities (filter/sort/paginate) and
// create / edit / deactivate / delete / trigger-recovery them. Writes go only to Kratos via the
// admin client (README "stateless"); the app holds no user store. The pure builders here turn
// identities + the request URL into the building-block view models; `handleAdminUsers` is the
// imperative shell app.ts dispatches to — it gates (admin only), CSRF-guards every mutation, and
// maps each action to a RouteResult (render a page, or redirect after a write — PRG).
// Built-in Users admin screen (todo §5): list Kratos identities (filter/sort/paginate) +
// create/edit/deactivate/delete/trigger-recovery. Writes go only to Kratos via the admin client
// (README "stateless"). Pure builders turn identities + the request URL into building-block view
// models; `handleAdminUsers` is the imperative shell app.ts dispatches to — gated admin-only,
// CSRF-guarded, each action mapped to a RouteResult (render, or redirect after a write — PRG).
import { ADMIN_USERS_BASE, adminNav, buildConfirmModel, guardedForm, requireAdmin } from "./admin-nav.ts";
import type { RequestContext, User } from "./context.ts";