# StellaOps Web Frontend ## Mission Design and build the StellaOps web user experience that surfaces backend capabilities (Authority, Concelier, Exporters) through an offline-friendly Angular application. ## Team Composition - **UX Specialist** ??? defines user journeys, interaction patterns, accessibility guidelines, and visual design language. - **Angular Engineers** ??? implement the SPA, integrate with backend APIs, and ensure deterministic builds suitable for air-gapped deployments. ## Technology Stack - **Framework**: Angular 21 (standalone components, signals, built-in control flow) - **Language**: TypeScript 5.9 - **UI Library**: Angular Material 21 + Angular CDK 21 - **State**: Angular Signals - **Build**: `@angular/build:application` (esbuild-based) - **Unit Tests**: Vitest via `@angular/build:unit-test` builder (Jasmine compatibility shim in `src/test-setup.ts`) - **E2E Tests**: Playwright - **Storybook**: Storybook 10 with `@storybook/angular` - **Node.js**: ^20.19.0 || ^22.12.0 || ^24.0.0 ## Operating Principles - Favor modular Angular architecture (feature modules, shared UI kit) with strong typing via latest TypeScript/Angular releases. - Align UI flows with backend contracts; coordinate with Authority and Concelier teams for API changes. - Keep assets and build outputs deterministic and cacheable for Offline Kit packaging. - Coordinate cross-module changes via docs/implplan/SPRINT*.md files updates and PR descriptions. - Console admin flows use Authority `/console/admin/*` APIs and enforce fresh-auth for privileged actions. - Branding uses Authority `/console/branding` and applies only whitelisted CSS variables. ## Key Paths - `src/Web/StellaOps.Web` — Angular workspace. - `docs/` — UX specs and mockups. - `devops/compose/docker-compose.dev-ui.yml` — Dev override for zero-restart UI development. ## Local UI Development (IMPORTANT) For UI work against the Docker stack, **use the dev-ui compose override** to avoid restarting the gateway container after every build: ```bash # One-time: apply the override (bind-mounts dist/ into the gateway) cd devops/compose docker compose -f docker-compose.stella-ops.yml -f docker-compose.dev-ui.yml up -d router-gateway # Build (output goes directly to gateway's wwwroot — no copy, no restart) cd src/Web/StellaOps.Web npx ng build --configuration=development # Or use watch mode for continuous rebuilds: npx ng build --configuration=development --watch ``` After build, just **refresh the browser** — the gateway serves the new files immediately. **Without the override**, you must copy files into the Docker volume and restart: ```bash docker run --rm -v compose_console-dist:/output -v "...browser:/src:ro" alpine cp -a /src/. /output/ docker restart stellaops-router-gateway ``` This is slow and should only be used for CI/production builds. ## Reachability Drift UI (Sprint 3600) ### Components - **PathViewerComponent** (`app/features/reachability/components/path-viewer/`) - Interactive call path visualization - Displays entrypoint ??? key nodes ??? sink paths - Highlights changed nodes with change kind indicators - Supports collapse/expand for long paths - **RiskDriftCardComponent** (`app/features/reachability/components/risk-drift-card/`) - Summary card for drift analysis - Shows newly reachable / mitigated path counts - Displays associated CVEs - Action buttons for drill-down ### Models - `PathNode` - Node in a reachability path with symbol, file, line - `CompressedPath` - Compact path representation - `DriftedSink` - Sink with reachability change and cause - `DriftCause` - Explanation of why reachability changed ### Services - `DriftApiService` (`app/core/services/drift-api.service.ts`) - API client for drift endpoints - Mock implementations available for offline development ### Integration Points - Scan detail page includes PathViewer for reachability visualization - Drift results linked to DSSE attestations for evidence chain - Path export supports JSON and SARIF formats ## Witness UI (Sprint 3700) - TODO ### Planned Components - **WitnessModalComponent** - Modal for viewing witness details - **PathVisualizationComponent** - Detailed path rendering with gates - **ConfidenceTierBadgeComponent** - Tier indicators (Confirmed/Likely/Present/Unreachable) - **GateBadgeComponent** - Auth gate visualization ### Planned Services - `witness.service.ts` - API client for witness endpoints - Browser-based Ed25519 signature verification ## Coordination - Sync with DevEx for project scaffolding and build pipelines. - Partner with Docs Guild to translate UX decisions into operator guides. - Collaborate with Security Guild to validate authentication flows and session handling. ## Required Reading - `docs/modules/platform/architecture-overview.md` - `docs/technical/architecture/console-admin-rbac.md` - `docs/technical/architecture/console-branding.md` ## Working Agreement - 1. Update task status to `DOING`/`DONE` in both correspoding sprint file `/docs/implplan/SPRINT_*.md` when you start or finish work. - 2. Review this charter and the Required Reading documents before coding; confirm prerequisites are met. - 3. Keep changes deterministic (stable ordering, timestamps, hashes) and align with offline/air-gap expectations. - 4. Coordinate doc updates, tests, and cross-guild communication whenever contracts or workflows change. - 5. Revert to `TODO` if you pause the task without shipping changes; leave notes in commit/PR descriptions for context. ## No Mockups Convention (MANDATORY) All UI components **must** connect to real backend API endpoints. Never use `window.confirm()`, mock data services, or stub implementations unless explicitly requested by the product owner. **Rules:** - Every button, form submission, and action handler must call a real API endpoint - If the backend endpoint doesn't exist yet, mark the task `BLOCKED` — do not create a mock - The in-memory mock clients (e.g., `InMemoryApprovalClient`) exist ONLY for `ng serve` without backends, never as production implementations - Error states from API failures must be surfaced to the user (never silently swallow errors) - If an API returns 404/500, show the error in a banner or toast — don't pretend the action succeeded ## Destructive Action Convention (MANDATORY) All destructive actions (delete, revoke, purge, reset) **must** use `` — never `window.confirm()` or unguarded inline handlers. **Rules:** - Every destructive button must open a styled `` with `variant="danger"` before executing - The confirm dialog message must name the resource being destroyed (e.g., "Delete script 'Pre-deploy Health Check'?") - Include "This cannot be undone." or equivalent irreversibility warning when applicable - Never perform destructive API calls directly from a `(click)` handler without confirmation **Pattern:** ```html ``` ## Truncated Text Convention (MANDATORY) All text that may be truncated by CSS (`text-overflow: ellipsis`, table cell overflow, or max-width constraints) **must** have a `[title]` attribute binding to the full untruncated text. **Rules:** - Table cells with descriptions, names, digests, or IDs that truncate must include `[title]="fullValue"` - Metric card labels already have `[title]="label"` (built into `stella-metric-card`) — do not add a second one - For dynamically computed truncation, prefer `[title]` over custom tooltip directives for simplicity and offline compatibility - Ensure tooltips are also applied to `` and `` elements inside table cells when they use `text-overflow: ellipsis` ## Promote Button Convention (MANDATORY) The Promote button on release detail pages must follow a three-state model: 1. **Hidden** — no further promotion path exists (single-environment release, or already at the final environment in the promotion graph) 2. **Disabled** — promotion path exists but preconditions are not met: - Release is not yet deployed on the current environment (status = `draft`) - Blocking gates are unresolved - Tooltip must explain why promotion is disabled 3. **Enabled** — release is deployed, gates are clear, and a next environment exists Use `showPromote` (computed, boolean) for visibility and `canPromote` (computed, boolean) for the enabled/disabled state. Use `promoteDisabledReason` (computed, string | null) for the disabled tooltip. ## Quick Links Convention (MANDATORY) All pages that include navigational quick links **must** follow these rules: 1. Use the `` component — never raw `