From ae159f4f73bbcf3ad22d4c1c2a04681de03ffcea Mon Sep 17 00:00:00 2001 From: OpenVelo Agent Date: Wed, 22 Jul 2026 16:16:20 +0000 Subject: [PATCH] docs: update documentation to OKF v0.1 format --- docs/api/system.md | 14 +++++++++++--- docs/architecture/key-files.md | 8 +++++--- docs/guides/landing-page.md | 31 ++++++++++++++++++++++++++++--- docs/index.md | 2 +- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/docs/api/system.md b/docs/api/system.md index 101db53..3615c1e 100644 --- a/docs/api/system.md +++ b/docs/api/system.md @@ -1,9 +1,9 @@ --- type: api title: System Endpoints -description: Bootstrap payload, public event status, public/authenticated SSE streams, and public event-window timestamps. -tags: [api, system, bootstrap, event, sse, settings] -timestamp: 2026-07-22T13:40:00Z +description: Bootstrap payload, public event status, public/authenticated SSE streams, and public event-window timestamps; the public `event/stream` also forwards `general` topic frames carrying `registrationsEnabled`. +tags: [api, system, bootstrap, event, sse, settings, registrations] +timestamp: 2026-07-22T16:15:00Z --- # Endpoints @@ -130,6 +130,14 @@ Public, flattened event stream that emits the legacy payload shape 1-second tick and on hub pushes. Preserved for backward compatibility with the original landing page status badge. +`admin/general` updates are also broadcast on this stream as +`{ topic: 'general', themeKey, registrationsEnabled }` so the public +landing page can refresh its cached bootstrap whenever an admin toggles +the registrations flag (or any other general setting) without forcing +the user to hard-refresh. The frame is interleaved with the legacy +event-status frames. The legacy event-status frames are still emitted +on the 1-second tick so existing consumers are unaffected. + # `GET /api/v1/scoreboard/stream` Public SSE stream that pushes a flattened solve payload whenever a new diff --git a/docs/architecture/key-files.md b/docs/architecture/key-files.md index 9356b0a..4c9816e 100644 --- a/docs/architecture/key-files.md +++ b/docs/architecture/key-files.md @@ -1,9 +1,9 @@ --- type: architecture title: Key Files Index -description: One-line responsibility for important source and contract-test files, including strict event-window validation. -tags: [architecture, key-files, event-window, validation, default-challenge-ip] -timestamp: 2026-07-22T15:46:18Z +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] +timestamp: 2026-07-22T16:15:00Z --- # Backend @@ -42,6 +42,8 @@ timestamp: 2026-07-22T15:46:18Z | `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. | | `frontend/src/app/core/services/event-status.pure.ts` | Event payload types, transport interface (including `'unauthorized'` listener), pure countdown helpers, 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. | diff --git a/docs/guides/landing-page.md b/docs/guides/landing-page.md index 30c44c5..608b812 100644 --- a/docs/guides/landing-page.md +++ b/docs/guides/landing-page.md @@ -1,9 +1,9 @@ --- type: guide title: Landing Page -description: How the public landing page renders, how the login + registration modal is opened, and what each form does. -tags: [guide, landing, login, register, ui] -timestamp: 2026-07-21T18:45:54Z +description: How the public landing page renders, how the login + registration modal is opened, what each form does, and how the modal stays in sync with admin `registrationsEnabled` changes via SSE. +tags: [guide, landing, login, register, ui, sse, bootstrap] +timestamp: 2026-07-22T16:15:00Z --- # What you see @@ -90,6 +90,31 @@ The modal is dismissible via the **×** button (`landing-modal-close`), clicking the overlay backdrop, or pressing `Escape`. Submit-in-flight dismissal is suppressed. +# Reacting to admin changes + +The Login/Register modal reflects the value of +`bootstrap.payload().registrationsEnabled`, which is loaded once at app +boot by `BootstrapService.load()`. Two paths keep the modal consistent +with the API: + +1. `LandingComponent.ngOnInit()` calls `BootstrapService.refresh()` so + the public landing page always fetches the latest bootstrap payload + before rendering the modal. This covers users who reach `/login` + via a hard refresh or fresh tab and have not previously subscribed to + the SSE channel. +2. `BootstrapEventService` (started by `AppComponent.ngOnInit`) opens + the public `GET /api/v1/event/stream` SSE channel and listens for + `{ topic: 'general' }` frames. Whenever the admin saves a setting via + `PUT /api/v1/admin/general/settings`, the backend emits a `general` + hub event with `themeKey` and `registrationsEnabled`; the public SSE + forwards it on `/api/v1/event/stream` and the SPA calls + `BootstrapService.refresh()` to re-apply the new flag (and theme). + +The pure helper `landingModalShowsRegister(registrationsEnabled)` in +`frontend/src/app/features/landing/login-modal.service.ts` mirrors the +HTML predicate and is asserted in +`tests/frontend/landing-modal.spec.ts`. + # Server error code → user copy `buildLoginFailureMessage` (`frontend/src/app/features/landing/login-modal.service.ts`) diff --git a/docs/index.md b/docs/index.md index 97fa4b6..dad838f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,7 +11,7 @@ scoreboard, an event window with a public countdown, theming, and admin controls. The docs below are organized by purpose so agents can pull just the slice -they need. Last regenerated 2026-07-22T15:46:18Z. +they need. Last regenerated 2026-07-22T16:15:00Z. # Architecture