# 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`