Files
HIPCTF2/docs/architecture/frontend-structure.md
T

5.8 KiB

type, title, description, tags, timestamp
type title description tags timestamp
architecture Frontend Structure Angular routes, components, services, guards, and interceptors.
architecture
frontend
angular
2026-07-21T15:05:00Z

Routes

Routes live in frontend/src/app/app.routes.ts:

Path Component Guard Notes
/bootstrap SetupCreateAdminComponent Rendered only when initialized === false. Non-dismissible modal overlay.
/login LoginComponent Standard login form.
/ 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

All components are standalone (no NgModules). Each component imports FormsModule directly and uses Angular signals for state.

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 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).

Services

Service Path Purpose
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.

Both interceptors are wired in frontend/src/main.ts via provideHttpClient(withInterceptors([csrfInterceptor, authInterceptor])) (notably CSRF runs first so the token is attached before the auth header).

Bootstrap flow

  1. AppComponent.ngOnInit()BootstrapService.load().
  2. BootstrapService calls GET /api/v1/bootstrap (public, with credentials: 'include').
  3. The payload sets initialized (true iff any admin user exists), pageTitle, logo, welcomeMarkdown, the active theme, and the default challenge IP.
  4. Theme tokens are written to CSS custom properties on document.documentElement (--color-primary, --font-family, --radius-*, etc.) consumed by frontend/src/styles.css.
  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. /adminAdminUsersComponent) 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