auth-yes/tasks/new/2026-0924.01.gem.plan.admin.app-registry-and-admin-actions-0705.md

5.6 KiB
Raw Blame History

TASK METADATA

  • Target Files:
    • src/features/admin/apps_fragments.tsx
    • src/features/admin/admin_actions_routes.ts
    • src/features/admin/admin.test.ts
    • public/admin-scripts.js
  • Core Objective: Complete the port of the Admin Application Registry (adding the Register App drawer, Edit/Delete actions, and client handlers) and wire missing Role/Invite script handlers using the VCS/FCIS pattern.
  • Dependencies: tasks/GUIDELINES.md, AGENTS.md, agent-forum/VCS_FCIS.
  • Additional Important Notes: Keep all files strictly bounded under the 400-line ceiling (aim for the 150–250 line sweet spot). Do not introduce React or heavy client libraries.

1. Architectural Considerations & Risks

  • Risks:
    • public/admin-scripts.js currently contains vanilla imperative DOM scripts for users, sessions, and passkeys. Adding App, Role, and Invite handlers must be done cleanly with proper global scoping (globalThis.*) to avoid collisions or undeclared handler errors during runtime DOM event evaluation (onsubmit, onclick).
    • Expanding src/features/admin/apps_fragments.tsx could push it near the line limit if the drawer markup is bloated. The file is currently 158 lines, leaving ~150–200 lines of budget before approaching the 400-line ceiling.
  • Alternatives:
    • Full Datastar Hypermedia Rewrite: Replace client JS with data-on-click, data-signals, and SSE/HTML fragments. While desirable for long-term hypermedia parity, the rest of the admin slice (users, roles, invites) currently relies on public/admin-scripts.js calling JSON endpoints (/api/admin/...). Retaining this pattern for Phase 2 completion ensures uniform consistency across all admin sub-pages before any coordinated Datastar migration.

2. Proposed Implementation (VCS & FCIS / T.I.P.S.)

flowchart TD
    subgraph Slices["Vertical Feature Slices"]
        S1["🍰 Slice 1: App Registry Drawer & Action Buttons<br/>(src/features/admin/apps_fragments.tsx & public/admin-scripts.js)"]
        S2["🍰 Slice 2: Role & Invite Client Handler Consolidation<br/>(public/admin-scripts.js)"]
        S3["🍰 Slice 3: Verification & Invariant Testing<br/>(src/features/admin/admin.test.ts)"]
    end
    S1 --> S2 --> S3

🍰 Slice 1: Admin Application Registry Drawer & Actions

Objective: Restore the missing "+ Register App" button, collapsible drawer form, and Edit/Delete row/card actions in the Admin Application Registry.

T.I.P.S. Breakdown:

  • T (Types & Contracts): src/features/admin/queries.ts (Already defines ConnectedApp and createApp/updateApp parameters).
  • I (I/O Reads): Non-mutating data retrieval in adminRoutes.get('/apps') via getAdminApps().
  • P (Pure Logic / Functional Core): src/features/admin/apps_fragments.tsx:
    • Pure Hono SSR JSX rendering:
      • Header with + Register App button (onclick="openCreateAppDrawer()").
      • In-page collapsible card drawer (#appDrawer) with fields: Name, SPIFFE ID, Domain, Description, Public Bypass checkbox, Bypass Paths, and Allowed CIDRs.
      • Actions column in appsTable with Edit (onclick="openEditAppDrawer(...)") and Delete (onclick="deleteApp(...)") buttons.
      • Action buttons on mobile card deck (#appsMobileDeck).
    • Line Budget: ~158 lines \rightarrow ~230 lines (well under 400 lines).
  • S (Side Effects / Imperative Shell): public/admin-scripts.js:
    • Implement and export to globalThis:
      • openCreateAppDrawer(): resets fields, displays drawer.
      • openEditAppDrawer(appJson): populates fields, sets edit ID, makes SPIFFE ID read-only, displays drawer.
      • closeAppDrawer(): hides drawer.
      • handleSaveApp(event): reads form, dispatches POST /api/admin/apps or PUT /api/admin/apps/:id, handles response toasts via showNotice.
      • deleteApp(appId, appName): confirms action, dispatches DELETE /api/admin/apps/:id.
  • Tests: src/features/admin/admin.test.ts:
    • Assert AdminAppsPageFragment renders the + Register App button, the #appDrawer form container, and the action buttons for registered apps.

🍰 Slice 2: Role & Invite Client Handler Consolidation

Objective: Wire the orphaned client-side submission and drawer handlers for the Roles and Invites admin sub-pages into public/admin-scripts.js.

T.I.P.S. Breakdown:

  • T (Types & Contracts): Handlers consume CreateRolePayload and CreateInvitePayload.
  • I (I/O Reads): Reads form field values by DOM ID (#roleNameInput, #roleAppSelect, #createInviteAppId, etc.).
  • P (Pure Logic): Payload formatting, input trimming, and validation.
  • S (Side Effects / Imperative Shell): public/admin-scripts.js:
    • Add missing handlers:
      • openCreateRoleDrawer(), closeRoleDrawer(), handleSaveRole(event), deleteRole(id, name).
      • toggleCreateInviteForm(), handleCreateInvite(event), revokeInvite(id).
    • Export all to globalThis to prevent undefined reference errors when users click buttons on /admin/roles and /admin/invites.
  • Tests: End-to-end integration and smoke check on form dispatch routes.

🍰 Slice 3: Verification & Invariant Quality Gates

Objective: Verify that all quality gates and architectural linters pass without warnings or regressions.

Verification Commands:

  1. deno fmt --check
  2. deno task lint (including scripts/lint_arch.ts for file line ceilings and AST checks)
  3. deno task check
  4. deno test -A --no-check