AI Implementation feature(880): Authenticated Shell, Quick Tabs and Change Password 1.04 (#19)
This commit was merged in pull request #19.
This commit is contained in:
@@ -3,7 +3,7 @@ type: architecture
|
||||
title: Frontend Structure
|
||||
description: Angular routes, components, services, guards, interceptors, and authenticated SSE transport.
|
||||
tags: [architecture, frontend, angular, shell, sse]
|
||||
timestamp: 2026-07-22T09:22:34Z
|
||||
timestamp: 2026-07-22T09:35:00Z
|
||||
---
|
||||
|
||||
# Routes
|
||||
@@ -27,7 +27,7 @@ Routes live in `frontend/src/app/app.routes.ts`:
|
||||
| `HomeComponent` | `frontend/src/app/features/home/home.component.ts` | Smart shell; owns navigation signals, user hydration, change-password flow, and event-stream lifecycle. |
|
||||
| `ShellHeaderComponent` | `frontend/src/app/features/shell/header/shell-header.component.ts` | Renders title, active section, event LED/countdown, and user menu; contains component-scoped LED styling. |
|
||||
| `QuickTabsComponent` | `frontend/src/app/features/shell/tabs/quick-tabs.component.ts` | Emits navigation events for Challenges, Scoreboard, and Blog. |
|
||||
| `EventStatusStore` | `frontend/src/app/core/services/event-status.store.ts` | Applies event state frames and computes countdown text. |
|
||||
| `EventStatusStore` | `frontend/src/app/core/services/event-status.store.ts` | Applies event state frames and computes countdown text; re-exports the pure LED color mapping. |
|
||||
| `AuthenticatedEventSourceService` | `frontend/src/app/core/services/authenticated-event-source.service.ts` | Opens authenticated SSE over `fetch`, parsing streamed frames into `EventSourceLike` events. |
|
||||
| `AuthService` | `frontend/src/app/core/services/auth.service.ts` | Stores the access token used by the authenticated SSE transport. |
|
||||
| `UserStore` | `frontend/src/app/core/services/user.store.ts` | Hydrates the signed-in user and rank data. |
|
||||
@@ -59,6 +59,31 @@ and runs a one-second local timer. `HomeComponent` stops the store on destructio
|
||||
| `frontend/src/app/core/services/event-status.pure.ts` | Defines the event payload and transport interface. |
|
||||
| `tests/frontend/authenticated-event-source.spec.ts` | Regression coverage for authenticated SSE transport behavior. |
|
||||
|
||||
# Event-status pure helpers
|
||||
|
||||
`frontend/src/app/core/services/event-status.pure.ts` owns the small,
|
||||
no-Angular types and pure functions consumed by the event status pipeline.
|
||||
`EventStatusStore` re-exports them so application code can import from a
|
||||
single path.
|
||||
|
||||
| Export | Purpose |
|
||||
|---|---|
|
||||
| `EventState` | Union `'running' \| 'countdown' \| 'stopped' \| 'unconfigured'`. |
|
||||
| `EventStatePayload` | Server-pushed event window payload shape. |
|
||||
| `EventSourceLike` | Minimal interface for any SSE transport the store can drive. |
|
||||
| `formatDdHhMm(seconds)` | Pure `DD:HH:mm` formatter. |
|
||||
| `deriveCountdownText(state, start, end)` | Pure mapping from event window state to countdown label. |
|
||||
| `LED_COLOR_BY_STATE` | `Readonly<Record<EventState, string>>` mapping each state to its theme CSS variable (`var(--color-success)`, `--color-warning`, `--color-danger`, `--color-secondary`). |
|
||||
| `ledBackgroundColor(state)` | Pure accessor returning the `background-color` value for the LED element. |
|
||||
|
||||
`ShellHeaderComponent` exposes a `computed` signal `ledColor()` that calls
|
||||
`ledBackgroundColor(this.eventState())` and binds it to the LED via
|
||||
`[style.background-color]`. The component's `.led` base rule is therefore
|
||||
shape-only (size, radius, `inline-block`, vertical alignment); the visible
|
||||
color always comes from `LED_COLOR_BY_STATE` and is guaranteed to be a
|
||||
non-transparent theme token. The four `led-<state>` classes remain on the
|
||||
element as selectors/test hooks but no longer own the color.
|
||||
|
||||
# See also
|
||||
|
||||
- [Authenticated Shell](/guides/authenticated-shell.md)
|
||||
|
||||
@@ -3,7 +3,7 @@ type: architecture
|
||||
title: Key Files Index
|
||||
description: One-line responsibility for important source files, including authenticated event streaming.
|
||||
tags: [architecture, index, key-files]
|
||||
timestamp: 2026-07-21T23:25:00Z
|
||||
timestamp: 2026-07-22T09:35:00Z
|
||||
---
|
||||
|
||||
# Backend
|
||||
@@ -34,8 +34,8 @@ timestamp: 2026-07-21T23:25:00Z
|
||||
| `frontend/src/app/core/services/auth.service.ts` | Signal-backed access token and current-user state. |
|
||||
| `frontend/src/app/core/services/authenticated-event-source.service.ts` | Fetch-based authenticated SSE transport with frame parsing and abort support. |
|
||||
| `frontend/src/app/core/services/event-status.store.ts` | Event state signal store and one-second countdown timer. |
|
||||
| `frontend/src/app/core/services/event-status.pure.ts` | Event payload types and pure countdown helpers. |
|
||||
| `frontend/src/app/features/shell/header/shell-header.component.ts` | Shell title, status LED, countdown, and user menu. |
|
||||
| `frontend/src/app/core/services/event-status.pure.ts` | Event payload types, pure countdown helpers, and the `LED_COLOR_BY_STATE` map used by the shell LED. |
|
||||
| `frontend/src/app/features/shell/header/shell-header.component.ts` | Shell title, status LED (size/shape only — color comes from the pure map via `[style.background-color]`), countdown, and user menu. |
|
||||
| `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. |
|
||||
| `tests/frontend/authenticated-event-source.spec.ts` | Tests SSE authorization and frame transport behavior. |
|
||||
|
||||
@@ -3,7 +3,7 @@ type: guide
|
||||
title: Authenticated Shell
|
||||
description: How a signed-in user experiences the post-login shell, including authenticated event streaming.
|
||||
tags: [guide, shell, header, sse, navigation, tester]
|
||||
timestamp: 2026-07-22T09:22:34Z
|
||||
timestamp: 2026-07-22T09:35:00Z
|
||||
---
|
||||
|
||||
# When this view is available
|
||||
@@ -35,20 +35,29 @@ before the shell mounts.
|
||||
|
||||
# Event LED colors
|
||||
|
||||
The LED is rendered by `ShellHeaderComponent` as a `<span class="led">` with one of four state classes attached via `[class.led-<state>]`. Its component-scoped styling is declared in `frontend/src/app/features/shell/header/shell-header.component.ts` and is driven entirely by the existing theme color tokens — there is no per-state color in TypeScript.
|
||||
The LED is rendered by `ShellHeaderComponent` as a `<span class="led">` with one of four state classes attached via `[class.led-<state>]` and a `[style.background-color]` bound directly from a pure TypeScript helper.
|
||||
|
||||
| Event state | CSS class | Color token | Approx. hex | Visual |
|
||||
|-------------------|-----------------------|-----------------------|-------------|--------|
|
||||
| `countdown` | `led led-countdown` | `--color-warning` | `#f59e0b` | Yellow filled dot |
|
||||
| `running` | `led led-running` | `--color-success` | `#10b981` | Green filled dot |
|
||||
| `stopped` | `led led-stopped` | `--color-danger` | `#ef4444` | Red filled dot |
|
||||
| `unconfigured` | `led led-unconfigured`| `--color-secondary` | `#64748b` | Neutral gray filled dot |
|
||||
| Event state | CSS class | Color token (`[style.background-color]` value) | Approx. hex | Visual |
|
||||
|-------------------|-----------------------|------------------------------------------------|-------------|--------|
|
||||
| `countdown` | `led led-countdown` | `var(--color-warning)` | `#f59e0b` | Yellow filled dot |
|
||||
| `running` | `led led-running` | `var(--color-success)` | `#10b981` | Green filled dot |
|
||||
| `stopped` | `led led-stopped` | `var(--color-danger)` | `#ef4444` | Red filled dot |
|
||||
| `unconfigured` | `led led-unconfigured`| `var(--color-secondary)` | `#64748b` | Neutral gray filled dot |
|
||||
|
||||
The mapping is defined in [`frontend/src/app/core/services/event-status.pure.ts`](/architecture/frontend-structure.md#event-status-pure-helpers) as the constant `LED_COLOR_BY_STATE` and exposed through the helper `ledBackgroundColor(state)`. `ShellHeaderComponent` exposes it on the DOM via a `computed` signal called `ledColor()`, so the active theme token resolves at runtime and the LED is never painted with `transparent`.
|
||||
|
||||
The base `.led` rule paints a 10×10 circular `inline-block`, so the LED
|
||||
is always the same size and shape — only the background color changes
|
||||
between states. The element also carries
|
||||
`aria-label="Event status: <state>"` for assistive tech.
|
||||
|
||||
# What the tester should see
|
||||
|
||||
* The 10×10 LED is visible (not transparent, not invisible) in every state.
|
||||
* The LED color matches the table above for the active `EventState`.
|
||||
* Switching the event window (countdown → running → stopped → unconfigured) flips the dot color in real time.
|
||||
* The `aria-label` updates to `Event status: <state>` and never relies on color alone.
|
||||
|
||||
## Quick tabs
|
||||
|
||||
The tab strip `[data-testid="quick-tabs"]` contains `Challenges`, `Scoreboard`, and
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
---
|
||||
type: guide
|
||||
title: Event LED Color Mapping
|
||||
description: Single source of truth mapping each event window state to the themed background color painted on the authenticated shell's status LED.
|
||||
tags: [guide, shell, led, theming, event-window, tester]
|
||||
timestamp: 2026-07-22T09:35:00Z
|
||||
---
|
||||
|
||||
# Purpose
|
||||
|
||||
The 10×10 status dot in the authenticated shell LED
|
||||
(`[data-testid="shell-led"]` in
|
||||
[`ShellHeaderComponent`](/architecture/frontend-structure.md)) reflects the
|
||||
current event window state. Its background color is driven by a single pure
|
||||
helper so the dot is **never transparent** and the active theme token always
|
||||
resolves at runtime.
|
||||
|
||||
# Mapping
|
||||
|
||||
Defined in
|
||||
`frontend/src/app/core/services/event-status.pure.ts` and re-exported via
|
||||
`frontend/src/app/core/services/event-status.store.ts`:
|
||||
|
||||
| `EventState` | `ledBackgroundColor(state)` | Theme CSS variable |
|
||||
|--------------|------------------------------|------------------------|
|
||||
| `countdown` | `var(--color-warning)` | `--color-warning` |
|
||||
| `running` | `var(--color-success)` | `--color-success` |
|
||||
| `stopped` | `var(--color-danger)` | `--color-danger` |
|
||||
| `unconfigured` | `var(--color-secondary)` | `--color-secondary` |
|
||||
|
||||
Backing constant: `LED_COLOR_BY_STATE: Readonly<Record<EventState, string>>`.
|
||||
The accessor function `ledBackgroundColor(state)` returns the same string for
|
||||
each state.
|
||||
|
||||
# How it reaches the DOM
|
||||
|
||||
1. `HomeComponent` forwards the `state` signal from
|
||||
[`EventStatusStore`](/architecture/frontend-structure.md) to
|
||||
`ShellHeaderComponent` via its `eventState` input.
|
||||
2. `ShellHeaderComponent.ledColor` is a `computed` signal defined as
|
||||
`computed(() => ledBackgroundColor(this.eventState()))`.
|
||||
3. The template binds it directly:
|
||||
`[style.background-color]="ledColor()"`.
|
||||
4. The LED's base `.led` rule is shape-only (`inline-block`, 10×10, circular,
|
||||
`vertical-align: middle`); no `transparent` fallback is applied, so the
|
||||
author background color is always visible.
|
||||
5. The legacy `.led-running`, `.led-countdown`, `.led-stopped`,
|
||||
`.led-unconfigured` CSS selectors remain on the element and continue to be
|
||||
useful hooks for selectors and tests, but they no longer declare the color.
|
||||
|
||||
# Examples
|
||||
|
||||
## Programmatic lookup
|
||||
|
||||
```ts
|
||||
import { ledBackgroundColor, LED_COLOR_BY_STATE } from
|
||||
'./frontend/src/app/core/services/event-status.pure';
|
||||
|
||||
ledBackgroundColor('running'); // 'var(--color-success)'
|
||||
ledBackgroundColor('stopped'); // 'var(--color-danger)'
|
||||
LED_COLOR_BY_STATE.unconfigured; // 'var(--color-secondary)'
|
||||
```
|
||||
|
||||
## Verifying in the DOM
|
||||
|
||||
```ts
|
||||
const dot = document.querySelector('[data-testid="shell-led"]') as HTMLElement;
|
||||
dot.style.backgroundColor; // resolves to the current theme token, never empty
|
||||
dot.getAttribute('aria-label'); // 'Event status: running'
|
||||
```
|
||||
|
||||
# Tester checklist
|
||||
|
||||
* The LED is **visible** in every state (no transparent or missing dot).
|
||||
* The LED color matches the mapping table when the event window is forced
|
||||
into each state via the [event window settings](/guides/event-window.md).
|
||||
* Switching states live updates both the dot color and the
|
||||
`aria-label="Event status: <state>"` attribute.
|
||||
* The four `led-<state>` classes are still applied to the element.
|
||||
|
||||
# See also
|
||||
|
||||
- [Authenticated Shell](/guides/authenticated-shell.md)
|
||||
- [Event Window](/guides/event-window.md)
|
||||
- [Frontend Structure](/architecture/frontend-structure.md)
|
||||
- [Theming](/guides/theming.md)
|
||||
+3
-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-22T09:22:34Z.
|
||||
they need. Last regenerated 2026-07-22T09:35:00Z.
|
||||
|
||||
# Architecture
|
||||
|
||||
@@ -75,5 +75,7 @@ they need. Last regenerated 2026-07-22T09:22:34Z.
|
||||
* [Theming](/guides/theming.md) - How themes are loaded and applied.
|
||||
* [Event Window](/guides/event-window.md) - How the 4-state event
|
||||
window and live countdown work, including the authenticated SSE stream.
|
||||
* [Event LED Color Mapping](/guides/event-led-colors.md) - Source of
|
||||
truth for the shell status dot's color in each `EventState`.
|
||||
* [Scoreboard Stream](/guides/scoreboard-stream.md) - How live solves are
|
||||
broadcast to clients.
|
||||
|
||||
Reference in New Issue
Block a user