docs: update documentation to OKF v0.1 format
This commit is contained in:
@@ -3,7 +3,7 @@ type: architecture
|
||||
title: Key Files Index
|
||||
description: One-line responsibility for every important source file in the repository.
|
||||
tags: [architecture, index, key-files]
|
||||
timestamp: 2026-07-21T18:45:54Z
|
||||
timestamp: 2026-07-21T22:19:08Z
|
||||
---
|
||||
|
||||
# Backend
|
||||
@@ -25,12 +25,12 @@ timestamp: 2026-07-21T18:45:54Z
|
||||
| `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` key/value table. |
|
||||
| `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)`. |
|
||||
| `backend/src/database/entities/refresh-token.entity.ts` | `refresh_token` table (token_hash + revocation). |
|
||||
| `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
|
||||
@@ -48,7 +48,7 @@ timestamp: 2026-07-21T18:45:54Z
|
||||
| `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` | Computes event `Stopped`/`Running` and `countdownMs`. |
|
||||
| `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. |
|
||||
@@ -58,19 +58,20 @@ timestamp: 2026-07-21T18:45:54Z
|
||||
| `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 `ThemeId`s. |
|
||||
| `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. |
|
||||
| `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. |
|
||||
| `backend/src/modules/auth/auth.controller.ts` | `/api/v1/auth/{register,login,refresh,logout,csrf}`. |
|
||||
| `backend/src/modules/auth/auth.service.ts` | Login, refresh, logout, register-first-admin, public player self-registration (`registerPlayer`), session minting. |
|
||||
| `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` (with `password === passwordConfirm` refine + username regex). |
|
||||
| `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`. |
|
||||
| `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. |
|
||||
@@ -83,8 +84,8 @@ timestamp: 2026-07-21T18:45:54Z
|
||||
| `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}` + SSE `/event/stream`, `/scoreboard/stream`. |
|
||||
| `backend/src/modules/system/system.service.ts` | Builds the public bootstrap payload from settings + theme + admin count. |
|
||||
| `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`). |
|
||||
@@ -111,10 +112,13 @@ timestamp: 2026-07-21T18:45:54Z
|
||||
| `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 (declares `/` shell with `adminGuard`-gated `/admin` child). |
|
||||
| `frontend/src/app/core/services/auth.service.ts` | Signal store for access token + current user; persists to `sessionStorage`, exposes `restoreSession()`, `waitUntilHydrated()`, `login()`, `register()` (both with `ensureCsrf()` + discriminated `LoginResult`/`RegisterResult`), `setSession()`. |
|
||||
| `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; `load()` / `ready()` deduplicate the in-flight fetch. |
|
||||
| `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). |
|
||||
@@ -134,14 +138,22 @@ timestamp: 2026-07-21T18:45:54Z
|
||||
| `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` | Authenticated shell: header + conditional admin nav + `<router-outlet>`. |
|
||||
| `frontend/src/app/features/home/home.shell.ts` | Pure `shouldShowAdminNav({isAuthenticated, role})` predicate (unit-tested). |
|
||||
| `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'|'admin-reset'`, `passwordMatchValidator`, policy hint, `errorMessage`/`submitting` inputs). Emits `submit({old,new,confirm})` and `cancel()`. |
|
||||
| `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` (18 suites) | Jest tests for backend modules, CSRF, OpenAPI 3.1, migrations, rate limits. |
|
||||
| `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. |
|
||||
@@ -152,6 +164,14 @@ timestamp: 2026-07-21T18:45:54Z
|
||||
| `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. |
|
||||
|
||||
Reference in New Issue
Block a user