AI Implementation feature(892): Admin Area General Settings and Categories 1.10 #32
+11
-3
@@ -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
|
||||
|
||||
@@ -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. |
|
||||
|
||||
@@ -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`)
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user