User Flow Architecture

This document traces how users interact with StellaOps end to end — from the Web UI, CLI, and CI/CD surfaces, through the Gateway, to the backend services and stores. Each flow is documented from the user’s perspective and annotated with the gateway-facing endpoints and backing modules involved, so the diagrams double as a routing reference.

It is written for engineers integrating with the platform and for operators tracing a request path during triage. The diagrams are ASCII schematics, not formal UML; treat endpoint paths as the shape of the surface and verify exact verbs/paths against the gateway route table (src/Router/StellaOps.Gateway.WebService/appsettings.json) and the Webservice Catalog.

Primary user paths:

UserFlow emphasis
CTORead-only deployment/compliance posture, evidence, and audit reconstruction.
DevOpsTopology, release movement, approvals, deployment execution, and recovery.
Security managerFindings, security risk, VEX, exceptions, and policy gate impact.
DeveloperOwned microservice image updates to allowed environments, or promotion requests when approval is required.

Table of Contents


1. Architecture Overview

Layered Architecture Diagram

+-----------------------------------------------------------------------------------------------------------+
|                                         USER EXPERIENCE LAYER                                             |
+-----------------------------------------------------------------------------------------------------------+
|                                                                                                           |
|   +----------------+     +----------------+     +----------------+                                        |
|   |   Web UI       |     |     CLI        |     |   CI/CD        |                                        |
|   |  (Angular 21)  |     | (Native AOT)   |     |  (BuildX)      |                                        |
|   +-------+--------+     +-------+--------+     +-------+--------+                                        |
|           |                      |                      |                                                 |
|           +----------------------+----------------------+                                                 |
|                                  | HTTPS + DPoP/mTLS                                                      |
|                                  v                                                                        |
|   +-------------------------------------------------------------------------------------------+           |
|   |                                    GATEWAY (API Router)                                   |           |
|   |  +---------------+ +---------------+ +---------------+ +---------------+ +-------------+ |           |
|   |  |CorrelationId  |>| DPoP/mTLS     |>|IdentityHeader |>| Authorization |>|Routing      | |           |
|   |  | Middleware    | | Validation    | | Policy        | | Middleware    | |Decision     | |           |
|   |  +---------------+ +---------------+ +---------------+ +---------------+ +-------------+ |           |
|   |                                         |                                                |           |
|   |                            +------------+------------+                                   |           |
|   |                            v                         v                                   |           |
|   |                   Token Validation           Binary Frame Protocol                       |           |
|   |                   via Authority              (TCP/TLS/Valkey)                            |           |
|   +-------------------------------------------------------------------------------------------+           |
|                                                                                                           |
+-----------------------------------------------------------------------------------------------------------+
                                                    |
              +------------------+------------------+------------------+------------------+
              v                  v                  v                  v                  v
+-----------------------------------------------------------------------------------------------------------+
|                                         MICROSERVICES LAYER                                               |
+-----------------------------------------------------------------------------------------------------------+
|                                                                                                           |
|  +------------------+  +------------------+  +------------------+  +------------------+  +--------------+ |
|  |   AUTHORITY      |  |    SCANNER       |  |    POLICY        |  |   CONCELIER      |  |  EXCITITOR   | |
|  | (OAuth/OIDC)     |  | (SBOM Gen)       |  | (Decisions)      |  | (Advisories)     |  | (VEX Ingest) | |
|  +------------------+  +------------------+  +------------------+  +------------------+  +--------------+ |
|  | * DPoP tokens    |  | * WebService     |  | * K4 Lattice     |  | * NVD/OSV/GHSA   |  | * OpenVEX    | |
|  | * mTLS certs     |  | * Worker pool    |  | * Confidence     |  | * CSAF sources   |  | * CSAF VEX   | |
|  | * Scopes/RBAC    |  | * 11 analyzers   |  | * Gates          |  | * Linksets       |  | * Consensus  | |
|  | * Tenant mgmt    |  | * Call graphs    |  | * VEX emission   |  | * AOC enforced   |  | * Signatures | |
|  +--------+---------+  +--------+---------+  +--------+---------+  +--------+---------+  +------+-------+ |
|           |                    |                    |                    |                      |         |
|           |    +---------------+--------------------+--------------------+----------------------+         |
|           |    |               |                    |                    |                                |
|           v    v               v                    v                    v                                |
|  +--------------------------------------------------------------------------------------------+           |
|  |                              EVENT BUS (Valkey Streams / NATS JetStream)                   |           |
|  |  scanner:events | concelier:drift | policy:evaluated | notify:delivery | scheduler:jobs    |           |
|  +--------------------------------------------------------------------------------------------+           |
|           |                    |                    |                    |                                |
|           v                    v                    v                    v                                |
|  +------------------+  +------------------+  +------------------+  +------------------+                   |
|  |   SCHEDULER      |  |    NOTIFY        |  |   ATTESTOR       |  |  EXPORTCENTER    |                   |
|  | (Job Orch)       |  | (Notifications)  |  | (DSSE/in-toto)   |  | (SARIF/SBOM)     |                   |
|  +------------------+  +------------------+  +------------------+  +------------------+                   |
|  | * Cron jobs      |  | * Slack/Teams    |  | * DSSE envelope  |  | * Format conv    |                   |
|  | * Delta rescan   |  | * Email/Webhook  |  | * Rekor v2 log   |  | * Batch export   |                   |
|  | * Lease/backoff  |  | * Templates      |  | * Verify chain   |  | * Evidence zip   |                   |
|  +------------------+  +------------------+  +--------+---------+  +------------------+                   |
|                                                      |                                                    |
|                                                      v                                                    |
|                                             +------------------+                                          |
|                                             |     SIGNER       |                                          |
|                                             | (Crypto Ops)     |                                          |
|                                             +------------------+                                          |
|                                             | * PKIX signing   |                                          |
|                                             | * FIPS/eIDAS     |                                          |
|                                             | * GOST/SM/PQ     |                                          |
|                                             +------------------+                                          |
|                                                                                                           |
+-----------------------------------------------------------------------------------------------------------+
                                                    |
                                                    v
+-----------------------------------------------------------------------------------------------------------+
|                                         PERSISTENCE LAYER                                                 |
+-----------------------------------------------------------------------------------------------------------+
|                                                                                                           |
|  +----------------------------------------------+    +----------------------------------------------+     |
|  |            PostgreSQL v16+                   |    |         RustFS (S3 API)                      |     |
|  |                                              |    |                                              |     |
|  |  Schema: authority (identity, clients, keys) |    |  blobs/{sha256}/sbom.json                    |     |
|  |  Schema: scanner (manifests, triage)         |    |  blobs/{sha256}/sbom.cdx.pb                  |     |
|  |  Schema: vuln (advisory_raw, linksets)       |    |  blobs/{sha256}/attestation.dsse             |     |
|  |  Schema: vex (vex_raw, consensus)            |    |  blobs/{sha256}/evidence.bundle              |     |
|  |  Schema: policy (exceptions, findings)       |    |                                              |     |
|  |  Schema: scheduler (jobs, runs)              |    |                                              |     |
|  |  Schema: notify (rules, channels, history)   |    |                                              |     |
|  |  Schema: orchestrator (workflows)            |    |                                              |     |
|  +----------------------------------------------+    +----------------------------------------------+     |
|                                                                                                           |
|  +----------------------------------------------+                                                         |
|  |            Valkey v8.0 (Cache/Queue)          |                                                         |
|  |                                              |                                                         |
|  |  scan:{digest} -> Last scan result           |                                                         |
|  |  layers:{digest} -> Delta cache (90d TTL)    |                                                         |
|  |  dpop:{jti} -> DPoP nonce (5m TTL)           |                                                         |
|  |  queue:* -> Task streams                     |                                                         |
|  |  events:* -> Event streams (7d TTL)          |                                                         |
|  +----------------------------------------------+                                                         |
|                                                                                                           |
+-----------------------------------------------------------------------------------------------------------+

2. Dashboard Data Flow

When a user opens the Web UI dashboard, the following data flow occurs:

User opens Web UI (Angular)
         |
         v
+--------------------------------------------------------------------------------------------+
|  HomeDashboardComponent (src/Web/StellaOps.Web/src/app/features/home/)                     |
|                                                                                            |
|  +--------------------------------------------------------------------------------------+  |
|  |  forkJoin({                                                                          |  |
|  |    vulnFacets:     ConsoleVulnApi.getFacets()  -> Severity/VEX/reachability facets    |  |
|  |    riskStats:      RiskApi.stats()             -> Risk counts (governance profiles)    |  |
|  |    riskAggregated: RiskApi.getAggregatedStatus()-> Overall score + trend              |  |
|  |    reachability:   ReachabilityApi.getSummary('latest')-> Reachable/Unreachable/...   |  |
|  |  })  // per-source catchError; failures degrade to null, not a hard failure          |  |
|  +--------------------------------------------------------------------------------------+  |
|                              |                                                             |
|                              | HTTPS                                                       |
|                              v                                                             |
|  +--------------------------------------------------------------------------------------+  |
|  |                          GATEWAY (routes by path)                                    |  |
|  |                                                                                      |  |
|  |  /api/console/vuln/facets       -> Platform.WebService (Console aggregation)         |  |
|  |  /api/risk(.*) , /api/v1/governance/risk-profiles -> Policy Engine                   |  |
|  |  /api/risk/aggregated-status    -> Platform.WebService                               |  |
|  |  /scans/{scanId}/reachability/summary -> Scanner.WebService                          |  |
|  +--------------------------------------------------------------------------------------+  |
|                              |                                                             |
|                              v                                                             |
|  +--------------------------------------------------------------------------------------+  |
|  |  Dashboard Widgets Rendered:                                                         |  |
|  |  +------------+ +------------+ +------------+ +------------+                         |  |
|  |  | Severity   | | Risk Score | |Reachability| | VEX Impact |                         |  |
|  |  | Breakdown  | | & Trend    | | Donut      | | Rate*      |                         |  |
|  |  +------------+ +------------+ +------------+ +------------+                         |  |
|  |  * VEX Impact is derived client-side from the vexState facets in the same           |  |
|  |    getFacets() response (suppressed = not_affected + fixed); it does NOT call a      |  |
|  |    dedicated suppression-rate endpoint.                                              |  |
|  +--------------------------------------------------------------------------------------+  |
+--------------------------------------------------------------------------------------------+

Data Sources (resolved behind the gateway / Console aggregation):
  - Console vuln facets   -> severity, vexState, and reachability counts (one call)
  - Governance risk profiles + aggregated status -> risk counts, overall score, trend
  - Scanner reachability summary -> reachable / unreachable / uncertain CVE counts

Note: the home-dashboard.service.ts forkJoin wraps every source in a catchError that maps failures to null, so a widget renders empty rather than failing the whole dashboard. The dashboard auto-refreshes every 60s.

Dashboard API Endpoints

The Console clients call these gateway-facing paths (the gateway rewrites them to the backing service shown in the Module column — see appsettings.json route table):

WidgetAPI Endpoint (as called by the Console)Backing moduleNotes
Severity BreakdownGET /api/console/vuln/facetsPlatform (Console aggregation)CONSOLE_API_BASE_URL = /api/console
Risk Score & TrendGET /api/v1/governance/risk-profiles (+ GET /api/risk/aggregated-status)Policy Engine + PlatformRiskHttpClient.stats() derives counts from the governance profile list; there is no /api/risk/stats endpoint.
Reachability DonutGET /scans/{scanId}/reachability/summary (scanId latest)Scanner.WebServiceReached via the Scanner base URL, NOT /api/reachability/summary.
VEX Impact Rate(none — computed client-side from vexState facets)No /api/vex/suppression-rate endpoint is called.

3. Scan Submission Flow

CLI/API Scan Submission

User: stellaops scan --image registry.example.com/app:v1.0
         |
         v
+--------------------------------------------------------------------------------------------+
|  POST /api/v1/scans/                                                                       |
|  {                                                                                         |
|    "image": { "reference": "registry.example.com/app:v1.0" },                              |
|    "metadata": { "tenant": "alpha" }                                                       |
|  }                                                                                         |
+--------------------------------------------------------------------------------------------+
         |
         v
+--------------------------------------------------------------------------------------------+
|  Scanner.WebService                                                                        |
|    1. Validate request (ref OR digest required)                                            |
|    2. Normalize ScanTarget                                                                 |
|    3. Create ScanManifest in PostgreSQL (scanner schema)                                   |
|    4. Enqueue job to Valkey Streams (scanner:jobs)                                         |
|    5. Return 202 Accepted + scanId                                                         |
+--------------------------------------------------------------------------------------------+
         |
         v
+--------------------------------------------------------------------------------------------+
|  Scanner.Worker (N replicas, queue-driven)                                                 |
|                                                                                            |
|    1. Consume job from Valkey Stream (with lease)                                          |
|    2. Pull OCI image layers                                                                |
|    3. Check delta cache (Valkey layers:{digest})                                           |
|       - If cached: stitch existing SBOM fragments (20ms fast path)                         |
|       - If new: run full analysis                                                          |
|                                                                                            |
|    4. Execute language / OS / native analyzers (one library per ecosystem under            |
|       src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.*):                              |
|       +------------------------------------------------------------------------+           |
|       | OS:     Apk, Dpkg, Rpm, Pacman, Portage, Homebrew, MacOsBundle, Pkgutil,|          |
|       |         Windows (Chocolatey/Msi/WinSxS)                                |           |
|       | Lang:   Java, Node, Python, Go, .NET, Rust, Ruby, PHP, Bun, Deno,      |           |
|       |         Dart, Elixir, Swift, C/C++                                     |           |
|       | Native: ELF, PE, MachO                                                 |           |
|       | Plus:   Secrets analyzer                                               |           |
|       +------------------------------------------------------------------------+           |
|                                                                                            |
|    5. Extract call graphs (for reachability)                                               |
|    6. Generate SBOM:                                                                       |
|       - Inventory view (all components)                                                    |
|       - Usage view (entrypoint closure)                                                    |
|       - Formats: CycloneDX 1.6 (JSON/Protobuf), SPDX 3.0.1                                 |
|                                                                                            |
|    7. Upload to RustFS: blobs/{sha256}/sbom.cdx.json                                       |
|    8. Update PostgreSQL: scanner.artifacts, scanner.scan_status                            |
|    9. Publish event: scanner:events (scan.completed)                                       |
+--------------------------------------------------------------------------------------------+

Scan Status Polling

GET /api/v1/scans/{scanId}
         |
         v
+--------------------------------------------------------------------------------------------+
|  Response:                                                                                 |
|  {                                                                                         |
|    "scanId": "scan-abc123",                                                                |
|    "imageDigest": "sha256:...",                                                            |
|    "state": "running|completed|failed",                                                    |
|    "progress": {                                                                           |
|      "currentStage": "analyzing-java",                                                     |
|      "percentage": 45,                                                                     |
|      "layersCurrent": 5,                                                                   |
|      "layersTotal": 12                                                                     |
|    },                                                                                      |
|    "startedAt": "2025-01-02T15:30:00Z",                                                    |
|    "completedAt": null,                                                                    |
|    "artifacts": {                                                                          |
|      "sbom": { "format": "cdx-json", "digest": "sha256:..." }                              |
|    }                                                                                       |
|  }                                                                                         |
+--------------------------------------------------------------------------------------------+

4. SBOM Generation Flow

Docker BuildX Plugin Integration

docker buildx build --sbom=true ...
         |
         v
+--------------------------------------------------------------------------------------------+
|  StellaOps.Scanner.Sbomer.BuildXPlugin (src/Scanner/...BuildXPlugin/)                      |
|                                                                                            |
|  For each layer:                                                                           |
|    1. Extract files                                                                        |
|    2. Run analyzers (Node, Java, Python, Go, .NET, Rust, Ruby, PHP, Bun, Deno)             |
|    3. Generate layer SBOM fragment                                                         |
|    4. Upload to local CAS (content-addressable store)                                      |
|    5. Emit OCI annotation (referrer)                                                       |
|                                                                                            |
|  CI overhead: <=300ms per layer                                                            |
+--------------------------------------------------------------------------------------------+
         |
         v
Image pushed to registry with SBOM referrer annotation

BYOS (Bring Your Own SBOM) Upload

POST /api/v1/sbom/upload          (singular "sbom"; SbomUploadEndpoints group "/sbom")
{
  "artifactRef": "app:v1.0",
  "artifactDigest": "sha256:...",
  "sbom": { /* CycloneDX or SPDX document */ },   // or "sbomBase64": "..."
  "format": "cdx-json"
}
         |
         v
+--------------------------------------------------------------------------------------------+
|  SbomByosUploadService:                                                                    |
|    1. Format detection + schema validation                                                 |
|    2. Component normalization (PURL, sort)                                                 |
|    3. Quality scoring + warnings                                                           |
|    4. Digest computation                                                                   |
|    5. Register in artifact catalog                                                         |
|    6. Trigger scan coordination (same downstream flow)                                     |
+--------------------------------------------------------------------------------------------+

5. Policy Evaluation Flow

Scan Completion Triggers Policy

scan.completed event published to Valkey Streams
                |
                v
+--------------------------------------------------------------------------------------------+
|  Event Subscribers (consume scanner:events)                                                |
|                                                                                            |
|  +----------------+  +----------------+  +----------------+  +----------------+            |
|  | Policy.Engine  |  | Notify.Worker  |  |TimelineIndexer |  | ExportCenter   |            |
|  |   (evaluate)   |  |  (alert)       |  |  (audit)       |  | (SARIF export) |            |
|  +-------+--------+  +----------------+  +----------------+  +----------------+            |
|          |                                                                                 |
|          v                                                                                 |
|  +--------------------------------------------------------------------------------------+  |
|  |  Policy Engine Evaluation Pipeline                                                   |  |
|  |                                                                                      |  |
|  |  Input Sources (immutable reads only - AOC enforced):                                |  |
|  |    * SBOM from SbomService (RustFS)                                                  |  |
|  |    * Advisory raw from PostgreSQL (vuln.advisory_raw)                                |  |
|  |    * VEX raw from PostgreSQL (vex.vex_raw)                                           |  |
|  |    * Reachability lattice from Scanner call-graph                                    |  |
|  |    * Policy definition (stella-dsl@1)                                                |  |
|  |                                                                                      |  |
|  |  +--------------------------------------------------------------------------------+  |  |
|  |  |  K4 LATTICE LOGIC (Four-Valued Truth)                                          |  |  |
|  |  |                                                                                |  |  |
|  |  |  Values: Unknown (bot) | True (T) | False (F) | Conflict (top)                 |  |  |
|  |  |                                                                                |  |  |
|  |  |  Knowledge Ordering: bot <= {T,F} <= top                                       |  |  |
|  |  |                                                                                |  |  |
|  |  |  Conflict Detection: T join F = top                                            |  |  |
|  |  |  (Both evidence for and against -> conflict preserved, not collapsed)          |  |  |
|  |  +--------------------------------------------------------------------------------+  |  |
|  |                                                                                      |  |
|  |  Processing Steps:                                                                   |  |
|  |    1. Load Policy IR (cached by policyId+version hash)                               |  |
|  |    2. Batch join: SBOM <-> Advisory <-> VEX (deterministic ordering)                 |  |
|  |    3. For each (component, vulnerability):                                           |  |
|  |       a. Compute Evidence-Weighted Score                                             |  |
|  |       b. Execute policy rules (first-match)                                          |  |
|  |       c. Apply exceptions (specificity-ranked)                                       |  |
|  |       d. Check unknown budget                                                        |  |
|  |       e. Calculate confidence (5 factors):                                           |  |
|  |          +-----------------------------------------------------------------------+   |  |
|  |          | Reachability (0.85 unreachable -> 0.1 confirmed reachable)            |   |  |
|  |          | Runtime (0.9 supports -> 0.2 contradicts)                             |   |  |
|  |          | VEX (trust score x status weight)                                    |   |  |
|  |          | Provenance (SBOM completeness)                                       |   |  |
|  |          | Policy (exception coverage)                                          |   |  |
|  |          |                                                                       |   |  |
|  |          | Final = Clamp01(Sum of Weight x RawValue)                            |   |  |
|  |          +-----------------------------------------------------------------------+   |  |
|  |       f. Emit OpenVEX decision (if verdict change)                                   |  |
|  |                                                                                      |  |
|  |    4. Upsert effective findings:                                                     |  |
|  |       - policy.effective_finding_{policyId} (current snapshot)                       |  |
|  |       - policy.effective_finding_{policyId}_history (audit trail)                    |  |
|  |                                                                                      |  |
|  |    5. Compute determinism hash for replay verification                               |  |
|  |                                                                                      |  |
|  |  Output:                                                                             |  |
|  |    verdict: PASS | BLOCK | WARN | FAIL                                              |  |
|  |    confidence: 0.0-1.0 with tier (VeryHigh/High/Medium/Low/VeryLow)                  |  |
|  |    explain_trace: [rule hits + factor breakdown]                                     |  |
|  |    evidence_ids: [advisory_raw_ids, vex_raw_ids, sbom_digest]                        |  |
|  +--------------------------------------------------------------------------------------+  |
+--------------------------------------------------------------------------------------------+
                |
                v
+--------------------------------------------------------------------------------------------+
|  Optional: DSSE Signing + Transparency                                                     |
|                                                                                            |
|  Policy Engine -> Signer (DSSE envelope)                                                   |
|                     |                                                                      |
|                     v                                                                      |
|              Attestor (in-toto predicate: stella.ops/vexDecision@v1)                       |
|                     |                                                                      |
|                     v                                                                      |
|              Rekor v2 transparency log (optional)                                          |
+--------------------------------------------------------------------------------------------+

6. Policy Setup Flow

User navigates to Policy Studio (/policy-studio)
                |
                v
+--------------------------------------------------------------------------------------------+
|  Web UI: PolicyWorkspaceComponent                                                          |
|                                                                                            |
|  +--------------------------------------------------------------------------------------+  |
|  |  Policy Studio Sub-Features:                                                         |  |
|  |                                                                                      |  |
|  |  1. Policy Editor (Monaco YAML)                                                      |  |
|  |     - Visual rule builder                                                            |  |
|  |     - stella-dsl@1 syntax                                                            |  |
|  |     - Live validation                                                                |  |
|  |                                                                                      |  |
|  |  2. Policy Simulation                                                                |  |
|  |     - Test against historical scan data                                              |  |
|  |     - What-if analysis                                                               |  |
|  |     - Impact preview                                                                 |  |
|  |                                                                                      |  |
|  |  3. Approval Workflow (diff-aware release gates, enum GateLevel G0-G4)                |  |
|  |     - G0 no-risk/admin -> G1 low -> G2 moderate (code-owner review) ->                |  |
|  |       G3 high (release-captain sign-off) -> G4 safety-critical (PM+DM+Security)       |  |
|  |     - Requirements escalate per level; see StellaOps.Policy/Gates/GateLevel.cs        |  |
|  |                                                                                      |  |
|  |  4. Policy Dashboard                                                                 |  |
|  |     - Execution history                                                              |  |
|  |     - Metrics & trends                                                               |  |
|  |     - Explain traces                                                                 |  |
|  +--------------------------------------------------------------------------------------+  |
|                |                                                                           |
|                v                                                                           |
|  +--------------------------------------------------------------------------------------+  |
|  |  Policy Schema (YAML v1.0)                                                           |  |
|  |                                                                                      |  |
|  |  version: "1.0"                                                                      |  |
|  |  rules:                                                                              |  |
|  |    - name: Block Critical                                                            |  |
|  |      severity: [Critical]                                                            |  |
|  |      action: block                                                                   |  |
|  |                                                                                      |  |
|  |    - name: Ignore Low Dev                                                            |  |
|  |      severity: [Low, None]                                                           |  |
|  |      environments: [dev, staging]                                                    |  |
|  |      action: ignore                                                                  |  |
|  |      expires: "2026-01-01"                                                           |  |
|  |                                                                                      |  |
|  |    - name: Escalate Regional High                                                    |  |
|  |      sources: [NVD, CNNVD, ENISA]                                                    |  |
|  |      severity: [High, Critical]                                                      |  |
|  |      action: escalate                                                                |  |
|  +--------------------------------------------------------------------------------------+  |
|                |                                                                           |
|                v                                                                           |
|  POST /api/v1/policies/* -> Gateway rewrites to /api/policy/* -> Policy.Engine             |
|  (gateway route: ^/api/v1/policies(.*) -> policy-engine /api/policy$1)                      |
|                |                                                                           |
|                v                                                                           |
|  +--------------------------------------------------------------------------------------+  |
|  |  Policy Engine Processing                                                            |  |
|  |                                                                                      |  |
|  |  1. Validate schema (JSON-Schema at src/Policy/__Libraries/.../Schemas/)             |  |
|  |  2. Compile to IR (cached by policyId+version hash)                                  |  |
|  |  3. Store the pack/version/rules rows in PostgreSQL (policy schema)                  |  |
|  |  4. Advance lifecycle through draft -> active/approved -> published states           |  |
|  |     (conceptual labels; the persisted enum is draft/active/approved/published/       |  |
|  |      archived — there is no SHADOW/ENFORCING state in the code)                       |  |
|  |                                                                                      |  |
|  |  Storage Tables (actual names in the policy schema):                                  |  |
|  |    * policy.packs / policy.pack_versions / policy.rules - Policy definitions          |  |
|  |    * policy.evaluation_runs - Run records with cursors                                |  |
|  |    * policy.snapshots - Compiled policy snapshots                                     |  |
|  |    * policy.exceptions - Approved exceptions (suppress/defer/downgrade)              |  |
|  |    * policy.exception_approval_audit - Approval chain                                |  |
|  +--------------------------------------------------------------------------------------+  |
+--------------------------------------------------------------------------------------------+

7. Notification Flow

Event published (e.g., scan.completed, advisory.delta)
         |
         v
+--------------------------------------------------------------------------------------------+
|  Valkey Stream: scanner:events / concelier:drift / etc.                                    |
+--------------------------------------------------------------------------------------------+
         |
         v
+--------------------------------------------------------------------------------------------+
|  Notify.Worker consumes stream                                                             |
|    1. Evaluates notification rules (Notify.Rule)                                           |
|    2. Matches event kind (scanner.report.ready, scheduler.rescan.delta)                    |
|    3. Queries user notification preferences                                                |
|    4. Renders template (configurable per channel + locale)                                 |
|    5. Sends via configured channels:                                                       |
|       +-- Slack: POST to hooks.slack.com                                                   |
|       +-- Teams: POST to graph.microsoft.com                                               |
|       +-- Email: SMTP send                                                                 |
|       +-- Webhook: POST to custom endpoint                                                 |
|    6. Records delivery receipt                                                             |
|    7. Idempotency tracking (prevents duplicate sends)                                      |
|    8. Retry with deterministic backoff                                                     |
+--------------------------------------------------------------------------------------------+

8. Export Flow

User requests export
         |
         v
+--------------------------------------------------------------------------------------------+
|  GET /api/v1/scans/{scan_id}/export?format=spdx                                            |
+--------------------------------------------------------------------------------------------+
         |
         v
+--------------------------------------------------------------------------------------------+
|  Scanner.Web or ExportCenter                                                               |
|    1. Queries scan metadata from PostgreSQL                                                |
|    2. Retrieves SBOM artifact from RustFS                                                  |
|    3. Signs SBOM with Signer service (DSSE envelope)                                       |
|    4. Creates in-toto attestation with Attestor                                            |
|    5. Stores final bundle to RustFS                                                        |
|    6. Returns signed bundle (application/vnd.in-toto+json)                                 |
+--------------------------------------------------------------------------------------------+
         |
         v
+--------------------------------------------------------------------------------------------+
|  For air-gap export:                                                                       |
|    ExportCenter bundles:                                                                   |
|      - SBOMs (SPDX/CycloneDX)                                                              |
|      - Offline Kit (vulnerability feeds, trust roots, signatures)                          |
|      - Evidence bundles (DSSE-signed artifacts)                                            |
|    Generates mirror artefacts                                                              |
|    Packages for portable/USB distribution                                                  |
+--------------------------------------------------------------------------------------------+

9. Developer Image Update Flow

This flow covers a developer updating a built or changed microservice Docker image in an environment they are allowed to touch. It is intentionally narrower than a DevOps release-manager flow.

Developer opens /developer/services
         |
         v
+--------------------------------------------------------------------------------------------+
|  Select owned service                                                                      |
|  - serviceId / repository / image namespace                                                |
|  - current deployed digest by environment                                                  |
|  - candidate digests from CI/registry                                                      |
+--------------------------------------------------------------------------------------------+
         |
         v
+--------------------------------------------------------------------------------------------+
|  Authority / Gateway                                                                       |
|  - validates tenant scope                                                                  |
|  - validates developer role                                                                |
|  - enforces ABAC: serviceIds, repositoryIds, imageNamespaces, environmentIds               |
+--------------------------------------------------------------------------------------------+
         |
         v
+--------------------------------------------------------------------------------------------+
|  Scanner + SBOM + Policy                                                                   |
|  - confirms digest identity                                                                |
|  - runs or reuses scan/SBOM/reachability evidence                                          |
|  - simulates policy for the selected service/environment                                   |
|  - returns PASS / WARN / BLOCK plus explanation                                            |
+--------------------------------------------------------------------------------------------+
         |
         v
+--------------------------------------------------------------------------------------------+
|  Release Orchestrator                                                                      |
|  If environment allows developer direct update:                                            |
|    - creates scoped service image update run                                               |
|    - records evidence and audit trail                                                      |
|  If environment requires approval:                                                         |
|    - creates promotion/update request                                                      |
|    - routes to DevOps, security manager, or policy approver based on gates                 |
+--------------------------------------------------------------------------------------------+

Developer tokens must not include broad ui.admin, release:bypass, policy:approve, or unrestricted orch:operate. Direct environment updates are allowed only when the environment policy and ABAC claims both permit it.

When a developer or registry/CI integration presents a new artifact digest for a release component that is already attached to a non-draft release, Stella does not mutate that release in place. PATCH /api/v1/release-orchestrator/releases/{releaseId}/components/{componentId} returns 409 release_artifact_update_requires_new_version with a suggested successor release version and the action endpoint. The developer flow then calls POST /api/v1/release-orchestrator/releases/{releaseId}/versions/from-artifact-update to create a new draft release version that copies the old release and replaces only the changed component digest.

Current Console behavior: /developer/services reads live releases, deployments, and findings. It disables direct update unless the token carries explicit service ownership, target environment, maxEnvironmentType, directUpdateAllowed=true, and an immutable candidate digest. When the newest image is not yet present in the release projection, the developer can paste its sha256: digest and the page re-evaluates the action against the same ABAC profile. Direct updates call POST /api/v1/release-orchestrator/deployments; Release Orchestrator rejects developer principals whose service, environment, digest, or direct-update claims do not match. Approval-required updates call POST /api/v1/release-orchestrator/approvals/developer-requests; the persisted approval row records source type developer_update, actor, service, digest, target environment, gate context, and audit details.

The developer follow-on surfaces preserve that context. Security findings and the SBOM explorer accept a service query filter so the developer can inspect stale scan/feed/SBOM and finding evidence for the owned service without receiving security-manager actions. /releases/approvals labels the request source, and /releases/deployments can filter by service, initiating developer, source type, and digest. Developers can inspect request/run progress and failure reasons, but approve/reject actions require operator, release-publisher, policy-approver, or admin scopes.

Administrators grant service-release access from Identity & Access by assigning role/service-release-contributor or the legacy role/release-developer bundle and setting the ABAC attributes that become token claims. The user editor warns before saving any broad mixed grant so self-service does not silently turn into release-operator or admin authority.

Administrators can additionally limit release creation and artifact-derived successor versions to a tenant-stored environment allow-list. When this limit is active, source releases, clones, and artifact successors must name an allowed target environment before the developer or operator action can proceed.


10. Admin Release Environment Limit Flow

This flow covers the administrator control that limits release targets to approved environments.

Admin opens /ops/platform-setup/defaults-guardrails
         |
         v
+--------------------------------------------------------------------------------------------+
|  Platform Setup: Release Environment Limit                                                 |
|  - load effective setting from Release Orchestrator                                        |
|  - show source: stored tenant setting or deployment-config fallback                        |
|  - edit require-target-environment toggle and allowed environment list                     |
+--------------------------------------------------------------------------------------------+
         |
         v
+--------------------------------------------------------------------------------------------+
|  PUT /api/v1/release-orchestrator/release-environment-limit                                |
|  - requires ui.admin scope and administrator role                                          |
|  - normalizes the allow-list                                                               |
|  - persists the tenant setting in PostgreSQL                                               |
|  - rejects developer/operator principals before mutation                                   |
+--------------------------------------------------------------------------------------------+
         |
         v
+--------------------------------------------------------------------------------------------+
|  Release Orchestrator release mutation paths                                               |
|  - create release                                                                          |
|  - update release target environment                                                       |
|  - clone release                                                                           |
|  - create artifact-derived successor version                                               |
|                                                                                            |
|  Each path reads the stored tenant setting first, then deployment configuration fallback.   |
|  Missing target returns release_target_environment_required.                               |
|  Disallowed target returns release_environment_not_allowed.                                |
+--------------------------------------------------------------------------------------------+

API Endpoint Quick Reference

Endpoints below are the gateway-facing paths a client uses. The gateway rewrites /api/v1/... aliases to the backing service path (see the route table in src/Router/StellaOps.Gateway.WebService/appsettings.json); the Backing module column names the service that actually serves the request.

User ActionEndpoint (gateway-facing)Backing moduleNotes
View DashboardGET /api/console/vuln/facetsPlatform (Console aggregation)severity/vexState/reachability facets in one call
GET /api/v1/governance/risk-profiles + GET /api/risk/aggregated-statusPolicy Engine + Platformno /api/risk/stats endpoint; counts derived client-side
GET /scans/{scanId}/reachability/summaryScannercalled with scanId latest; not /api/reachability/summary
Submit ScanPOST /api/v1/scans/Scanner202 + scanId
Check StatusGET /api/v1/scans/{id}Scanner
Download SBOMGET /api/v1/scans/{id}/sbomScannerartifact stored in RustFS
Upload SBOM (BYOS)POST /api/v1/sbom/uploadScannersingular sbom; body field is sbom/sbomBase64
View FindingsGET /api/v1/findings/ledgerFindingsgateway /api/v1/findings* -> findings.stella-ops.local
Create / manage PolicyPOST /api/v1/policies/*Policy Enginegateway rewrites to /api/policy/* (e.g. /api/policy/packs)
Evaluate PolicyPOST /api/policy/packs/{packId}/revisions/{version}/evaluate (or POST /policy/decisions)Policy Engineno /api/v1/policies/evaluate route exists
Manage ExceptionsGET/POST /api/v1/exceptions/Policy Enginegateway rewrites to /api/policy/exceptions
View VEXGET /api/v1/vex/statementsExcititor / VexHubgateway /api/v1/vex* -> VexHub; Excititor owns statement creation
View AdvisoriesGET /api/v1/advisories (AI) or GET /advisories/raw (raw)AdvisoryAI / Concelierno bare /api/advisories; Concelier serves /advisories/raw*
Export EvidencePOST /api/v1/export/* (gateway) -> ExportCenter /v1/exports/*ExportCenterno /api/v1/export/bundle; runs created via /v1/exports/profiles/{id}/runs
Manage release environment limitsGET/PUT /api/v1/release-orchestrator/release-environment-limitReleaseOrchestratorrequires ui.admin scope + admin role