Files

12 KiB

type, title, description, tags, timestamp
type title description tags timestamp
architecture Backend Module Map NestJS modules, controllers, services, and how they are wired together.
architecture
backend
nestjs
modules
2026-07-23T16:10:00Z

Module Map

All modules are imported in backend/src/app.module.ts. The root module also registers two global providers:

Global provider Purpose
APP_GUARD = JwtAuthGuard Enforces JWT auth unless the handler is @Public()
APP_FILTER = GlobalExceptionFilter Normalizes errors into the standard envelope

Modules

Module Path Responsibility
DatabaseModule backend/src/database/database.module.ts Configures TypeORM with better-sqlite3, registers entities, runs migrations, enforces WAL, and imports FilesystemTransactionModule so startup recovery runs before the database is opened.
FilesystemTransactionModule backend/src/modules/admin/system/filesystem-transaction.module.ts Provides the shared durable filesystem swap service to both DatabaseModule startup recovery and AdminSystemModule restore operations without a circular dependency.
CommonModule backend/src/common/common.module.ts Provides shared services (CSRF middleware class, backoff, registration rate limit, SSE hub, theme loader, etc.).
SettingsModule backend/src/modules/settings/settings.module.ts Exposes SettingsService (get/set/getAll over setting table).
AuthModule backend/src/modules/auth/auth.module.ts AuthController (/api/v1/auth/{register,login,refresh,logout,me,change-password,csrf}) + AuthService (login/refresh/logout/register-first-admin + public register + getMe + changePassword). Imports SettingsModule so the public-register flow can read the registrationsEnabled flag, and UsersModule (forwardRef) for UsersRankService.
UsersModule backend/src/modules/users/users.module.ts UsersController (/api/v1/auth/register-first-admin) + UsersService (last-admin invariant) + UsersRankService (rankOfUser(manager, userId) -> {rank, points} over the solve table).
SetupModule backend/src/modules/setup/setup.module.ts SetupController (POST /api/v1/setup/create-admin) + SetupService. Returns 409 SYSTEM_INITIALIZED once any admin exists; serializes concurrent first-admin attempts via an in-process promise chain.
SystemModule backend/src/modules/system/system.module.ts SystemController (/api/v1/bootstrap, /event/status, SSE streams) + SystemService.
AdminModule backend/src/modules/admin/admin.module.ts Five controllers (AdminController for /api/v1/admin/users*, AdminGeneralController for /api/v1/admin/general/*, AdminCategoriesController for /api/v1/admin/categories*, AdminChallengesController for /api/v1/admin/challenges*, AdminSystemController for /api/v1/admin/system/*) plus their services (AdminService, AdminGeneralService, AdminCategoriesService, AdminChallengesService, ChallengeFilesService, BackupService, RestoreService, DangerZoneService, FilesystemTransactionService, ConfirmationTokenService). Gated by AdminGuard + @Roles('admin'). Imports TypeOrmModule.forFeature([UserEntity, CategoryEntity, ChallengeEntity, ChallengeFileEntity, SolveEntity]), AuthModule, UsersModule, SettingsModule, CommonModule (for SseHubService, ThemeLoaderService), and AdminSystemModule (which adds AdminOperationTokenEntity + AuthModule).
AdminSystemModule backend/src/modules/admin/system/admin-system.module.ts Hosts the destructive System operations: AdminSystemController + BackupService + RestoreService + DangerZoneService + ConfirmationTokenService. Imports shared FilesystemTransactionModule, TypeOrmModule.forFeature([AdminOperationTokenEntity]), and AuthModule (for reauthenticateAdmin/revokeAllRefreshSessions).
UploadsModule backend/src/modules/uploads/uploads.module.ts UploadsController (/api/v1/uploads/*). Admin-only multipart.
BlogModule backend/src/modules/blog/blog.module.ts BlogController/BlogService expose published posts at GET /api/v1/blog/posts; AdminBlogController/AdminBlogService provide guarded CRUD at /api/v1/admin/blog/posts using BlogPostEntity.
ChallengesModule backend/src/modules/challenges/challenges.module.ts ChallengesController (/api/v1/challenges/{board,status,:id,:id/solves}) + ChallengesEventsController (authenticated SSE /api/v1/events) + ChallengesService (board, detail, submit, scoring util).
FrontendModule backend/src/frontend/frontend.module.ts Registers SpaFallbackMiddleware and the uploads static helper.

Controllers

Controller Path prefix Auth Source
AuthController /api/v1/auth Mostly public (login, refresh, logout, csrf) backend/src/modules/auth/auth.controller.ts
UsersController /api/v1/auth/register-first-admin Public (bootstrap-only) backend/src/modules/users/users.controller.ts
SetupController /api/v1/setup/create-admin Public (bootstrap-only; 409 SYSTEM_INITIALIZED once an admin exists) backend/src/modules/setup/setup.controller.ts
AdminController /api/v1/admin Admin only backend/src/modules/admin/admin.controller.ts
AdminGeneralController /api/v1/admin/general Admin only backend/src/modules/admin/admin-general.controller.ts
AdminCategoriesController /api/v1/admin/categories Admin only backend/src/modules/admin/admin-categories.controller.ts
AdminChallengesController /api/v1/admin/challenges Admin only backend/src/modules/admin/admin-challenges.controller.ts
AdminSystemController /api/v1/admin/system Admin only (plus confirmation tokens for destructive ops) backend/src/modules/admin/system/admin-system.controller.ts
SystemController /api/v1 Mixed (bootstrap/event/scoreboard/settings are public; events/status SSE is JWT-protected) backend/src/modules/system/system.controller.ts
UploadsController /api/v1/uploads Admin only backend/src/modules/uploads/uploads.controller.ts
BlogController /api/v1/blog Public backend/src/modules/blog/blog.controller.ts
AdminBlogController /api/v1/admin/blog/posts Admin only backend/src/modules/blog/admin-blog.controller.ts
ChallengesController /api/v1/challenges Authenticated backend/src/modules/challenges/challenges.controller.ts
ChallengesEventsController /api/v1/events Authenticated (SSE) backend/src/modules/challenges/events.controller.ts

Common services

Service Path Purpose
CsrfMiddleware backend/src/common/middleware/csrf.middleware.ts Mints/validates CSRF tokens via cookie + header.
JwtAuthGuard backend/src/common/guards/jwt-auth.guard.ts Global guard; honors @Public() decorator.
AdminGuard backend/src/common/guards/admin.guard.ts Requires authenticated user with role === 'admin'.
RolesGuard backend/src/common/guards/roles.guard.ts Enforces @Roles(...) metadata.
GlobalExceptionFilter backend/src/common/filters/global-exception.filter.ts Converts exceptions to standard envelope.
EventStatusService backend/src/common/services/event-status.service.ts Computes the 4-state event state machine (countdown/running/stopped/unconfigured) via getState() plus the legacy getStatus() shape (Stopped/Running + countdownMs).
LoginBackoffService backend/src/common/services/login-backoff.service.ts Per-IP+username brute-force throttle.
RegistrationRateLimitService backend/src/common/services/registration-rate-limit.service.ts Per-IP rate limit on first-admin registration.
SseHubService backend/src/common/services/sse-hub.service.ts In-process pub/sub for SSE streams.
ThemeLoaderService backend/src/common/utils/theme-loader.service.ts Loads + validates the 10 canonical themes.
ZodValidationPipe backend/src/common/pipes/zod-validation.pipe.ts Replaces ValidationPipe for zod-validated DTOs.
TransformInterceptor backend/src/common/interceptors/transform.interceptor.ts Optional response transformer.
scoring.util backend/src/modules/challenges/scoring.util.ts computeLivePoints, rankBonusForPosition, compareDifficulty, and safeEqualString (constant-time flag compare).

Decorators

Decorator Path Purpose
@Public() backend/src/common/decorators/public.decorator.ts Mark a route as unauthenticated.
@Roles(...) backend/src/common/decorators/roles.decorator.ts Required role(s).
@SkipCsrf() backend/src/common/decorators/skip-csrf.decorator.ts Exempt a route from CSRF check.

Startup chain

main.tsAppModule (loads ConfigModule, then all feature modules) → DatabaseInitService.init()FilesystemTransactionService.recoverTransactions() (resolves interrupted restore manifests before TypeORM opens the live SQLite file; ambiguous generations abort startup) → stale unowned swap-artifact sweep → migrations + WAL → verifySeed() (best-effort) → ensureSystemCategoryIcons() (best-effort — writes CRY/HW/MSC/PWN/REV/WEB.png into <UPLOAD_DIR>/icons/ if missing so freshly bootstrapped instances never serve 404 icons; see System Category Icon Seed) → app.use(...) middlewares (helmet, parsers, CSRF, static) → SwaggerModule.setup(...) (OpenAPI 3.1) → SpaFallbackMiddlewareapp.listen().

See also