4.0 KiB
4.0 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. |
|
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)
│
├── /api/docs, /api/docs-json ── Swagger UI (OpenAPI 3.1)
│
├── /uploads/* ── static file server (UPLOAD_DIR)
│
└── /* ── SPA fallback (FRONTEND_DIST/index.html)
Backend entrypoint flow
backend/src/main.ts orchestrates startup in this order:
- Create the Nest application.
- Read configuration via
ConfigService(validated againstbackend/src/config/env.schema.ts). - Call
DatabaseInitService.init()so migrations + WAL PRAGMA run before HTTP traffic is accepted. - Register global middleware:
helmet,cookieParser, JSON / URL-encoded parsers, thenCsrfMiddleware(registered explicitly so it can read the parsed body). - Mount
/uploadsstatic and Angular static (FRONTEND_DIST). - Build the OpenAPI 3.1 document via
toOpenApi31()and expose Swagger UI at/api/docsand JSON at/api/docs-json. - Install
SpaFallbackMiddlewareso non-/api, non-/uploads, extensionlessGETrequests returnindex.html. app.listen(port).
Frontend entrypoint flow
frontend/src/main.ts bootstraps a standalone Angular app:
provideHttpClient(withInterceptors([csrfInterceptor, authInterceptor]))attaches the CSRF header on unsafe methods and the Bearer access token on every request.provideRouter(APP_ROUTES, withComponentInputBinding()).AppComponent.ngOnInit()callsBootstrapService.load()which fetchesGET /api/v1/bootstrapand applies the returned theme tokens to CSS custom properties ondocument.documentElement.
Cross-cutting concepts
| Concern | Backend | Frontend |
|---|---|---|
| Authentication | JwtAuthGuard (global) + AuthGuard('jwt') strategy |
AuthService signal + authInterceptor |
| Authorization | AdminGuard + @Roles('admin') decorator |
authGuard for /, adminGuard for /admin (delegates to pure decideAdminGuard) |
| CSRF | CsrfMiddleware (skips /api/v1/auth/login and /api/v1/auth/register-first-admin) |
csrfInterceptor reads csrf cookie |
| Errors | ApiError → GlobalExceptionFilter returns {code, message, details, path, timestamp} |
Components display error?.error?.message |
| Config | envSchema (zod) + validateEnv |
None (consumed via bootstrap) |