frontend/src/main.ts |
Bootstraps Angular and registers HTTP interceptors. |
frontend/proxy.conf.json |
Angular dev-server proxy: forwards /api and /uploads to http://localhost:3000. |
frontend/angular.json |
Angular workspace config; the serve target references proxy.conf.json. |
package.json (root) |
Root npm scripts; dev runs both workspaces via concurrently, dev:backend / dev:frontend run one at a time. |
setup.sh |
Idempotent setup: installs root + workspace deps, builds both packages, creates ./data/uploads. |
frontend/src/app/app.routes.ts |
Defines public, shell, child, and admin routes. |
frontend/src/app/core/services/bootstrap.service.ts |
Caches and exposes bootstrap state, refreshes it after admin updates, and applies the resolved theme. |
frontend/src/app/core/services/bootstrap.types.ts |
Defines bootstrap/theme payload types and maps theme tokens to CSS custom properties. |
frontend/src/app/core/services/admin.service.ts |
Calls admin settings, theme-list, category, and upload APIs. |
frontend/src/app/features/home/home.component.ts |
Authenticated shell container; starts user and event state services. |
frontend/src/app/core/services/auth.service.ts |
Signal-backed access token and current-user state; owns the cross-tab invalidation BroadcastChannel + storage-event fallback. |
frontend/src/app/core/services/auth-session-events.pure.ts |
Pure cross-tab message encoding/validation and namespaced constants used by the auth broadcast channel. |
frontend/src/app/core/services/authenticated-event-source.service.ts |
Fetch-based authenticated SSE transport with frame parsing, abort support, and a separate 'unauthorized' event for 401/403. |
frontend/src/app/core/services/bootstrap-event.service.ts |
Root-provided public SSE listener that subscribes to /api/v1/event/stream, filters topic === 'general' frames, and triggers BootstrapService.refresh() so the landing modal stays in sync with admin general-settings updates. |
frontend/src/app/core/services/bootstrap-event.pure.ts |
Pure helpers for the public bootstrap SSE listener: isBootstrapGeneralFrame predicate, SSE line parser, and the makeBootstrapEventSource factory (fetch + ReadableStream opener with frame buffering and idempotent close()). |
frontend/src/app/core/services/event-status.store.ts |
Event state signal store, one-second countdown timer, and the optional onUnauthorized callback wiring; exposes start()/stop()/closeTransport() for transport lifecycle and subscribeReloadAtCountdownZero(handler) (with reloadAtCountdownZero(handler) kept as a back-compat wrapper) so the reload handler is owned by its subscriber rather than the transport. |
frontend/src/app/core/services/event-status.pure.ts |
Event payload types, transport interface (including 'unauthorized' listener), pure countdown helpers (formatDdHhMm returns DD:HH:mm:ss and deriveCountdownText), and the LED_COLOR_BY_STATE map used by the shell LED. |
frontend/src/app/features/home/home.component.ts |
Authenticated shell container; starts user and event state services, subscribes to peer invalidation, and navigates to /login when the session is invalidated elsewhere. |
frontend/src/app/features/shell/header/shell-header.component.ts |
Shell title, status LED (size/shape only — color comes from the pure map via [style.background-color]), countdown, and user menu. |
frontend/src/app/features/shell/tabs/quick-tabs.component.ts |
Main shell navigation tabs. |
frontend/src/app/features/shell/change-password/change-password-modal.component.ts |
Change-password form modal. |
frontend/src/app/features/admin/general.component.ts |
AdminGeneralComponent reactive form for /admin/general — per-field inline error rendering (page-title + event-start + event-end), logo upload wiring, welcome Markdown preview, event-state derivation, and SSE general event handling. |
frontend/src/app/features/admin/categories/category-form-modal.component.ts |
Standalone OnPush modal for create + edit; owns the CategoryFormGroup, exposes the pure syncCategoryForm helper, binds [formGroup] on its template <form>, accepts errorMessage + saving parent inputs (renders cf-error and disables OK while saving), and reacts to open / mode / category signal inputs via a markForCheck effect so edit prefill reaches the DOM. |
frontend/src/app/features/admin/general.pure.ts |
Pure General Settings helpers, including required datetime validation, field messages, UTC conversion, end-after-start validation, and the default-challenge-address IPv4/hostname validator/normalizer/message trio. |
tests/frontend/admin-general-pure.spec.ts |
Pure client-contract tests for required event timestamps, datetime messaging, UTC conversion, event-window ordering, and default-challenge-address validation, error mapping, and normalization. |
tests/frontend/admin-categories-form-modal.spec.ts |
Tests the pure syncCategoryForm helper that drives the edit/create prefill in CategoryFormModalComponent: system-row abbreviation lock, user-row unlock, re-population on second invocation, clearing on create, and iconPreview passthrough. |
tests/frontend/authenticated-event-source.spec.ts |
Tests SSE authorization, frame transport behavior, and the 401/403 unauthorized path. |
tests/frontend/auth-session-events.spec.ts |
Pure tests for cross-tab invalidation message encoding, payload validation, and storage-event filtering. |
tests/frontend/admin-challenges-import-autoclose.spec.ts |
Pure helpers (summarizeImportResult, importErrorMessage) and modal auto-close branch for the confirmed-import handler. |
frontend/src/app/features/challenges/challenges.page.ts |
/challenges smart page: gate logic (countdown/running/stopped/unconfigured), modal lifecycle, SSE wiring on /api/v1/events, and the page-owned countdown-zero reload (handler registered in the constructor with the disposer wired into DestroyRef). |
frontend/src/app/features/challenges/challenges.store.ts |
Signal store: board, event state, per-card solve listeners, SSE solve-frame mutation, submit response application, stop() lifecycle. |
frontend/src/app/features/challenges/challenges.service.ts |
HTTP service for /api/v1/challenges/{board,status,:id,:id/solves} returning typed ApiErrorEnvelopes. getDetail always requests ?include=solvers so the modal can render the solvers list in one round-trip; getBoard only attaches include=solvers when the caller opts in. |
frontend/src/app/features/challenges/challenges.pure.ts |
Pure types and helpers (BoardCard, SolverRow, SolveEventPayload, parseSolveEvent, mergeSolveEventIntoSolvers, messageForSolveError, formatDdHhMm). |
frontend/src/app/features/challenges/category-column.component.ts |
Renders a single category column (header + cards) on the challenges board. |
frontend/src/app/features/challenges/challenge-card.component.ts |
Renders a single challenge card on the board (difficulty, live points, solve count, ✓ when solved by the player). |
frontend/src/app/features/challenges/challenge-modal.component.ts |
Challenge detail modal: description, flag form, awarded banner, solvers list, live-solve updates. |
frontend/src/app/core/services/notification.service.ts |
Root-provided signal-backed store of { id, kind, message, ts } records; error() / info() push, dismiss(id) / clear() remove. |
frontend/src/app/core/interceptors/error-notification.interceptor.ts |
Translates HttpErrorResponse into friendly messages and pushes them to NotificationService (with suppression for /api/v1/auth/{login,csrf,register} and /api/v1/challenges/status). |
tests/frontend/challenges.pure.spec.ts |
Pure helpers: sorting, parsers, friendly error mapping, formatDdHhMm (DD:HH:mm:ss). |
tests/frontend/challenges.service.spec.ts |
HTTP-service contract: getDetail URL-encodes the id, attaches ?include=solvers, and forwards withCredentials: true. |
tests/frontend/challenges.store.spec.ts |
Signal store: board mutation, live solve merge, listeners, stop(). |
tests/frontend/notification-interceptor.spec.ts |
Interceptor suppression rules and friendly message mapping. |
tests/backend/challenges-board.spec.ts |
Board query shape, ordering, ?include=solvers. |
tests/backend/challenges-status-rest.spec.ts |
/api/v1/challenges/status snapshot shape. |
tests/backend/challenges-events-sse.spec.ts |
/api/v1/events SSE: status + solve frames, dedup, ordering. |
tests/backend/challenges-submit-flag.spec.ts |
Submit flow: correct/incorrect flag, idempotent re-submit, event-state guard, race handling. |