# 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.) ```mermaid flowchart TD subgraph Slices["Vertical Feature Slices"] S1["🍰 Slice 1: App Registry Drawer & Action Buttons
(src/features/admin/apps_fragments.tsx & public/admin-scripts.js)"] S2["🍰 Slice 2: Role & Invite Client Handler Consolidation
(public/admin-scripts.js)"] S3["🍰 Slice 3: Verification & Invariant Testing
(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`