8.1 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.
- Provide global search aggregation across entities.
- 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/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
Metadata
- GET
/api/v1/platform/metadata - Response includes a capabilities list for UI bootstrapping; analytics capability is reported only when analytics storage is configured.
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
Data model
platform.dashboard_preferences(dashboard layout, widgets, filters)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)- 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)
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 - Search:
search.readplus 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 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 tenantPOST /api/v1/setup/sessions- Create new setup sessionPOST /api/v1/setup/sessions/resume- Resume existing or create new sessionPOST /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
DataAsOfUtcfor 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