--- type: guide title: Theming description: How the canonical themes are loaded, selected by administrators, and applied to the SPA via CSS custom properties. tags: [guide, theming, design, admin] timestamp: 2026-07-22T13:40:00Z --- # Theme catalog HIPCTF ships canonical themes defined as JSON files in `backend/themes/`. The catalog is identified by `THEME_IDS` in `backend/src/common/types/theme-ids.ts`; the default is `classic`. Each theme contains an `id`, display `name`, and token set containing colors, font family, radii, and spacing values. The frontend maps the supported visual tokens to CSS custom properties. # Administrator workflow 1. Sign in as an administrator and open **Admin area → General**, or navigate to `/admin/general`. 2. Wait for the settings and available-theme requests to finish. 3. Choose a value from **Global theme** (`data-testid="general-themeKey"`). 4. Click **Save** (`data-testid="general-save"`). 5. Verify that `Saved.` appears and that the page uses the selected colors, font, and corner radii. Reloading the application should preserve the theme. The selector lists themes exposed by `GET /api/v1/admin/general/themes`. Only theme JSON files present in the configured `THEMES_DIR` are listed, while the loader still maintains canonical fallback themes for bootstrap and runtime safety. # Backend loading `ThemeLoaderService` (`backend/src/common/utils/theme-loader.service.ts`) runs on module initialization: 1. Reads theme JSON files from `THEMES_DIR` (default `./themes`). 2. Validates IDs and tokens; malformed files are skipped or reported through the loader's validation path. 3. Backfills missing canonical themes so the application always has a valid catalog. 4. Validates the configured `SETTINGS_KEYS.THEME_KEY`; an unknown value falls back to `classic` and is persisted as the repaired setting. The selected theme is sent to the SPA in `GET /api/v1/bootstrap` (see [System Endpoints](/api/system.md)). Administrators can read and update the selection through [Admin Endpoints](/api/admin.md). A successful general-settings update emits a `general` SSE event containing the new `themeKey`. # Frontend application `BootstrapService` (`frontend/src/app/core/services/bootstrap.service.ts`) fetches `/api/v1/bootstrap` once per application lifecycle, stores the payload in signals, and applies the returned theme before the UI is rendered. The `applyThemeToCss` helper in `frontend/src/app/core/services/bootstrap.types.ts` writes these tokens to `document.documentElement`: | Theme token | CSS custom property | |---|---| | `primary`, `secondary`, `accent`, `surface`, `text` | `--color-*` | | `success`, `warning`, `danger` | `--color-*` | | `fontFamily` | `--font-family` | | `radii.sm`, `radii.md`, `radii.lg` | `--radius-sm`, `--radius-md`, `--radius-lg` | Reapplying a theme replaces the existing values. `clearThemeCss` removes every property managed by the helper. Components consume the properties through `var(--token)` in the global stylesheet and component styles. # Verification The frontend theme tests in `tests/frontend/bootstrap-theme.spec.ts` verify that all tokens are written, missing tokens are a no-op, reapplication replaces values, zero-valued radii are preserved, and cleanup removes every managed property. # See also - [System Endpoints](/api/system.md) - [Admin — General Settings](/guides/admin-general-settings.md) - [Admin Endpoints](/api/admin.md) - [Backend Module Map](/architecture/backend-modules.md)