docs: update documentation to OKF v0.1 format

This commit is contained in:
OpenVelo Agent
2026-07-22 19:19:43 +00:00
parent f62c77cf41
commit 73cfbb9af0
4 changed files with 61 additions and 11 deletions
+14 -1
View File
@@ -3,7 +3,7 @@ type: api
title: Uploads Endpoints title: Uploads Endpoints
description: Admin-only multipart upload endpoints for site logos, category icons, and challenge files. description: Admin-only multipart upload endpoints for site logos, category icons, and challenge files.
tags: [api, uploads, multipart, admin] tags: [api, uploads, multipart, admin]
timestamp: 2026-07-22T13:05:30Z timestamp: 2026-07-22T19:18:00Z
--- ---
# Endpoints # Endpoints
@@ -37,6 +37,19 @@ valid admin session and the standard CSRF cookie/header pair.
* An accepted logo keeps its sanitized filename, is written directly under * An accepted logo keeps its sanitized filename, is written directly under
`UPLOAD_DIR`, and returns `{ publicUrl, originalFilename }`, with `publicUrl` `UPLOAD_DIR`, and returns `{ publicUrl, originalFilename }`, with `publicUrl`
in the form `/uploads/{safeFilename}`. in the form `/uploads/{safeFilename}`.
* Category icons are decoded with Sharp and normalized to a 128-by-128 PNG.
When `categoryId` is supplied, the file is written to
`UPLOAD_DIR/icons/{categoryId}.png` (overwriting any previous icon for that
category) and the response carries `{ id: "{categoryId}.png", publicUrl,
width: 128, height: 128, mimeType: "image/png", storedPath, size,
originalFilename }`.
* Category-icon validation is strict: a missing `file`, an oversized upload,
a corrupt/non-image payload, or a buffer that Sharp cannot decode returns
`400 Bad Request`. Invalid category-icon payloads use the message
`Category icon must be a valid PNG, JPEG, GIF, or WebP image.` and **are
not persisted** — the existing icon file (if any) on disk is left untouched.
The multipart MIME type, the filename extension, and any browser `accept`
metadata are not trusted as proof of validity.
* A missing `file` part, an oversized upload, a corrupt image, or a decoded logo * A missing `file` part, an oversized upload, a corrupt image, or a decoded logo
in another format returns `400 Bad Request`. Invalid logo payloads use the in another format returns `400 Bad Request`. Invalid logo payloads use the
message `Logo must be a valid PNG, JPEG, GIF, or WebP image.` and are not message `Logo must be a valid PNG, JPEG, GIF, or WebP image.` and are not
+3 -3
View File
@@ -3,7 +3,7 @@ type: architecture
title: Key Files Index title: Key Files Index
description: One-line responsibility for important source and contract-test files, including strict event-window validation and the public bootstrap SSE listener. description: One-line responsibility for important source and contract-test files, including strict event-window validation and the public bootstrap SSE listener.
tags: [architecture, key-files, event-window, validation, default-challenge-ip, sse, bootstrap, migrations] tags: [architecture, key-files, event-window, validation, default-challenge-ip, sse, bootstrap, migrations]
timestamp: 2026-07-22T18:37:00Z timestamp: 2026-07-22T19:18:00Z
--- ---
# Backend # Backend
@@ -25,7 +25,7 @@ timestamp: 2026-07-22T18:37:00Z
| `backend/src/modules/admin/general.service.ts` | Reads/writes global settings, filters available theme files, and publishes the `general` SSE notification after updates. | | `backend/src/modules/admin/general.service.ts` | Reads/writes global settings, filters available theme files, and publishes the `general` SSE notification after updates. |
| `backend/src/modules/auth/auth.controller.ts` | Registers authentication and account endpoints. | | `backend/src/modules/auth/auth.controller.ts` | Registers authentication and account endpoints. |
| `backend/src/modules/auth/auth.service.ts` | Handles sessions, authentication, registration, and password changes. | | `backend/src/modules/auth/auth.service.ts` | Handles sessions, authentication, registration, and password changes. |
| `backend/src/modules/uploads/uploads.controller.ts` | Registers admin-only multipart uploads, including Sharp-backed site-logo format validation. | | `backend/src/modules/uploads/uploads.controller.ts` | Registers admin-only multipart uploads, including Sharp-backed site-logo format validation and strict category-icon decode (rejects undecodable / non-image buffers with HTTP 400 before any filesystem write so existing icons are preserved). |
| `backend/src/modules/admin/dto/general.dto.ts` | Zod contract for `PUT /api/v1/admin/general/settings`; both event timestamps are required ISO-8601 values and end must be strictly after start. | | `backend/src/modules/admin/dto/general.dto.ts` | Zod contract for `PUT /api/v1/admin/general/settings`; both event timestamps are required ISO-8601 values and end must be strictly after start. |
| `tests/backend/admin-general-event-window.spec.ts` | Focused contract tests for valid, empty, malformed, equal, and reversed event-window timestamps. | | `tests/backend/admin-general-event-window.spec.ts` | Focused contract tests for valid, empty, malformed, equal, and reversed event-window timestamps. |
| `tests/backend/admin-general-service.spec.ts` | General-settings schema and service tests, including per-field empty datetime failures and settings-event emission. | | `tests/backend/admin-general-service.spec.ts` | General-settings schema and service tests, including per-field empty datetime failures and settings-event emission. |
@@ -52,7 +52,7 @@ timestamp: 2026-07-22T18:37:00Z
| `frontend/src/app/features/shell/tabs/quick-tabs.component.ts` | Main shell navigation tabs. | | `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/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/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, and reacts to `open` / `mode` / `category` signal inputs via a `markForCheck` effect so edit prefill reaches the DOM. | | `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. | | `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-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/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. |
+43 -6
View File
@@ -3,7 +3,7 @@ type: guide
title: Admin — Categories title: Admin — Categories
description: How an admin lists, creates, edits, and deletes challenge categories from the /admin/categories page, including system-row protection and challenge-attached protection. description: How an admin lists, creates, edits, and deletes challenge categories from the /admin/categories page, including system-row protection and challenge-attached protection.
tags: [guide, admin, categories, tester] tags: [guide, admin, categories, tester]
timestamp: 2026-07-22T18:37:00Z timestamp: 2026-07-22T19:18:00Z
--- ---
# When this view is available # When this view is available
@@ -45,6 +45,7 @@ side-nav (categories are also embedded inside the General settings page).
| Form modal | `[data-testid="cat-form-modal"]` | Create/edit dialog (`cat-form-backdrop` is the click-outside dismiss layer). | | Form modal | `[data-testid="cat-form-modal"]` | Create/edit dialog (`cat-form-backdrop` is the click-outside dismiss layer). |
| Delete modal | `[data-testid="cat-delete-modal"]` | Confirmation dialog (`cat-delete-backdrop` is the dismiss layer). | | Delete modal | `[data-testid="cat-delete-modal"]` | Confirmation dialog (`cat-delete-backdrop` is the dismiss layer). |
| Delete error | `[data-testid="cat-delete-error"]` | Inline error message after a failed delete. | | Delete error | `[data-testid="cat-delete-error"]` | Inline error message after a failed delete. |
| Form error | `[data-testid="cf-error"]` | Inline error rendered inside the form modal after a failed create/update/upload. |
# Form modal fields # Form modal fields
@@ -54,7 +55,7 @@ side-nav (categories are also embedded inside the General settings page).
| Abbreviation (uppercase) | `cf-abbr` | Required, 26 chars; server upper-cases on save. `readonly` when editing a system row. | | Abbreviation (uppercase) | `cf-abbr` | Required, 26 chars; server upper-cases on save. `readonly` when editing a system row. |
| Description | `cf-desc` | Optional, max 2000 chars. | | Description | `cf-desc` | Optional, max 2000 chars. |
| Icon (file picker) | `cf-icon` | Optional image; uploaded to `POST /api/v1/uploads/category-icon` and resized/normalized server-side. | | Icon (file picker) | `cf-icon` | Optional image; uploaded to `POST /api/v1/uploads/category-icon` and resized/normalized server-side. |
| Cancel / OK | `cf-cancel`, `cf-ok` | OK disabled while form invalid or already submitting. | | Cancel / OK | `cf-cancel`, `cf-ok` | OK disabled while form invalid, already submitting, or while the parent is performing the async save (bound `saving` input). |
# Expected behavior # Expected behavior
@@ -84,10 +85,23 @@ side-nav (categories are also embedded inside the General settings page).
1. Click `cat-edit-{ABBR}` → modal opens in edit mode, pre-filled with 1. Click `cat-edit-{ABBR}` → modal opens in edit mode, pre-filled with
the row's values. the row's values.
2. For system rows, the abbreviation field is `readonly`. 2. For system rows, the abbreviation field is `readonly`. For user
3. On save the component issues `updateCategory(id, {...})`. If an icon (non-system) rows the abbreviation is editable and is uppercased
file is selected, the new icon is uploaded first and the returned server-side on save (the existing category row is re-sorted
`publicUrl` replaces `iconPath` in the same update. alphabetically by the defensive client sort after a successful
update).
3. On save the component issues `updateCategory(id, {...})` with
`name`, `abbreviation`, `description`, and (if an icon file was
chosen) `iconPath`. When an icon file is selected, the new icon is
uploaded first via `POST /api/v1/uploads/category-icon` and the
returned `publicUrl` replaces `iconPath` in the same update.
4. On either an upload rejection (HTTP 400) or an update rejection
(HTTP 400/404/409), the modal stays open, the OK button is disabled
while the request is in flight via the bound `saving` flag, and the
server message is rendered inside the modal at
`data-testid="cf-error"`. The list is not refreshed and any
previously-valid icon on disk is preserved (the upload endpoint
does not overwrite when Sharp decode fails).
### Edit prefill mechanics ### Edit prefill mechanics
@@ -112,6 +126,29 @@ input. `syncCategoryForm` is exported from the modal file so it can be
exercised in isolation by exercised in isolation by
`tests/frontend/admin-categories-form-modal.spec.ts`. `tests/frontend/admin-categories-form-modal.spec.ts`.
### Save error and loading state
`CategoryFormModalComponent` is purely presentational and does not own
HTTP state. It exposes two additional signal inputs:
* `errorMessage: string | null` — when truthy, an inline error paragraph
is rendered at `data-testid="cf-error"` showing the supplied message.
* `saving: boolean` — when `true`, the OK button is disabled in addition
to the existing `form.invalid` and `submitting` guards.
The parent `AdminCategoriesComponent` owns both signals:
* `formError` — set from the server's `error.message` (or a generic
fallback) when create/update/upload fails, and cleared every time the
modal is opened or a submission begins.
* `saving` — set to `true` at the start of `onFormSubmit` and reset to
`false` in `finally`, so the modal can never get stuck in a
"submitting" state if the request rejects.
This separation matters because `deleteError` (rendered by the delete
modal at `data-testid="cat-delete-error"`) is a different state machine
and must not be reused for create/update failures.
## Delete behavior ## Delete behavior
* **System rows:** the delete modal renders * **System rows:** the delete modal renders
+1 -1
View File
@@ -11,7 +11,7 @@ scoreboard, an event window with a public countdown, theming, and admin
controls. controls.
The docs below are organized by purpose so agents can pull just the slice The docs below are organized by purpose so agents can pull just the slice
they need. Last regenerated 2026-07-22T18:37:00Z. they need. Last regenerated 2026-07-22T19:18:00Z.
# Architecture # Architecture