--- 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 --- # When this view is available The authenticated shell is the post-login UI rendered by `HomeComponent` (`frontend/src/app/features/home/home.component.ts`). It is gated by the client `authGuard` and the JWT-protected `/api/v1/events/status` stream. A user who is not signed in, or whose session has expired, is sent to `/login` before the shell mounts. # How to access (tester steps) 1. Ensure the instance is initialized. If not, follow [First-Run Bootstrap](/guides/bootstrap.md). 2. Sign in via `/login` as an admin or player. 3. Confirm the browser lands on `/challenges` and renders the shell. # Expected behavior ## Header | Element | Selector | Expected | |---|---|---| | Page title | `[data-testid="shell-title"]` | Shows the bootstrap `pageTitle`; clicking navigates to `/challenges`. | | Active section | `[data-testid="shell-active-section"]` | Shows `Challenges`, `Scoreboard`, `Blog`, or `Admin` based on the URL. | | Event LED | `[data-testid="shell-led"]` | A 10×10 circular dot whose color reflects the current event state. See [Event LED colors](#event-led-colors) below. | | Countdown | `[data-testid="shell-countdown"]` | Displays `DD:HH:mm`, `Event ended`, or empty for an unconfigured event. | | User menu | `[data-testid="user-menu-trigger"]` | Toggles rank, change-password, optional admin, and logout entries. | # Event LED colors The LED is rendered by `ShellHeaderComponent` as a `` with one of four state classes attached via `[class.led-]`. 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. | 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 | 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: "` for assistive tech. ## Quick tabs The tab strip `[data-testid="quick-tabs"]` contains `Challenges`, `Scoreboard`, and `Blog`. Clicking a tab navigates to its matching route; the active tab is marked with the active class. # Live event window 1. `HomeComponent.ngOnInit()` starts `EventStatusStore` with `AuthenticatedEventSourceService.open('/api/v1/events/status')`. 2. The transport uses `fetch`, sends `Accept: text/event-stream`, includes `Authorization: Bearer ` when available, and sends credentials. 3. It parses SSE `event:` and `data:` lines, buffers frames until a message listener is registered, and dispatches `MessageEvent` payloads. 4. The store applies each state frame and advances countdown values with a local one-second tick between server pushes. 5. Leaving the shell closes the source, aborts the fetch, and clears the tick. A failed HTTP response, missing stream body, or streaming failure dispatches an error event. The shell retains the last event state until a later connection succeeds. # Architecture map | File | Responsibility | |---|---| | `frontend/src/app/features/home/home.component.ts` | Hosts the shell and starts/stops the authenticated event stream. | | `frontend/src/app/core/services/authenticated-event-source.service.ts` | Fetch-based authenticated SSE transport with abort and frame parsing. | | `frontend/src/app/core/services/event-status.store.ts` | Applies event frames and derives the live countdown. | | `frontend/src/app/features/shell/header/shell-header.component.ts` | Renders event LED, countdown, navigation, and user menu; owns the component-scoped LED shape and state color rules. | | `frontend/src/styles.css` | Defines the shared theme color tokens consumed by the shell LED. | | `frontend/src/app/features/shell/tabs/quick-tabs.component.ts` | Renders the main navigation tabs. | | `tests/frontend/authenticated-event-source.spec.ts` | Verifies authorization headers, SSE frame delivery, and anonymous header omission. | # Tester flows ## Live event window 1. Configure a future start time and confirm the countdown LED and text appear. 2. Move the start time into the past and the end time into the future; confirm the LED changes to running and the countdown counts toward the end. 3. Move the end time into the past; confirm `Event ended` and the stopped LED. 4. Remove either setting; confirm the unconfigured LED and empty countdown. ## Navigation and logout 1. Click each quick tab and confirm the matching route and active styling. 2. Open the user menu and click **Logout**. 3. Confirm navigation to `/login` and that the event stream is closed. # See also - [Event Window](/guides/event-window.md) - [System Endpoints](/api/system.md) - [Frontend Structure](/architecture/frontend-structure.md) - [Change Password](/guides/change-password.md)