Skip to content

M6-09 Manage instance, branding, login providers and feature flags

No Date Ruling Reason
D-M6-09-0 2026-10-23 Built on feat/M6-09-instance-admin from origin/main (M1-47, M3-10 and M6-04 merged); rulings and changelog are fragments. Names that differ from the brief: the screens live in packages/admin_ui/lib/src/instance/ (InstanceView, InstanceSettingsSection, SettingEditorDialog, BrandingSection, AccentPicker, AccentPreview, ProvidersSection, ProviderEditorDialog, FlagsSection, FlagSwitchDialog), the data source is InstanceRepository (ApiInstanceRepository, part of AdminRepository), the place is AdminSection.instance (/admin/instance on the desktop, /instance in the console), and the patrol suites are a9_instance_test.dart and a10_login_providers_test.dart in apps/console/integration_test/admin/. design_system is unchanged: buildDsTheme with a DsContext of the chosen accent already builds the preview theme. Instructions of the launcher; merged names win (D-W-100).
D-M6-09-1 2026-10-23 Typed settings and the version check: InstanceSetting carries only key, value, version and who changed it, so instanceSettingSchemas holds one entry per key of the configuration reference section 6 (kind, type text, writing operation; defaults are the server's, a key without a row is listed with its default), whose keys and types setting_kinds_test.dart holds equal to that table, with the palette keys of ADR 0044 and the server and the languages of locale.default the server accepts. A key with a closed list (language, accent) gets a choice, any other a text field; branding keys are shown read-only with a pointer to the branding screen (only updateBranding writes them, M1-46/1); a key this build does not know is shown read-only with the note to use the API. Saving states "from, to", confirms, and sends the value with If-Match on the version the editor read; the server's 400 stands at the input; a 412 takes the newer state from the problem's current (or reads the list again without one), shows it next to the person's input and keeps the input, so the next save names the newer version. The same holds for the branding (If-Match on the branding version). Providers have no version in the API (IdentityProvider has none and updateIdentityProvider takes no If-Match), so an update sends only the members that changed. Brief Design note 1; fixed requirement 14; 06 8.
D-M6-09-2 2026-10-23 Accent and branding: the picker offers exactly the seven palette keys as radios with a swatch and a name; there is no text input for a color, and the selection sends only the key (accent_picker_test.dart). The preview renders two cards with buildDsTheme for the chosen key in light and dark and shows the roles color.accent.bg, color.accent.subtle with color.accent.fg, color.text.link and color.focus.ring. The product name field shows no counter: branding.product_name_max_chars is a server key the API does not deliver, so the server's 400 (too long, control or bidi character) stands at the field. The logo goes through the host's file dialog (PNG, JPEG, WebP; the MIME type from the file name, the server's 415 decides), the preview is the server's variant from getBrandingLogo, and until the scan passed (404) the screen says the logo is being checked and offers "Check again" instead of polling. After a branding or logo change the console reads discovery again, so its theme and product name follow at once; the desktop follows through instance.updated. Brief Design note 2; R-PR-08; ADR 0044; 12 3.7.
D-M6-09-3 2026-10-23 Login providers: the API stores secrets of providers only as references (client_secret_ref, client_key_ref, 08 2.6) and returns them in config. The form treats these references as write-only: the field is masked, starts empty when editing, says that empty keeps the stored reference, and the stored reference is never shown on any screen; the confirmation names the changed members, never a value. The rest of the stored configuration (members this form does not know too) is sent back unchanged with the form's members set or removed; a new client authentication needs its own reference, which the server names at its field when it is missing. "Test configuration" is not built: the API has no check of a provider configuration. The redirect URI is the server's callback (<api base>/auth/oidc/callback, 08 2.2 step 4) with a copy action. The proxy header form states the loopback rule (08 2.4 rule 1), and the server's 409 conflict with reason trusted_header_requires_loopback is explained with its hint; disable and delete say that the sessions from the provider end at once (R-ID-12), and a 409 conflict with reason provider_in_use shows the server's hint to disable instead. Brief Design note 3; fixed requirements 15 and 16.
D-M6-09-4 2026-10-23 Feature flags: the list shows key, description, kind, module, the state evaluated for the caller (getInstance.features), the stored global value with the default and the size of the rollout, version and who changed it. The switch states the new global value for everyone, requires a reason and sends putFeatureFlag with If-Match and the rollout unchanged, so switching never drops a rollout; a 412 closes the dialog, shows the newer state and changes nothing, so the person decides again on what is stored. Orphaned flags are read-only (the server answers 404). The desktop loads settings and flags again on every instance.updated (a change of the stored instance information of the sync engine); the console reloads after its own change, as it has no live updates. Brief Design note 4; configuration reference 7; 16 6.2.
D-M6-09-5 2026-10-23 The patrol suites A9 and A10 run after A8 in the same bundle: A9 changes locale.default, the accent and the flag dm.enabled; A10 adds an OIDC provider with the issuer https://login.example.com and a reference env:BOTHY_IDP_EXAMPLE, logs the console out and sees its button on E2, so it runs last. Adding a provider reads nothing from the issuer (the configuration is checked at write time, the discovery document is read at login), so no identity provider has to run in the Compose network for this flow; the fake identity provider of M1-41 is a Go test package, not a service of the stack. Brief Tests; 08 2.6; M1-41.