AI Implementation feature(881): Authenticated Shell, Quick Tabs and Change Password 1.05 (#20)
This commit was merged in pull request #20.
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:35:00Z
|
||||
timestamp: 2026-07-22T10:32:00Z
|
||||
---
|
||||
|
||||
# Routes
|
||||
@@ -24,13 +24,14 @@ Routes live in `frontend/src/app/app.routes.ts`:
|
||||
|
||||
| Symbol | Path | Responsibility |
|
||||
|---|---|---|
|
||||
| `HomeComponent` | `frontend/src/app/features/home/home.component.ts` | Smart shell; owns navigation signals, user hydration, change-password flow, and event-stream lifecycle. |
|
||||
| `HomeComponent` | `frontend/src/app/features/home/home.component.ts` | Smart shell; owns navigation signals, user hydration, change-password flow, event-stream lifecycle, and peer-invalidation subscription. |
|
||||
| `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; 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. |
|
||||
| `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; wires an optional `onUnauthorized` callback for the new SSE `401`/`403` event. |
|
||||
| `AuthenticatedEventSourceService` | `frontend/src/app/core/services/authenticated-event-source.service.ts` | Opens authenticated SSE over `fetch`, parsing streamed frames into `EventSourceLike` events; dispatches a separate `'unauthorized'` event for `401`/`403`. |
|
||||
| `AuthService` | `frontend/src/app/core/services/auth.service.ts` | Stores the access token used by the authenticated SSE transport; owns the cross-tab invalidation `BroadcastChannel` + `storage`-event fallback and exposes `clearAndBroadcast` / `onPeerInvalidation`. |
|
||||
| `UserStore` | `frontend/src/app/core/services/user.store.ts` | Hydrates the signed-in user and rank data. |
|
||||
| `auth-session-events.pure.ts` | `frontend/src/app/core/services/auth-session-events.pure.ts` | Pure cross-tab message encoding/validation and the namespaced channel / storage-key constants. |
|
||||
|
||||
# Authenticated SSE wiring
|
||||
|
||||
@@ -44,10 +45,17 @@ Routes live in `frontend/src/app/app.routes.ts`:
|
||||
4. Splits complete SSE records on blank lines, joins repeated `data:` lines, and
|
||||
dispatches `MessageEvent` objects.
|
||||
5. Buffers records received before the message listener is attached.
|
||||
6. Aborts and clears listeners when `close()` is called.
|
||||
6. Inspects the response status *before* the `ok`/`body` check; on `401` or
|
||||
`403` dispatches a separate `'unauthorized'` event and returns without
|
||||
reading the body. Generic transport failures still dispatch `'error'`.
|
||||
7. Aborts and clears listeners when `close()` is called.
|
||||
|
||||
`EventStatusStore` parses each message as `EventStatePayload`, updates its signals,
|
||||
and runs a one-second local timer. `HomeComponent` stops the store on destruction.
|
||||
`EventStatusStore.start(createSource, onUnauthorized?)` parses each message as
|
||||
`EventStatePayload`, updates its signals, runs a one-second local timer, and —
|
||||
when `onUnauthorized` is provided — invokes it on `'unauthorized'` events.
|
||||
`HomeComponent` passes an `onUnauthorized` callback that delegates to its
|
||||
shared `handleSessionInvalidated('sse-unauthorized')` flow and stops the store
|
||||
on destruction.
|
||||
|
||||
# Key integration files
|
||||
|
||||
@@ -84,6 +92,20 @@ 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.
|
||||
|
||||
# Cross-tab session invalidation
|
||||
|
||||
`AuthService` (constructed once at root) installs a single
|
||||
`BroadcastChannel('hipctf.auth.v1')` and a `localStorage` `storage`-event
|
||||
fallback. The shape of the broadcast payload is defined in
|
||||
`auth-session-events.pure.ts` and contains only `{ type, origin, ts }` — no
|
||||
tokens or user data. `clearAndBroadcast()` is invoked from `logout()` and
|
||||
from the SSE unauthorized callback; peer listeners clear their local state
|
||||
without rebroadcasting. `HomeComponent` subscribes via
|
||||
`auth.onPeerInvalidation(...)`, resets `UserStore`, closes any open shell
|
||||
overlays, and navigates to `/login`. See
|
||||
[Cross-Tab Authenticated Shell Invalidation](/guides/cross-tab-invalidation.md)
|
||||
for the full contract and tester matrix.
|
||||
|
||||
# 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-22T09:35:00Z
|
||||
timestamp: 2026-07-22T10:32:00Z
|
||||
---
|
||||
|
||||
# Backend
|
||||
@@ -31,14 +31,17 @@ timestamp: 2026-07-22T09:35:00Z
|
||||
| `frontend/src/app/app.routes.ts` | Defines public, shell, child, and admin routes. |
|
||||
| `frontend/src/app/app.component.ts` | Loads bootstrap data and restores the session. |
|
||||
| `frontend/src/app/features/home/home.component.ts` | Authenticated shell container; starts user and event state services. |
|
||||
| `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, pure countdown helpers, and the `LED_COLOR_BY_STATE` map used by the shell LED. |
|
||||
| `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/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. |
|
||||
| `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. |
|
||||
| `tests/frontend/authenticated-event-source.spec.ts` | Tests SSE authorization, frame transport behavior, and the `401`/`403` unauthorized path. |
|
||||
| `tests/frontend/auth-session-events.spec.ts` | Pure tests for cross-tab invalidation message encoding, payload validation, and `storage`-event filtering. |
|
||||
|
||||
# See also
|
||||
|
||||
|
||||
Reference in New Issue
Block a user