docs: update documentation to OKF v0.1 format

This commit is contained in:
OpenVelo Agent
2026-07-22 15:10:59 +00:00
parent 282fcbab94
commit a8a81b0429
2 changed files with 61 additions and 4 deletions
+60 -3
View File
@@ -2,8 +2,8 @@
type: guide type: guide
title: Admin — General Settings title: Admin — General Settings
description: How an admin edits required platform-wide settings, including the validated event window, from the /admin/general page. description: How an admin edits required platform-wide settings, including the validated event window, from the /admin/general page.
tags: [guide, admin, settings, general, tester, datetime, validation] tags: [guide, admin, settings, general, tester, datetime, validation, utc, timezone]
timestamp: 2026-07-22T14:50:25Z timestamp: 2026-07-22T15:09:39Z
--- ---
# When this view is available # When this view is available
@@ -56,7 +56,8 @@ The page is a single reactive form with these controls (every
* **Initial load:** `loading() === true` renders `general-loading`. After * **Initial load:** `loading() === true` renders `general-loading`. After
both requests resolve, the form is patched with the values from the both requests resolve, the form is patched with the values from the
backend (UTC timestamps are converted to `datetime-local` strings via backend (UTC timestamps are converted to `datetime-local` strings via
`toDatetimeLocal` so the native picker shows them). `toDatetimeLocal` so the native picker shows them — see
[Datetime UTC round-trip](#datetime-utc-round-trip) below).
* **Logo upload:** selecting a file fires `POST /api/v1/uploads/logo`, * **Logo upload:** selecting a file fires `POST /api/v1/uploads/logo`,
then writes the returned `publicUrl` into the hidden `logo` control. then writes the returned `publicUrl` into the hidden `logo` control.
If the upload fails, `general-logo-error` shows the message; the If the upload fails, `general-logo-error` shows the message; the
@@ -179,6 +180,62 @@ is rendered inside the per-field error region
(`data-testid="general-eventEnd-error"`) by the (`data-testid="general-eventEnd-error"`) by the
`eventEndFieldMessage` helper. `eventEndFieldMessage` helper.
# Datetime UTC round-trip
Both Event-window fields (`general-eventStart`, `general-eventEnd`) are
backed by HTML `<input type="datetime-local">` controls, which the
browser renders as a wall-clock picker **without** any timezone
indicator. The two pure helpers exported from
`frontend/src/app/features/admin/general.pure.ts` make the wall-clock
values behave as if they were already UTC, so the admin sees the same
instant no matter where the browser is running:
| Helper | Direction | Purpose |
|------------------------------------------------|-------------------------------------|---------|
| `toDatetimeLocal(iso: string): string` | ISO-8601 UTC → `YYYY-MM-DDTHH:mm` | Renders a backend UTC instant in the native picker using `getUTC*` getters. |
| `toIsoUtc(local: string): string` | `YYYY-MM-DDTHH:mm[:ss[.fff]]` → ISO-8601 UTC | Parses the wall-clock components as **UTC** (not local time) via `Date.UTC(...)` and returns `toISOString()`. |
The `toIsoUtc` helper explicitly does **not** call `new Date(local)`,
which would interpret the components in the browser's local timezone
and shift the round-tripped instant by the browser's UTC offset. Instead
it regex-parses the year / month / day / hour / minute components (and
optional seconds / milliseconds), constructs the instant with
`new Date(Date.UTC(...))`, and returns `toISOString()`. As a result,
`toIsoUtc(toDatetimeLocal(iso)) === iso` for any minute-precision
`datetime-local` value the picker can produce, regardless of the
browser's `Intl.DateTimeFormat().resolvedOptions().timeZone` value.
The helper preserves its existing fallback contract:
| Input | Output |
|------------------------------------|---------------------------------|
| `''` (empty) | `''` |
| Non-matching `YYYY-MM-DDTHH:mm…` | Returns the input verbatim so the reactive-form `invalidDatetime` validator still fires. |
| Matching `YYYY-MM-DDTHH:mm` | `<value>:00.000Z` |
| Matching `YYYY-MM-DDTHH:mm:ss` | `<value>.000Z` |
| Matching `YYYY-MM-DDTHH:mm:ss.fff` | `<value>Z` (fraction padded to ms) |
`AdminGeneralComponent` calls `toIsoUtc` on both `eventStartUtc` and
`eventEndUtc` before issuing `PUT /api/v1/admin/general/settings`, so
correcting the shared helper fixes start and end submissions without
any further component, form, or backend rewiring. The backend zod
schema (`GeneralSettingsSchema` in
`backend/src/modules/admin/dto/general.dto.ts`) accepts the resulting
timezone-aware ISO-8601 strings unchanged and enforces
`eventEndUtc > eventStartUtc` via `superRefine`.
The regression for this fix lives in
`tests/frontend/admin-general-pure.spec.ts` under the `datetime helpers`
suite, with cases that lock in:
* `toIsoUtc('2027-03-15T08:30')``'2027-03-15T08:30:00.000Z'`
(would previously have returned `'2027-03-15T15:30:00.000Z'` from a
PDT browser).
* `toIsoUtc('2027-03-15T08:30:15')``'2027-03-15T08:30:15.000Z'`.
* `toIsoUtc('2027-03-15T08:30:15.123')``'2027-03-15T08:30:15.123Z'`.
* `toIsoUtc(toDatetimeLocal('2027-03-15T08:30:00.000Z'))` round-trips
back to the original ISO string.
# Visual elements # Visual elements
| Element | Selector | | Element | Selector |
+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-22T14:50:25Z. they need. Last regenerated 2026-07-22T15:09:39Z.
# Architecture # Architecture