Files
cgalo5758 8e3c68c6be Make UI surfaces honestly reflect system state
- Add deployment-name branding to titles, mastheads, and OG tags
- Share one grant delivery-state query with lineage across grants
  surfaces
- Show pool status/usage, org owners, and config readiness
- Make billing views projection-aware with recency and sync vocabulary
- Guard FedWiki creation without domains and render route-aware 404s
2026-08-23 01:45:52 -05:00

9.7 KiB

integration-settings

Purpose

Defines runtime-managed integration configuration: a single core-owned store of operator-set, non-secret overrides layered over the environment (override → environment → default), discovered and validated from each integration's declared configuration spec, applied by a boot-time overlay (changes take effect on restart), and surfaced through a generic per-integration operator settings page. Secrets and bootstrap remain environment-only; this capability never stores or displays a secret.

Requirements

Requirement: Runtime overrides are stored app-level and override-only

The system SHALL store operator-set integration configuration overrides in a single core-owned table, core.integration_config_overrides, keyed by the flat configuration key name. A row SHALL exist only while an override is set; value encoding SHALL be the same string form the environment transport uses. Each row SHALL record who set it and when. No per-integration configuration tables SHALL be introduced.

Scenario: Absent row falls through

  • WHEN no override row exists for a configuration key
  • THEN the key SHALL resolve from environment/flag/config-file, then its declared default

Scenario: Clearing an override removes the row

  • WHEN an operator clears an override
  • THEN the row SHALL be deleted, restoring resolution from environment/default at next effect

Requirement: Configuration resolves runtime override first

Every declared integration configuration key SHALL resolve in the order: runtime override → environment/flag/config-file → declared default. The order SHALL be uniform across keys and integrations.

Scenario: Override wins over environment

  • WHEN a key is set in the environment and an override row exists
  • THEN the effective value SHALL be the override

Scenario: Environment wins over default

  • WHEN a key has no override row and is set in the environment
  • THEN the effective value SHALL be the environment value, not the declared default

Requirement: Overrides take effect at boot

The system SHALL load overrides once at startup — after migrations run, before any route or worker registration — and apply them ahead of all integration configuration reads. Saving an override SHALL NOT alter the running process's effective configuration. The settings surface SHALL state that changes apply on restart and SHALL indicate per key when a stored override differs from the boot-effective value.

Scenario: Save does not change the running process

  • WHEN an operator saves an override while the system is running
  • THEN behavior governed by that key SHALL be unchanged until restart
  • AND the settings surface SHALL mark the key as pending restart

Scenario: Restart applies the override

  • WHEN the system restarts with an override row present
  • THEN the override SHALL be the effective value everywhere the key is read

Requirement: Secret keys are never runtime-managed

Keys declared secret SHALL NOT be storable as overrides, SHALL NOT be editable from the settings surface, and their values SHALL never be displayed. The settings surface SHALL list secret keys by name with an environment-managed marker only.

Scenario: Secret key rendering

  • WHEN the settings page renders an integration whose spec declares a secret key
  • THEN the key SHALL appear with its usage text and an environment-managed marker, with no value and no input

Scenario: Secret override write is rejected

  • WHEN a write names a secret key as an override target
  • THEN the system SHALL reject it and store nothing

Requirement: Override values are validated and typed

Override writes SHALL be validated at save time against the key's declaration: values for keys declaring an enumeration SHALL be members of it. At boot, the overlay SHALL coerce each stored value by the key's declared default type (list keys comma-split, boolean and integer keys parsed) so typed reads behave identically to environment-sourced values. A stored value that fails coercion or enumeration at boot SHALL fail startup with an error naming the key and the remediation.

Scenario: List-typed override reads as a list

  • WHEN a key declared with a list default has override value "a.example,b.example"
  • THEN typed reads of that key SHALL return two elements after restart

Scenario: Invalid enum value rejected at save

  • WHEN an operator submits a value outside a key's declared enumeration
  • THEN the save SHALL be rejected and no row written

Scenario: Corrupt stored value fails boot actionably

  • WHEN the overrides table contains a value that fails coercion for its key (e.g. written by hand)
  • THEN startup SHALL fail with an error naming the key and how to delete the offending row

Requirement: Bootstrap remains environment-only

Boot-time required-configuration validation SHALL continue to run before the database is available and SHALL be satisfiable from the environment alone. Overrides SHALL layer on top of a valid environment configuration and SHALL NOT substitute for required keys at validation time.

Scenario: Required key present only as an override

  • WHEN a required key is unset in the environment but has an override row
  • THEN boot validation SHALL fail exactly as if the key were unset

Requirement: Operator settings surface is generic and declaration-driven

The operator panel SHALL provide a per-integration settings page at /operator/integrations/{slug}/settings, rendered by one core handler and template for all integrations from the integration's declared configuration spec. For each non-secret key it SHALL show the key, its usage text, the effective value, and the winning source (override, environment, or default), with an input to set or clear the override; keys declaring an enumeration SHALL render as a closed select. Writes SHALL follow the operator panel's HTMX + CSRF-header pattern and require the operator role. Registering an integration with declared configuration SHALL surface its settings page with no per-integration template or handler edits. Override rows whose key matches no installed integration's declaration SHALL be listed with a removal affordance.

Scenario: Settings page renders from declarations

  • WHEN an operator opens an integration's settings page
  • THEN every declared non-secret key SHALL appear with usage text, effective value, and source, and every secret key with an environment-managed marker

Scenario: New integration needs no surface work

  • WHEN a new integration declaring configuration is registered
  • THEN its settings page SHALL be reachable and complete with no operator template or handler edits

Scenario: Setting and clearing an override

  • WHEN an operator saves a valid value for a non-secret key and later clears it
  • THEN the save SHALL upsert the override row and the clear SHALL delete it, each reflected on the page

Scenario: Orphan overrides are visible

  • WHEN an override row's key matches no installed integration's declaration
  • THEN the operator surface SHALL list it as unrecognized with an affordance to delete it

Requirement: Integration status presentation distinguishes registry lifecycle from configuration readiness

Operator surfaces that present per-integration state (the integrations list and the overview's system region) SHALL label the registry lifecycle value for what it is — an operator-managed registry status, defaulting to active and never changed by any health check — and SHALL NOT present it under wording that implies connectivity or live health ("connected", "read live"). Alongside the registry status, these surfaces SHALL show a configuration-readiness signal derived from the same required-key resolution the settings pages already perform: an integration with any required key unresolved SHALL be visibly marked as not configured wherever its status is shown, not only on its own settings page.

Scenario: Unconfigured integration is visibly unconfigured on the list

  • WHEN an operator views the integrations list while an integration's required key resolves to no value
  • THEN that integration's row shows a not-configured signal alongside its registry status
  • AND the page does not describe the integration as connected

Scenario: Registry status is labeled as registry status

  • WHEN an operator views any surface showing integration status
  • THEN the lifecycle value is labeled so it cannot read as a health check result

Requirement: Secret settings distinguish set from unset

Settings surfaces SHALL render required secret keys with a truthful presence indicator — set (masked) versus not set — rather than one identical masked treatment for both states, so an operator can tell whether a required secret exists without consulting the environment.

Scenario: Missing secret renders as not set

  • WHEN an operator views the settings page for an integration whose required secret is absent from the environment
  • THEN the secret's row states that no value is set
  • AND a present secret renders as set-and-masked, visually distinct from the absent state

Requirement: Switching Stripe to live mode carries a consequence warning

The stripe-mode setting SHALL disclose, adjacent to the control and before submission, that selecting live moves the deployment onto real payment processing with real charges, distinguishing this control from routine settings on the same page.

Scenario: Live mode selection is warned before save

  • WHEN an operator selects live for stripe-mode
  • THEN consequence copy adjacent to the control states that real charges result
  • AND the copy renders before the operator submits the change