Customization

mandatory

How users + developers personalize Koder UI without leaving the design system. Material parity (`/foundations/customization`). Covers the axes available (style × scheme × density × motion × i18n × layout density × accessibility prefs), where each persists, who the audience is, and what's NOT customizable per surface.

Spec — Customization

Facet *isual*do Koder Design. Material parity: https://m3.material.io/foundations/customization.

Customization axes (canonical 8)

Every Koder app exposes the same 8 axes in Settings (where applicable), with the same default values and the same persistence pattern. Spec per axis lives in linked references; this doc catalogs them.

Axis Default Spec
*I style*(forma/densidade) material3 themes/ui-style.kmd
*olor scheme*(paleta) default themes/color-schemes.kmd
*heme mode*(claro/escuro) system themes/light-dark.kmd
*anguage*(i18n) device locale i18n/contract.kmd
*oice / wake-word* OFF (except barge-in) voice/wake-word.kmd
*rror reporting* OFF (opt-in) errors/reporting.kmd
*uto-update* ON koder-app/behaviors.kmd §4
*ensity* comfortable themes/ui-style.kmd

R1 — One Settings page, consistent shape

Every Koder app's Settings page has the SAME section order:

  1. *ppearance*(UI style, color scheme, theme mode, density)
  2. *anguage*(locale picker, ICU regional prefs)
  3. *otifications*(per-app)
  4. *oice*(wakeword, bargein, hot phrases)
  5. *rivacy*(error reporting, telemetry opt-out, data export)
  6. *ccount*(signin, signout, tenant switch)
  7. *bout*(version, licenses, what's new)

Order is rigid; sections can be omitted (no Voice → skip), never reordered.

R2 — Persistence

Axis Where it persists
Appearance + Language Per-surface (localStorage / Flutter SharedPreferences) — sticky per device
Voice Per-app (same storage)
Privacy Perapp + propagated to backend audit log on optin
Account Server-side (Koder ID)

R3 — System hints

When the user has not made a choice, surfaces follow system hints:

  • Theme mode: ThemeMode.system / prefers-color-scheme
  • Language: Platform.localeName / navigator.language
  • High contrast / reduced motion: OS accessibility prefs (Android

    View.SystemUiHints, iOS UIAccessibility, Windows SystemSettings, GNOME org.gnome.desktop.a11y, etc.)

R4 — Pertenant vs peruser vs per-surface

Scope Examples
Pertenant (workspacewide) Custom brand color, organization name, allowed login methods
Per-user (synced) Display name, notification prefs, language
Persurface (devicelocal) UI style, density, theme mode, voice settings

Pertenant customization always takes precedence over peruser; peruser always takes precedence over persurface defaults.

R5 — What's NOT customizable

The following are *eliberately fixed*to preserve product identity:

  • Product logo / icon
  • Element family taxonomy (foundations/elements.kmd)
  • Canonical layouts (canonical-layouts.kmd)
  • Error message format (errors/user-facing-messages.kmd)
  • Touch target minimums (safe-area.kmd)
  • Keyboard shortcuts that conflict with OS conventions
  • Brand-color accent (varies by tenant, but the role "accent" stays)

User requests for these go through product feedback, not Settings.

R6 — Customization pickers in UI

Each axis has a canonical widget (in koder_kit):

Axis Widget Spec ref
UI style KoderUIStylePicker themes/ui-style.kmd
Color scheme KoderColorSchemePicker (planned) themes/color-schemes.kmd
Theme mode KoderThemeToggle themes/light-dark.kmd
Language KoderL10nSwitcher i18n/contract.kmd §R3
Voice KodeVoiceSettingsTile voice/wake-word.kmd
Error reporting KoderReportButton toggle errors/reporting.kmd

R7 — Reset to defaults

Every Settings page exposes a "Reset to defaults" button in the About section. Behavior:

  • Clears all per-surface preferences (returns to system hints)
  • Per-user prefs preserved (the user owns those)
  • Per-tenant prefs unaffected (admin owns those)
  • Confirmation dialog: "Reset appearance and preferences to defaults?"
  • All axis specs above
  • koder-app/behaviors.kmd — broader app behaviors
  • policies/reuse-first.kmd — pickers come from koder_kit, not per-app

Source: ../home/koder/dev/koder/meta/docs/stack/specs/foundations/customization.kmd