AI Implementation feature(841): First-Start Create Admin Modal 1.00 (#3)
This commit was merged in pull request #3.
This commit is contained in:
@@ -3,7 +3,7 @@ type: architecture
|
||||
title: Frontend Structure
|
||||
description: Angular routes, components, services, guards, and interceptors.
|
||||
tags: [architecture, frontend, angular]
|
||||
timestamp: 2026-07-21T14:43:00Z
|
||||
timestamp: 2026-07-21T15:05:00Z
|
||||
---
|
||||
|
||||
# Routes
|
||||
@@ -14,7 +14,8 @@ Routes live in `frontend/src/app/app.routes.ts`:
|
||||
|--------------|----------------------------------|---------------|----------------------------------------|
|
||||
| `/bootstrap` | `SetupCreateAdminComponent` | — | Rendered only when `initialized === false`. Non-dismissible modal overlay. |
|
||||
| `/login` | `LoginComponent` | — | Standard login form. |
|
||||
| `/` | `HomeComponent` | `authGuard` | Requires auth + initialized. |
|
||||
| `/` | `HomeComponent` (shell) | `authGuard` | Requires auth + initialized. Hosts a `<router-outlet>` for child routes. |
|
||||
| `/admin` | `AdminUsersComponent` | `adminGuard` | Child of `/`; requires `role === 'admin'`. |
|
||||
| `**` | Redirect to `/` | — | Wildcard fallback. |
|
||||
|
||||
# Components
|
||||
@@ -25,7 +26,8 @@ All components are standalone (no NgModules). Each component imports
|
||||
| Component | Path | Purpose |
|
||||
|------------------------|-----------------------------------------------------------------|-------------------------------------------------|
|
||||
| `AppComponent` | `frontend/src/app/app.component.ts` | Root; renders `<router-outlet>` and calls `BootstrapService.load()`. |
|
||||
| `HomeComponent` | `frontend/src/app/features/home/home.component.ts` | Landing page shown after auth. |
|
||||
| `HomeComponent` | `frontend/src/app/features/home/home.component.ts` | Authenticated shell with header, conditional admin nav, and `<router-outlet>` for children. |
|
||||
| `AdminUsersComponent` | `frontend/src/app/features/admin/admin-users.component.ts` | Admin-only user list rendered inside the home shell. |
|
||||
| `LoginComponent` | `frontend/src/app/features/auth/login.component.ts` | Username/password form. |
|
||||
| `SetupCreateAdminComponent` | `frontend/src/app/features/setup/setup-create-admin.component.ts` | First-admin bootstrap modal (non-dismissible, typed reactive forms). |
|
||||
|
||||
@@ -35,12 +37,15 @@ All components are standalone (no NgModules). Each component imports
|
||||
|---------------------|---------------------------------------------------------------|-----------------------------------------------------------|
|
||||
| `AuthService` | `frontend/src/app/core/services/auth.service.ts` | Signal-backed access token + current user. |
|
||||
| `BootstrapService` | `frontend/src/app/core/services/bootstrap.service.ts` | Fetches `/api/v1/bootstrap`, applies theme tokens to CSS. |
|
||||
| `AdminService` | `frontend/src/app/core/services/admin.service.ts` | `GET /api/v1/admin/users` (typed `AdminUser[]`). |
|
||||
|
||||
# Guards and interceptors
|
||||
|
||||
| Symbol | Path | Purpose |
|
||||
|---------------------|---------------------------------------------------------------|-----------------------------------------------------------|
|
||||
| `authGuard` | `frontend/src/app/core/guards/auth.guard.ts` | Redirects to `/bootstrap` when uninitialized, `/login` when not authenticated. |
|
||||
| `adminGuard` | `frontend/src/app/core/guards/admin.guard.ts` | Delegates to `decideAdminGuard` (pure). Redirects to `/bootstrap`, `/login`, or `/` based on state; allows only admins. |
|
||||
| `decideAdminGuard` | `frontend/src/app/core/guards/admin.guard.decision.ts` | Pure decision function: returns `{kind:'allow'}` or `{kind:'redirect', path}`. |
|
||||
| `authInterceptor` | `frontend/src/app/core/interceptors/auth.interceptor.ts` | Attaches `Authorization: Bearer <accessToken>` header. |
|
||||
| `csrfInterceptor` | `frontend/src/app/core/interceptors/csrf.interceptor.ts` | Attaches `X-CSRF-Token` header on POST/PUT/PATCH/DELETE. |
|
||||
|
||||
@@ -62,8 +67,23 @@ Both interceptors are wired in `frontend/src/main.ts` via
|
||||
5. The `authGuard` reads `BootstrapService.initialized()` and either
|
||||
allows navigation or redirects to `/bootstrap`.
|
||||
|
||||
# Home shell flow
|
||||
|
||||
After successful auth, `HomeComponent` renders a thin shell layout:
|
||||
|
||||
1. The header (`shell-header`) shows the page title and signed-in
|
||||
identity.
|
||||
2. When `shouldShowAdminNav({isAuthenticated, role})` returns `true`
|
||||
(see `frontend/src/app/features/home/home.shell.ts`) the admin nav
|
||||
link (`data-testid="nav-admin"`) is rendered.
|
||||
3. Child routes (e.g. `/admin` → `AdminUsersComponent`) render into the
|
||||
shell's `<router-outlet>`.
|
||||
4. `AdminUsersComponent` calls `AdminService.listUsers()` on init;
|
||||
loading, error, and the rendered list are exposed as Angular signals.
|
||||
|
||||
# See also
|
||||
|
||||
- [System Overview](/architecture/overview.md)
|
||||
- [Backend Module Map](/architecture/backend-modules.md)
|
||||
- [First-Run Bootstrap](/guides/bootstrap.md)
|
||||
- [Admin Shell & User Management](/guides/admin-shell.md)
|
||||
|
||||
Reference in New Issue
Block a user