Files
HIPCTF2/docs/architecture/overview.md
T
2026-07-22 19:56:30 +00:00

4.6 KiB

type, title, description, tags, timestamp
type title description tags timestamp
architecture System Overview High-level layout of the HIPCTF monorepo (NestJS API + Angular SPA) and how they communicate.
architecture
backend
frontend
overview
2026-07-21T15:05:00Z

Overview

HIPCTF is delivered as a Node.js npm workspace containing two packages:

Package Path Stack
Backend backend/ NestJS 10 + TypeORM + better-sqlite3
Frontend frontend/ Angular 17 standalone components

The backend also serves the built Angular SPA as static files and falls back to index.html for client-side routes, so a single Node process hosts the whole application.

Topology

Browser  ──HTTPS──▶  NestJS process (PORT, default 3000)
                       │
                       ├── /api/v1/*  ── controllers → services → TypeORM
                       │                                 │
                       │                                 ▼
                        │                         better-sqlite3
                        │                          (DATABASE_PATH, default ./data/db.sqlite)
                       │
                       ├── /api/docs, /api/docs-json ── Swagger UI (OpenAPI 3.1)
                       │
                        ├── /uploads/*  ── static file server (UPLOAD_DIR, default ./data/uploads)
                       │
                       └── /*  ── SPA fallback (FRONTEND_DIST/index.html)

Backend entrypoint flow

backend/src/main.ts orchestrates startup in this order:

  1. Create the Nest application.
  2. Read configuration via ConfigService (validated against backend/src/config/env.schema.ts).
  3. Call DatabaseInitService.init() so migrations + WAL PRAGMA run before HTTP traffic is accepted.
  4. Register global middleware: helmet, cookieParser, JSON / URL-encoded parsers, then CsrfMiddleware (registered explicitly so it can read the parsed body).
  5. Mount /uploads static and Angular static (FRONTEND_DIST).
  6. Build the OpenAPI 3.1 document via toOpenApi31() and expose Swagger UI at /api/docs and JSON at /api/docs-json.
  7. Install SpaFallbackMiddleware so non-/api, non-/uploads, extensionless GET requests return index.html.
  8. app.listen(port).

Frontend entrypoint flow

frontend/src/main.ts bootstraps a standalone Angular app:

  1. provideHttpClient(withInterceptors([csrfInterceptor, authInterceptor])) attaches the CSRF header on unsafe methods and the Bearer access token on every request.
  2. provideRouter(APP_ROUTES, withComponentInputBinding()).
  3. AppComponent.ngOnInit() calls BootstrapService.load() then AuthService.restoreSession(). Bootstrap fetches GET /api/v1/bootstrap and applies the returned theme tokens to CSS custom properties on document.documentElement. Session restore rehydrates the in-memory auth signals from sessionStorage and posts POST /api/v1/auth/refresh with withCredentials: true so a hard refresh does not log the user out.
  4. Guards (authGuard, adminGuard) are async and await BootstrapService.ready() + AuthService.waitUntilHydrated() before reading state, so refreshing on a deep link never flashes /bootstrap or /login.

Cross-cutting concepts

Concern Backend Frontend
Authentication JwtAuthGuard (global) + AuthGuard('jwt') strategy AuthService signal + authInterceptor; session is mirrored to sessionStorage and rehydrated on boot via /api/v1/auth/refresh
Authorization AdminGuard + @Roles('admin') decorator authGuard for /, adminGuard for /admin (both async, both delegate to pure decision functions: decideAuthRedirect / decideAdminGuard)
CSRF CsrfMiddleware (skips /api/v1/auth/login and /api/v1/auth/register-first-admin) csrfInterceptor reads csrf cookie
Errors ApiErrorGlobalExceptionFilter returns {code, message, details, path, timestamp} Components display error?.error?.message
Config envSchema (zod) + validateEnv None (consumed via bootstrap)

See also