25 KiB
25 KiB
type, title, description, tags, timestamp
| type | title | description | tags | timestamp | |||
|---|---|---|---|---|---|---|---|
| architecture | Key Files Index | One-line responsibility for every important source file in the repository. |
|
2026-07-21T22:19:08Z |
Backend
Entrypoint & config
| File | Responsibility |
|---|---|
backend/src/main.ts |
Bootstraps Nest, registers middleware, builds OpenAPI 3.1, mounts SPA fallback. |
backend/src/app.module.ts |
Root module; wires every feature module + global guards/filters. |
backend/src/config/env.schema.ts |
Zod-validated env schema, SETTINGS_KEYS, system category metadata. |
Database
| File | Responsibility |
|---|---|
backend/src/database/database.module.ts |
TypeORM better-sqlite3 config, entity + migration registration. |
backend/src/database/database-init.service.ts |
Initializes the DataSource, enforces WAL PRAGMA, runs migrations, verifies seed. |
backend/src/database/migrations/1700000000000-InitSchema.ts |
Creates all tables and sets WAL + foreign keys. |
backend/src/database/migrations/1700000000100-SeedSystemData.ts |
Seeds the 6 system categories and default settings. |
backend/src/database/entities/user.entity.ts |
user table (admin/player role, enabled/disabled status). |
backend/src/database/entities/setting.entity.ts |
setting table. |
backend/src/database/entities/category.entity.ts |
category table with system_key unique index. |
backend/src/database/entities/challenge.entity.ts |
challenge table (difficulty, decay, protocol, flag, port). |
backend/src/database/entities/challenge-file.entity.ts |
challenge_file table for attachments. |
backend/src/database/entities/solve.entity.ts |
solve table with unique (challenge_id, user_id) (used by UsersRankService). |
backend/src/database/entities/refresh-token.entity.ts |
refresh_token table (token_hash + revocation). |
backend/src/database/entities/blog-post.entity.ts |
blog_post table (draft/published + publishedAt index). |
Common
| File | Responsibility |
|---|---|
backend/src/common/common.module.ts |
Aggregates common services, middleware, and providers. |
backend/src/common/middleware/csrf.middleware.ts |
Double-submit CSRF check; mints/reads cookie, compares header. |
backend/src/common/guards/jwt-auth.guard.ts |
Global JWT guard; honors @Public(). |
backend/src/common/guards/admin.guard.ts |
Requires req.user.role === 'admin'. |
backend/src/common/guards/roles.guard.ts |
Enforces @Roles(...) metadata. |
backend/src/common/decorators/public.decorator.ts |
@Public() marker. |
backend/src/common/decorators/roles.decorator.ts |
@Roles(...) metadata. |
backend/src/common/decorators/skip-csrf.decorator.ts |
@SkipCsrf() marker. |
backend/src/common/filters/global-exception.filter.ts |
Converts all errors to the standard envelope. |
backend/src/common/pipes/zod-validation.pipe.ts |
Validates body/param/query with a zod schema. |
backend/src/common/interceptors/transform.interceptor.ts |
Optional response transformer. |
backend/src/common/services/event-status.service.ts |
4-state machine (countdown/running/stopped/unconfigured) via getState(); legacy getStatus() shape preserved for backward compatibility. |
backend/src/common/services/login-backoff.service.ts |
Per-IP+username failed-login throttle. |
backend/src/common/services/registration-rate-limit.service.ts |
Per-IP first-admin registration throttle. |
backend/src/common/services/sse-hub.service.ts |
In-process pub/sub for event status and scoreboard streams. |
backend/src/common/utils/openapi31.ts |
Converts the Nest-generated OpenAPI 3.0 doc to OpenAPI 3.1. |
backend/src/common/utils/password-policy.ts |
Argon2 password validator (length, mixed-case policy). |
backend/src/common/utils/theme-loader.service.ts |
Loads themes from disk, backfills built-ins, validates tokens. |
backend/src/common/utils/upload.ts |
Upload size-limit parser + filename sanitizer. |
backend/src/common/types/theme.ts, theme-ids.ts |
Theme interface and the 10 canonical ThemeIds. |
backend/src/common/errors/api-error.ts |
ApiError class (status + machine code + message + details). |
backend/src/common/errors/error-codes.ts |
Canonical ERROR_CODES enum (now includes INVALID_OLD_PASSWORD, PASSWORD_POLICY, PASSWORDS_DO_NOT_MATCH). |
Modules
| File | Responsibility |
|---|---|
backend/src/modules/auth/auth.module.ts |
Wires AuthController, AuthService, JwtStrategy; imports SettingsModule for the public register flow and UsersModule (forwardRef) for UsersRankService. |
backend/src/modules/auth/auth.controller.ts |
/api/v1/auth/{register,login,refresh,logout,csrf,me,change-password}. logout, me, and change-password are JWT-protected (CSRF-enforced on change-password). |
backend/src/modules/auth/auth.service.ts |
Login, refresh, logout, register-first-admin, public player self-registration (registerPlayer), session minting, getMe(userId) (rank + points), changePassword(userId, dto) (revoke-all-refresh-tokens on success). |
backend/src/modules/auth/cookie.ts |
setRefreshCookie / clearRefreshCookie helpers. |
backend/src/modules/auth/dto/auth.dto.ts |
Zod schemas for login + refresh + RegisterDtoSchema + ChangePasswordDtoSchema + MeResponseDtoSchema. |
backend/src/modules/auth/strategies/jwt.strategy.ts |
Passport JWT strategy. |
backend/src/modules/users/users.module.ts |
Wires UsersController + UsersService + UsersRankService. |
backend/src/modules/users/users-rank.service.ts |
Pure provider rankOfUser(manager, userId) returning {rank, points} by summing pointsAwarded from solve and counting distinct users ahead. |
backend/src/modules/users/users.controller.ts |
/api/v1/auth/register-first-admin. |
backend/src/modules/users/users.service.ts |
enforceLastAdminInvariant helper. |
backend/src/modules/users/dto/create-first-admin.dto.ts |
Zod schema for first-admin registration. |
backend/src/modules/setup/setup.module.ts |
Wires SetupController + SetupService (dedicated first-admin bootstrap flow). |
backend/src/modules/setup/setup.controller.ts |
POST /api/v1/setup/create-admin (returns 404 once an admin exists). |
backend/src/modules/setup/setup.service.ts |
Hashes password (Argon2id), runs the create inside a transaction, mints session via AuthService.createSession. |
backend/src/modules/setup/dto/create-admin.dto.ts |
Zod schema with password === passwordConfirm refine. |
backend/src/modules/admin/admin.module.ts |
Wires AdminController + AdminService. |
backend/src/modules/admin/admin.controller.ts |
/api/v1/admin/users[/{id}]. |
backend/src/modules/admin/admin.service.ts |
list / create / update role / delete user with last-admin guard. |
backend/src/modules/admin/dto/admin.dto.ts |
Zod schemas for admin endpoints. |
backend/src/modules/system/system.module.ts |
Wires SystemController + SystemService + status + hub services. |
backend/src/modules/system/system.controller.ts |
/api/v1/{bootstrap,event/status,event/stream,settings/event,scoreboard/stream} (public) + authenticated SSE /events/status (plural, JWT-protected). |
backend/src/modules/system/system.service.ts |
Builds the public bootstrap payload from settings + theme + admin count + password policy. |
backend/src/modules/uploads/uploads.module.ts |
Wires UploadsController. |
backend/src/modules/uploads/uploads.controller.ts |
/api/v1/uploads/{category-icon,challenge-file}. |
backend/src/modules/blog/blog.module.ts |
Wires BlogController + BlogService (registers BlogPostEntity). |
backend/src/modules/blog/blog.controller.ts |
GET /api/v1/blog/posts (public). |
backend/src/modules/blog/blog.service.ts |
listPublished() returns published posts ordered by publishedAt DESC. |
backend/src/modules/blog/dto/blog.dto.ts |
Zod schemas PublicBlogPostSchema + PublicBlogListSchema. |
backend/src/modules/settings/settings.module.ts |
SettingsService (get/set/getAll over the setting table). |
backend/src/frontend/frontend.module.ts |
Wires SPA fallback + uploads static middleware. |
backend/src/frontend/spa.controller.ts |
SpaFallbackMiddleware (returns index.html for client routes). |
backend/src/frontend/uploads-static.middleware.ts |
Mounts /uploads static helper. |
Themes
| File | Responsibility |
|---|---|
backend/themes/01-classic.json |
classic theme tokens. |
backend/themes/02-midnight.json … 10-monochrome.json |
The other 9 canonical themes. |
Frontend
| File | Responsibility |
|---|---|
frontend/src/main.ts |
Bootstraps the standalone Angular app + registers interceptors. |
frontend/src/index.html |
Root HTML shell. |
frontend/src/styles.css |
Global styles consuming theme CSS custom properties. |
frontend/src/app/app.component.ts |
Root component; triggers bootstrap then AuthService.restoreSession() on init. |
frontend/src/app/app.routes.ts |
Angular route table (bootstrap, login, shell / with child routes challenges/scoreboard/blog/admin, wildcard **). |
frontend/src/app/core/services/auth.service.ts |
Signal store for access token + current user; persists to sessionStorage, exposes restoreSession(), waitUntilHydrated(), login(), register(), logout(), me(), changePassword() (all with ensureCsrf() + discriminated LoginResult/RegisterResult/ChangePasswordResult), setSession(). |
frontend/src/app/core/services/auth.session-storage.ts |
Pure sessionStorage helpers (readStoredSession, writeStoredSession, clearStoredSession) under key hipctf.auth.v1. |
frontend/src/app/core/services/bootstrap.service.ts |
Fetches /api/v1/bootstrap, applies theme tokens to CSS; exposes a passwordPolicy computed signal derived from the bootstrap payload. |
frontend/src/app/core/services/event-status.store.ts |
Signal store for the live event window (state, serverNowUtc, eventStartUtc, eventEndUtc, derived countdownText); start(createSource)/stop() manage the SSE connection + 1-second tick. |
frontend/src/app/core/services/event-status.pure.ts |
Pure helpers used by the store and tests: deriveCountdownText, formatDdHhMm, EventSourceLike, EventState/EventStatePayload. |
frontend/src/app/core/services/user.store.ts |
Signal store for the authenticated user (user, loading, error, derived rankText); hydrateFromAuth() + loadMe() (calls AuthService.me()). |
frontend/src/app/core/services/admin.service.ts |
GET /api/v1/admin/users returning AdminUser[]. |
frontend/src/app/core/services/markdown.service.ts |
Thin Angular MarkdownService.render(md): string that forwards to renderMarkdownToHtml. The DOMPurify sanitization happens inside renderMarkdownToHtml so Angular's [innerHTML] binding receives a sanitized plain string — no DomSanitizer.bypassSecurityTrustHtml wrapper is required. |
frontend/src/app/core/services/markdown.pure.ts |
Pure renderMarkdownToHtml helper using marked + DOMPurify (kept in its own file so it can be unit-tested without Angular's ESM-only runtime and so the sanitization boundary is shared between production and tests). |
frontend/src/app/core/guards/auth.guard.ts |
Async CanActivateFn; awaits bootstrap + auth hydration, delegates to decideAuthRedirect. |
frontend/src/app/core/guards/auth.guard.decision.ts |
Pure decision function for the auth guard (returns true or a redirect UrlTree). |
frontend/src/app/core/guards/admin.guard.ts |
Async CanActivateFn for admin-only routes; awaits bootstrap + auth hydration, delegates to decideAdminGuard. |
frontend/src/app/core/guards/admin.guard.decision.ts |
Pure decision function for the admin guard (returns allow / redirect). |
frontend/src/app/core/guards/landing.guard.ts |
Async CanActivateFn for /login; awaits bootstrap + auth hydration, then delegates to the pure decideLandingGuard. |
frontend/src/app/core/guards/landing.guard.decision.ts |
Pure decision: returns true to render the landing page, or UrlTree to /bootstrap (not initialized) or / (already authenticated). |
frontend/src/app/core/interceptors/auth.interceptor.ts |
Attaches Bearer header. |
frontend/src/app/core/interceptors/csrf.interceptor.ts |
Attaches X-CSRF-Token on unsafe methods. |
frontend/src/app/features/landing/landing.component.{ts,html,css} |
Public landing page (logo, page title, rendered welcomeMarkdown, login button, blog list) + modal containing the login and registration forms (toggled by the same mode signal). The template binds the welcome card via [innerHTML]="welcomeHtml()" (the computed signal invoked); binding the raw welcomeHtml signal object would render the runtime helper source — see tests/frontend/landing-welcome.spec.ts. |
frontend/src/app/features/landing/landing.service.ts |
Fetches GET /api/v1/blog/posts, exposes posts/loading/error signals, refresh(). |
frontend/src/app/features/landing/login-modal.service.ts |
Pure buildLoginFailureMessage helper that maps {code,message} into user-facing copy (handles INVALID_CREDENTIALS, RATE_LIMITED, CSRF_INVALID, USERNAME_TAKEN, WEAK_PASSWORD, REGISTRATIONS_DISABLED, VALIDATION_FAILED). |
frontend/src/app/features/admin/admin-users.component.ts |
Admin-only user list (signals: loading, error, users). |
frontend/src/app/features/setup/setup-create-admin.component.ts |
First-admin modal overlay (non-dismissible; typed reactive form). |
frontend/src/app/features/setup/setup-create-admin.service.ts |
POSTs to /api/v1/setup/create-admin and tags the result with the error code. |
frontend/src/app/features/setup/setup-create-admin.validators.ts |
Standalone passwordMatchValidator group-level reactive form validator. |
frontend/src/app/features/setup/setup-create-admin.field-errors.ts |
Pure usernameError / passwordError / confirmError helpers that turn reactive-form state into the inline validation messages rendered next to each input. |
frontend/src/app/features/home/home.component.ts |
Smart authenticated shell: renders ShellHeaderComponent, QuickTabsComponent, ChangePasswordModalComponent, and <router-outlet>. Owns the SSE lifecycle (EventStatusStore.start/stop), the UserStore.loadMe() call, and the open/close signals for the change-password modal. |
frontend/src/app/features/home/home.shell.ts |
Pure shouldShowAdminNav({isAuthenticated, role}) and deriveActiveSectionFromUrl(url) predicates (unit-tested). |
frontend/src/app/features/shell/header/shell-header.component.ts |
Dumb header: page title, active-section label, LED (led-{state} class), countdown text, user menu trigger, inline user menu dropdown with rank / change-password / admin / logout entries. |
frontend/src/app/features/shell/tabs/quick-tabs.component.ts |
Dumb Challenges / Scoreboard / Blog tab strip; tabs/active inputs, tabChange output. |
frontend/src/app/features/shell/change-password/change-password-modal.component.ts |
Dumb reactive-form modal (mode `'self' |
frontend/src/app/features/shell/change-password/change-password-modal.validators.ts |
passwordMatchValidator group validator + PasswordPolicy zod schema. |
frontend/src/app/features/shell/change-password/password-feedback.ts |
Pure formatChangePasswordError({code, message}) helper that maps the API code to user-facing copy. |
frontend/src/app/features/challenges/challenges.page.ts |
Placeholder /challenges page. |
frontend/src/app/features/scoreboard/scoreboard.page.ts |
Placeholder /scoreboard page. |
frontend/src/app/features/blog/blog.page.ts |
Placeholder /blog page. |
Tests
| File | Responsibility |
|---|---|
tests/backend/*.spec.ts (~25 suites) |
Jest tests for backend modules, CSRF, OpenAPI 3.1, migrations, rate limits, the new /me + /change-password + authenticated SSE flows, and UsersRankService. |
tests/frontend/theme.spec.ts |
Jest test for theme token application. |
tests/frontend/admin-shell.spec.ts |
Unit tests for shouldShowAdminNav predicate. |
tests/frontend/admin-navigation.spec.ts |
Tests for admin guard decision + nav-link rendering. |
tests/frontend/auth-restore.spec.ts |
Round-trips auth.session-storage helpers + refresh success/failure paths. |
tests/frontend/setup-create-admin.spec.ts |
Pure-Jest tests for passwordMatchValidator and the three field-error helpers (usernameError, passwordError, confirmError). |
tests/frontend/guard-bootstrap-race.spec.ts |
Pins decideAuthRedirect so a refresh on a deep link never flashes /bootstrap or /login while auth is hydrating. |
tests/frontend/landing-guard.spec.ts |
Pins decideLandingGuard for the not-initialized / authenticated / anonymous branches. |
tests/frontend/landing-markdown.spec.ts |
Pins renderMarkdownToHtml (sanitization of raw <script> payloads, script URL schemes, etc.). |
tests/frontend/landing-welcome.spec.ts |
Regression test for the landing welcome binding — asserts the bootstrap payload's welcomeMarkdown produces the expected sanitized HTML (h1 + paragraph) and never the Angular runtime helper source string, including for null/empty/hostile payloads. |
tests/frontend/landing-modal.spec.ts |
Pins buildLoginFailureMessage (INVALID_CREDENTIALS, RATE_LIMITED with retry-seconds extraction, CSRF_INVALID, USERNAME_TAKEN, WEAK_PASSWORD, REGISTRATIONS_DISABLED, VALIDATION_FAILED, default fallback). |
tests/frontend/event-status.store.spec.ts |
Pins EventStatusStore.applyServerStatus (state + delta anchor) and deriveCountdownText (countdown / running / stopped / unconfigured). |
tests/frontend/change-password-modal.spec.ts |
Pins the dumb modal's reactive form (validation, submit/cancel emission, error rendering). |
tests/frontend/shell-active-section.spec.ts |
Pins deriveActiveSectionFromUrl for the four URL branches. |
tests/backend/change-password.spec.ts |
Integration coverage for /api/v1/auth/change-password (wrong-old / mismatched / weak / unauth branches). |
tests/backend/event-status-state.spec.ts |
Pins the 4-state derivation in EventStatusService.getState(). |
tests/backend/events-status-sse.spec.ts |
Pins the authenticated SSE stream (401 + initial EventStatePayload). |
tests/backend/me-endpoint.spec.ts |
Pins /api/v1/auth/me (401 + payload shape including rank/points). |
tests/backend/rank-points.spec.ts |
Pure unit test for UsersRankService.rankOfUser(). |
tests/backend/auth-register.spec.ts |
Backend integration tests for POST /api/v1/auth/register (happy path, disabled flag, duplicate username, weak password, rate limit). |
tests/backend/blog-public.spec.ts |
Backend integration tests for GET /api/v1/blog/posts (only published rows, descending order). |
tests/backend/csrf-protected-routes.spec.ts |
Pins CSRF enforcement on the formerly-skipped /api/v1/auth/login route. |
tests/backend/csrf-client.ts |
Test helper for CSRF flow. |
tests/backend/db-helper.ts |
Test helper for spinning up an isolated DB. |