# 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` ### Global search - 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`. ## 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` ### 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__`) 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` - 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`: ```yaml 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:///{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). ```yaml 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 exposes setup wizard endpoints to support first-run configuration and reconfiguration workflows. These endpoints replace UI-mock implementations with real backend state management. ### API surface (v1) #### Sessions - `GET /api/v1/setup/sessions` - Get current setup session for tenant - `POST /api/v1/setup/sessions` - Create new setup session - `POST /api/v1/setup/sessions/resume` - Resume existing or create new session - `POST /api/v1/setup/sessions/finalize` - Finalize setup session #### Steps - `POST /api/v1/setup/steps/execute` - Execute a setup step (runs Doctor checks) - `POST /api/v1/setup/steps/skip` - Skip an optional setup step #### Definitions - `GET /api/v1/setup/definitions/steps` - List all step definitions ### Setup step identifiers | Step ID | Title | Required | Depends On | |---------|-------|----------|------------| | `Database` | Database Setup | Yes | - | | `Valkey` | Valkey/Redis Setup | Yes | - | | `Migrations` | Database Migrations | Yes | Database | | `Admin` | Admin Bootstrap | Yes | Migrations | | `Crypto` | Crypto Profile | Yes | Admin | | `Vault` | Vault Integration | No | - | | `Scm` | SCM Integration | No | - | | `Notifications` | Notification Channels | No | - | | `Environments` | Environment Definition | No | Admin | | `Agents` | Agent Registration | No | Environments | ### 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 | | `Current` | Currently active step | | `Passed` | Completed successfully | | `Failed` | Validation failed | | `Skipped` | Explicitly skipped | | `Blocked` | Blocked by dependency | ### 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 ### Related documentation - UX flow specification: `docs/setup/setup-wizard-ux.md` - Repository inventory: `docs/setup/setup-wizard-inventory.md` - Doctor checks: `docs/setup/setup-wizard-doctor-contract.md`