Files
git.stella-ops.org/docs/modules/platform/platform-service.md
2026-04-14 21:44:35 +03:00

20 KiB

Platform Service (StellaOps.Platform.WebService)

Purpose

Provide a single, deterministic aggregation layer for cross-service UX workflows (health, quotas, onboarding, preferences, global search) so the Console UI and CLI do not fan out to multiple modules directly.

Non-goals

  • Replace module-owned APIs (Authority, Policy, Scanner, Orchestrator, etc.).
  • Ingest or mutate raw evidence or policy overlays.
  • Store high-volume evidence payloads (SBOMs, VEX, audit bundles).

Responsibilities

  • Aggregate platform health and dependency status.
  • Aggregate quota usage across Authority, Gateway, Orchestrator, and storage backends.
  • Persist onboarding progress and tenant setup milestones.
  • Persist dashboard personalization and layout preferences.
  • Persist authenticated user language preference for shared Web/CLI locale selection.
  • Provide global search aggregation across entities.
  • Provide global context selectors (region/environment/time window) and per-user persistence for Pack 22 top-bar context.
  • Provide Pack 22 release read-model projections for list/detail/activity/approvals queue views.
  • Provide Pack 22 topology inventory read-model projections for regions/environments/targets/hosts/agents/promotion paths/workflows/gate profiles.
  • Surface platform metadata for UI bootstrapping (version, build, offline status).
  • Expose analytics lake aggregates for SBOM, vulnerability, and attestation reporting.

API surface (v1)

Health aggregation

  • GET /api/v1/platform/health/summary
  • GET /api/v1/platform/health/dependencies
  • GET /api/v1/platform/health/incidents
  • GET /api/v1/platform/health/metrics

Quota aggregation

  • GET /api/v1/platform/quotas/summary
  • GET /api/v1/platform/quotas/tenants/{tenantId}
  • GET /api/v1/platform/quotas/alerts
  • POST /api/v1/platform/quotas/alerts

Onboarding

  • GET /api/v1/platform/onboarding/status
  • POST /api/v1/platform/onboarding/complete/{step}
  • POST /api/v1/platform/onboarding/skip
  • GET /api/v1/platform/tenants/{tenantId}/setup-status

Preferences

  • GET /api/v1/platform/preferences/dashboard
  • PUT /api/v1/platform/preferences/dashboard
  • GET /api/v1/platform/preferences/language
  • PUT /api/v1/platform/preferences/language
  • GET /api/v1/platform/dashboard/profiles
  • GET /api/v1/platform/dashboard/profiles/{profileId}
  • POST /api/v1/platform/dashboard/profiles
  • GET /api/v1/search (alias to /api/v1/platform/search)
  • GET /api/v1/platform/search
  • Legacy notice: both endpoints now emit deprecation metadata (Deprecation, Sunset, Link, Warning) and are being replaced by Unified Search POST /api/v1/search/query.

Metadata

  • GET /api/v1/platform/metadata
  • Response includes a capabilities list for UI bootstrapping; analytics capability is reported only when analytics storage is configured.

Localization

  • GET /platform/i18n/{locale}.json (anonymous, cacheable UI translation bundle)
  • GET /api/v1/platform/localization/bundles/{locale}
  • GET /api/v1/platform/localization/bundles/{locale}/{namespace}
  • GET /api/v1/platform/localization/locales (catalog used by Web and CLI locale selectors)
  • PUT /api/v1/platform/localization/bundles
  • DELETE /api/v1/platform/localization/strings/{locale}/{key}
  • Backend locale resolution contract: X-Locale -> Accept-Language -> default locale.
  • Runtime bundle layering consumed by backend services: shared embedded common -> service embedded bundle -> Platform override bundle.
  • Platform ships locale-complete ui and platform namespace bundles for en-US, de-DE, bg-BG, ru-RU, es-ES, fr-FR, uk-UA, zh-TW, zh-CN; shared localization library now provides common bundles for the same locale set.
  • Bundled locales currently shipped: en-US, de-DE, bg-BG, ru-RU, es-ES, fr-FR, uk-UA, zh-TW, zh-CN.

Release Orchestrator compatibility

  • Platform hosts /api/v1/release-orchestrator/environments/* as a compatibility facade for Console release-management flows.
  • Supported families include environment CRUD plus /settings, per-environment /targets CRUD with /health-check, and /freeze-windows CRUD.
  • The compatibility facade no longer uses runtime in-memory environment stores. Platform now binds those flows to the PostgreSQL-backed Release Orchestrator environment services when the release schema is configured locally, and otherwise proxies the owning Release Orchestrator WebApi over tenant/auth-aware HTTP.
  • Platform hosts /api/v2/scripts* against the real Release Orchestrator scripts backend on both runtime branches: direct library/schema binding when Platform has the scripts PostgreSQL connection, and an HTTP proxy to the owning Release Orchestrator WebApi when it does not.
  • The scripts facade no longer falls back to a local in-memory catalog; list/count/detail/version/validation/compatibility flows all resolve against the owning Release Orchestrator service or schema.

API surface (v2)

Global context

  • GET /api/v2/context/regions
  • GET /api/v2/context/environments?regions=
  • GET /api/v2/context/preferences
  • PUT /api/v2/context/preferences

Releases read model

  • GET /api/v2/releases
  • GET /api/v2/releases/{releaseId}
  • GET /api/v2/releases/activity
  • GET /api/v2/releases/approvals

Topology inventory read model

  • GET /api/v2/topology/regions
  • GET /api/v2/topology/environments
  • GET /api/v2/topology/targets
  • GET /api/v2/topology/hosts
  • GET /api/v2/topology/agents
  • GET /api/v2/topology/promotion-paths
  • GET /api/v2/topology/workflows
  • GET /api/v2/topology/gate-profiles
  • /api/v2/topology/hosts includes ProbeStatus, ProbeType, and ProbeLastHeartbeat.
  • Current host probe contract is projection-derived rather than live Signals state: ProbeLastHeartbeat mirrors the latest projected host sync timestamp, ProbeStatus is active when that heartbeat is within two minutes of the freshest host heartbeat in the tenant snapshot and offline otherwise, and missing heartbeat data yields not_installed.
  • Probe type mapping is deterministic: winrm_host -> etw; docker_host, compose_host, ssh_host, ecs_service, and nomad_job -> ebpf.

Security read model

  • GET /api/v2/security/findings
  • GET /api/v2/security/disposition
  • GET /api/v2/security/disposition/{findingId}
  • GET /api/v2/security/sbom-explorer

Integrations read model

  • GET /api/v2/integrations/feeds
  • GET /api/v2/integrations/vex-sources

Analytics (SBOM lake)

  • GET /api/analytics/suppliers
  • GET /api/analytics/licenses
  • GET /api/analytics/vulnerabilities
  • GET /api/analytics/backlog
  • GET /api/analytics/attestation-coverage
  • GET /api/analytics/trends/vulnerabilities
  • GET /api/analytics/trends/components

Legacy alias compatibility (/api/v1/*)

  • GET /api/v1/context/regions (alias of /api/v2/context/regions)
  • GET /api/v1/releases (alias of /api/v2/releases)
  • GET /api/v1/topology/regions (alias of /api/v2/topology/regions)
  • GET /api/v1/security/findings (alias of /api/v2/security/findings)
  • GET /api/v1/integrations/feeds (alias of /api/v2/integrations/feeds)
  • GET /api/v1/integrations/vex-sources (alias of /api/v2/integrations/vex-sources)
  • Alias usage telemetry is emitted as deterministic event keys (alias_<method>_<route_pattern>) with tenant hash metadata only.

Data model

  • platform.dashboard_preferences (dashboard layout, widgets, filters, optional user locale preference key)
  • platform.dashboard_profiles (saved profiles per tenant)
  • platform.onboarding_state (step state, timestamps, actor)
  • platform.quota_alerts (per-tenant quota alert thresholds)
  • platform.search_history (optional, user-scoped, append-only)
  • platform.translations (tenant + locale scoped translation override store)
  • platform.context_regions (global region selector inventory)
  • platform.context_environments (global environment selector inventory with region linkage)
  • platform.ui_context_preferences (tenant + actor scoped region/environment/time-window selections)
  • release.release_read_model (Pack 22 release list/detail projection root)
  • release.release_activity_projection (cross-release timeline projection with run/approval correlation keys)
  • release.release_approvals_projection (cross-release approval queue projection with blocker summaries)
  • release.security_finding_projection (Pack 22 consolidated findings projection with pivot/filter fields)
  • release.security_disposition_projection (read-only join projection for VEX + exception disposition state)
  • release.security_sbom_component_projection (component-level SBOM explorer table projection)
  • release.security_sbom_graph_projection (edge-level SBOM graph projection used by graph and diff modes)
  • release.integration_feed_source_health (advisory feed source health/freshness projection)
  • release.integration_vex_source_health (VEX source health/freshness projection with statement-format metadata)
  • release.integration_source_sync_watermarks (source family synchronization watermark projection state)
  • release.topology_region_inventory (region-level topology projection with deterministic ordering counts)
  • release.topology_environment_inventory (environment-level topology projection with region linkage and aggregate counters)
  • release.topology_target_inventory (target/component deployment inventory projection)
  • release.topology_host_inventory (host runtime inventory projection linked to targets and agents)
  • release.topology_agent_inventory (agent fleet projection with capability and assignment summaries)
  • release.topology_promotion_path_inventory (region-aware promotion-path projection with workflow and gate links)
  • release.topology_workflow_inventory (workflow template projection for topology routes)
  • release.topology_gate_profile_inventory (gate profile projection bound to region/environment inventory)
  • release.topology_sync_watermarks (projection synchronization watermark state for deterministic replay/cutover checks)
  • Schema reference: docs/db/schemas/platform.sql (PostgreSQL; in-memory stores used until storage driver switches).

Dependencies

  • Authority (tenant/user identity, quotas, RBAC)
  • Gateway (rate-limit status and request telemetry)
  • Orchestrator (job quotas, SLO state)
  • Notifier (alert policies and delivery status)
  • Policy/Scanner/Registry/VexHub (search aggregation sources)

Runtime boundary policy

  • Runtime read-model services (/api/v2/releases, /api/v2/topology/*, /api/v2/security/*, /api/v2/integrations/*) must depend only on explicit query contracts:
  • IReleaseControlBundleStore
  • IPlatformContextQuery
  • Current host probe enrichment is derived only from the topology projection timestamps already returned by IReleaseControlBundleStore.
  • Future live runtime probe or observed inventory enrichment for /api/v2/topology/hosts must still arrive through an explicit query contract. Read-model services must not reach into foreign persistence directly.
  • Foreign module persistence references are migration/admin-only and limited to explicit allowlist surfaces (SeedEndpoints, MigrationModulePlugins).
  • Runtime read endpoints must not inject foreign *.Persistence* types, DbContext from other modules, or migration runners directly.
  • Guard tests: src/Platform/__Tests/StellaOps.Platform.WebService.Tests/PlatformRuntimeBoundaryGuardTests.cs.

Security and scopes

  • Health: ops.health (summary), ops.admin (metrics)
  • Quotas: quota.read (summary), quota.admin (alerts/config)
  • Onboarding: onboarding.read, onboarding.write
  • Preferences: ui.preferences.read, ui.preferences.write
  • Context: platform.context.read, platform.context.write
  • Releases read model: orch:read (platform.releasecontrol.read policy mapping in Platform service)
  • Topology read model: orch:read (platform.topology.read policy mapping in Platform service)
  • Security read model: findings:read (platform.security.read policy mapping in Platform service)
  • Integrations feed read model: advisory:read (platform.integrations.read policy mapping in Platform service)
  • Integrations VEX source read model: vex:read (platform.integrations.vex.read policy mapping in Platform service)
  • Search: search.read plus downstream service scopes (findings:read, policy:read, etc.)
  • Metadata: platform.metadata.read
  • Analytics: analytics.read

Determinism and offline posture

  • Stable ordering with explicit sort keys and deterministic tiebreakers.
  • All timestamps in UTC ISO-8601.
  • Cache last-known snapshots for offline rendering with "data as of" markers.

Analytics ingestion configuration

Analytics ingestion runs inside the Platform WebService and subscribes to Scanner, Concelier, and Attestor streams. Configure ingestion with Platform:AnalyticsIngestion:

Platform:
  AnalyticsIngestion:
    Enabled: true
    PostgresConnectionString: "" # optional; defaults to Platform:Storage
    AllowedTenants: ["tenant-a"]
    Streams:
      ScannerStream: "orchestrator:events"
      ConcelierObservationStream: "concelier:advisory.observation.updated:v1"
      ConcelierLinksetStream: "concelier:advisory.linkset.updated:v1"
      AttestorStream: "attestor:events"
      StartFromBeginning: false
    Cas:
      RootPath: "/var/lib/stellaops/cas"
      DefaultBucket: "attestations"
    Attestations:
      BundleUriTemplate: "bundle:{digest}"

BundleUriTemplate supports {digest} and {hash} placeholders. The bundle: scheme maps to cas://<DefaultBucket>/{digest} by default. Verify offline bundles with stella bundle verify before ingestion.

Analytics maintenance configuration

Analytics rollups + materialized view refreshes are driven by PlatformAnalyticsMaintenanceService when analytics storage is configured.
Use BackfillDays to recompute recent rollups on the first maintenance run (set to 0 to disable).

Platform:
  Storage:
    PostgresConnectionString: "Host=...;Database=...;Username=...;Password=..."
  AnalyticsMaintenance:
    Enabled: true
    RunOnStartup: true
    IntervalMinutes: 1440
    ComputeDailyRollups: true
    RefreshMaterializedViews: true
    BackfillDays: 7

Observability

  • Metrics: platform.aggregate.latency_ms, platform.aggregate.errors_total, platform.aggregate.cache_hits_total
  • Logs include traceId, tenantId, operation, and cache-hit indicators.

Gateway exposure

The Platform Service is exposed via Gateway and registered through Router discovery. It does not expose direct ingress outside Gateway in production.

Setup Wizard

The Platform Service owns the installation-scoped setup wizard used by /setup-wizard/wizard for first-run control-plane bootstrap and later reconfiguration checks.

Current runtime behavior:

  • Authoritative wizard state is persisted in platform.setup_sessions via migration 063_PlatformSetupSessions.sql.
  • Installation-scoped environment settings and the SetupComplete marker now converge through platform.environment_settings keyed only by key. Migration 064_EnvironmentSettingsInstallationScopeConvergence.sql upgrades older compose-created tables that still used the legacy (tenant_id, key) primary key.
  • The persisted store keeps only non-sensitive draft configuration plus step state, timestamps, and check results. Secret material is still expected to be staged through a secret authority rather than stored in wizard session state.
  • The live wizard now owns only the five control-plane steps the running control plane can truthfully validate and converge: database, cache, migrations, admin, and crypto.
  • Tenant onboarding remains outside the bootstrap wizard. Integrations, feeds, notifications, environments, agents, branding, and related repeatable operations continue on /setup/* and module-owned authenticated APIs.
  • probe is diagnostic only. Only apply can move a step into the converged state.

API surface (v1)

Sessions

  • GET /api/v1/setup/sessions - Get the current installation-scoped setup session
  • GET /api/v1/setup/sessions/current - Alias for the current installation-scoped session
  • GET /api/v1/setup/sessions/{sessionId} - Read a specific persisted session by ID
  • POST /api/v1/setup/sessions - Create a new session or force a restart
  • POST /api/v1/setup/sessions/resume - Resume the current session or create one
  • PUT /api/v1/setup/sessions/{sessionId}/config - Persist non-sensitive draft values
  • POST /api/v1/setup/sessions/{sessionId}/finalize - Finalize the current session with convergence checks
  • POST /api/v1/setup/sessions/finalize - Compatibility finalize path

Steps

  • POST /api/v1/setup/sessions/{sessionId}/steps/{stepId}/probe - Run a diagnostic probe without completing the step
  • POST /api/v1/setup/sessions/{sessionId}/steps/{stepId}/apply - Apply the current step and persist the new state
  • POST /api/v1/setup/sessions/{sessionId}/steps/{stepId}/execute - Compatibility mutation wrapper (dryRun=true maps to probe)
  • POST /api/v1/setup/sessions/{sessionId}/steps/{stepId}/reset - Reset a step to pending
  • POST /api/v1/setup/sessions/{sessionId}/steps/{stepId}/skip - Compatibility endpoint retained for older clients; the current control-plane steps are all required
  • GET /api/v1/setup/sessions/{sessionId}/steps/{stepId}/checks - Read current check results
  • POST /api/v1/setup/sessions/{sessionId}/steps/{stepId}/checks/run - Re-run checks for a step
  • POST /api/v1/setup/sessions/{sessionId}/steps/{stepId}/prerequisites - Evaluate prerequisites for a step
  • POST /api/v1/setup/steps/{stepId}/test-connection - Compatibility probe endpoint used by older clients

Definitions

  • GET /api/v1/setup/definitions/steps - List the current live step definitions

Setup step identifiers

Step ID Title Required Depends On Notes
database PostgreSQL Database Yes - Probe verifies reachability. Apply records convergence against the current runtime connection.
cache Cache / Valkey Yes - Probe verifies cache reachability. Apply records convergence against the current runtime connection.
migrations Database Migrations Yes database Probe reports pending migration state. Apply runs the migration-admin path against the canonical Platform and ReleaseOrchestrator registry modules and re-validates convergence.
admin Admin Bootstrap Yes migrations Probe validates bootstrap prerequisites. Apply ensures the bootstrap admin exists.
crypto Crypto Profile Yes admin Probe validates the requested crypto profile. Apply records the converged profile selection.

Legacy aliases accepted during the compatibility window:

  • valkey -> cache
  • authority -> admin
  • users -> admin

Former tenant-onboarding steps such as vault, scm, registry, sources, notify, environments, agents, telemetry, llm, and settingsstore are no longer valid setup targets. Platform returns explicit handoff guidance to the authenticated onboarding surfaces instead.

Setup session states

Status Description
NotStarted Setup not begun
InProgress Setup in progress
Completed All steps completed
CompletedPartial Required steps completed, optional skipped
Failed Required step failed
Abandoned Setup abandoned by user

Setup step states

Status Description
Pending Not yet started
Passed Completed successfully
Failed Validation failed
Skipped Explicitly skipped (optional steps only)
Current Reserved contract value for active-step projections
Blocked Reserved contract value for dependency failures

Anonymous posture

  • Before installation setup is marked complete, setup session APIs may resolve to the installation scope without an authenticated caller.
  • After setup is marked complete, anonymous setup session reads and mutations return 401 and the normal authenticated platform.setup.* policies apply.
  • Finalize succeeds only after every required control-plane step has converged.

Security and scopes

  • Read: platform.setup.read
  • Write: platform.setup.write
  • Admin: platform.setup.admin

Offline posture

  • Sessions include DataAsOfUtc for offline rendering with stale indicators
  • Step results cached with Doctor check pass/fail status
  • Suggested fixes generated for failed checks
  • UX flow specification: docs/setup/setup-wizard-ux.md
  • CLI guide: docs/modules/cli/guides/setup-guide.md
  • Local operator runbook: docs/INSTALL_GUIDE.md
  • Live proof: src/Web/StellaOps.Web/scripts/live-setup-wizard-state-truth-check.mjs