From ec3c5fdcd3f45b1c4737f2d5490f264a2869b4cf Mon Sep 17 00:00:00 2001 From: OpenVelo Agent Date: Wed, 22 Jul 2026 13:06:31 +0000 Subject: [PATCH] docs: update documentation to OKF v0.1 format --- docs/api/uploads.md | 59 +++++++++++++++++++++++++++------- docs/architecture/key-files.md | 3 +- docs/index.md | 2 +- 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/docs/api/uploads.md b/docs/api/uploads.md index eda9bf5..79c96a5 100644 --- a/docs/api/uploads.md +++ b/docs/api/uploads.md @@ -1,33 +1,70 @@ --- type: api title: Uploads Endpoints -description: Admin-only multipart upload endpoints for category icons and challenge files. +description: Admin-only multipart upload endpoints for site logos, category icons, and challenge files. tags: [api, uploads, multipart, admin] -timestamp: 2026-07-21T18:28:00Z +timestamp: 2026-07-22T13:05:30Z --- # Endpoints | Method | Path | Auth | Source | |--------|---------------------------------------|-------|---------------------------------------------------------| -| `POST` | `/api/v1/uploads/category-icon` | Admin | `backend/src/modules/uploads/uploads.controller.ts` | +| `POST` | `/api/v1/uploads/logo` | Admin | `backend/src/modules/uploads/uploads.controller.ts` | +| `POST` | `/api/v1/uploads/category-icon` | Admin | Same. | | `POST` | `/api/v1/uploads/challenge-file` | Admin | Same. | # Guard chain -Both handlers are gated by `JwtAuthGuard` + `AdminGuard`. CSRF is enforced -(standard cookie + header pattern; nothing is added to the skip list). +All handlers are gated by the controller-level `AdminGuard` and `admin` role. +The global authentication and CSRF protections also apply; clients must send a +valid admin session and the standard CSRF cookie/header pair. # Behavior -* Each endpoint uses `FileInterceptor('file')` and parses a single - multipart part named `file`. -* File size is validated by `parseUploadSizeLimit()` in - `backend/src/common/utils/upload.ts`. -* Filenames are sanitized by the same helper before being persisted - under `UPLOAD_DIR`. +* Each endpoint uses `FileInterceptor('file')` and parses a single multipart + part named `file`. +* File size is validated against `UPLOAD_SIZE_LIMIT` through + `parseUploadSizeLimit()` in `backend/src/common/utils/upload.ts`. +* Category icons are written under `UPLOAD_DIR/icons`; when `categoryId` is + supplied, the image is cropped to a 128-by-128 PNG and exposed at + `/uploads/icons/{categoryId}.png`. +* Challenge attachments are written under `UPLOAD_DIR/challenges` and exposed + at `/uploads/challenges/{safeFilename}`. +* Site logos are decoded with Sharp and accepted only when their actual format + is PNG, JPEG, GIF, or WebP. The multipart MIME type and filename extension + are not trusted for validation. +* An accepted logo keeps its sanitized filename, is written directly under + `UPLOAD_DIR`, and returns `{ publicUrl, originalFilename }`, with `publicUrl` + in the form `/uploads/{safeFilename}`. +* 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 + message `Logo must be a valid PNG, JPEG, GIF, or WebP image.` and are not + persisted. + +# Examples + +1. Sign in as an administrator and navigate to `/admin/general`. +2. In the site-logo setting, choose a PNG, JPEG, GIF, or WebP image and save the + general settings. +3. The client uploads the selected file to `POST /api/v1/uploads/logo` before + saving the returned `/uploads/...` URL as the configured logo. +4. After a successful save, the uploaded image is available from its returned + public URL and is used wherever the configured site logo is rendered. +5. Choosing a corrupt file, or a valid image in an unsupported format, leaves + the file unstored and surfaces the upload validation failure to the user. + +# Key files + +| File | Responsibility | +|---|---| +| `backend/src/modules/uploads/uploads.controller.ts` | Registers upload routes, validates payloads, and persists files. | +| `backend/src/common/utils/upload.ts` | Parses size limits and sanitizes upload filenames. | +| `frontend/src/app/features/admin/general/admin-general.component.ts` | Provides the administrator-facing logo selection and settings workflow. | +| `tests/backend/uploads-logo.spec.ts` | Verifies accepted logo formats, spoofed/corrupt payload rejection, size limits, and persisted responses. | # See also +- [Admin — General Settings](/guides/admin-general-settings.md) - [REST API Overview](/api/rest-overview.md) - [Backend Module Map](/architecture/backend-modules.md) diff --git a/docs/architecture/key-files.md b/docs/architecture/key-files.md index 8f7e224..5f8cf24 100644 --- a/docs/architecture/key-files.md +++ b/docs/architecture/key-files.md @@ -1,7 +1,7 @@ --- type: architecture title: Key Files Index -description: One-line responsibility for important source files, including authenticated event streaming. +description: One-line responsibility for important source files, including authenticated event streaming and validated site-logo uploads. tags: [architecture, index, key-files] timestamp: 2026-07-22T10:32:00Z --- @@ -22,6 +22,7 @@ timestamp: 2026-07-22T10:32:00Z | `backend/src/modules/system/system.service.ts` | Builds the public bootstrap payload. | | `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/uploads/uploads.controller.ts` | Registers admin-only multipart uploads, including Sharp-backed site-logo format validation. | # Frontend diff --git a/docs/index.md b/docs/index.md index e56426b..b7da900 100644 --- a/docs/index.md +++ b/docs/index.md @@ -49,7 +49,7 @@ they need. Last regenerated 2026-07-22T12:44:45Z. * [System Endpoints](/api/system.md) - Bootstrap, event status, public SSE streams, public event-window settings, and the authenticated `/events/status` SSE stream. -* [Uploads Endpoints](/api/uploads.md) - Admin-only multipart uploads. +* [Uploads Endpoints](/api/uploads.md) - Admin-only multipart uploads for category icons, challenge files, and validated site logos. # Guides