Files
Inboxintel/docs/discovery/multi-provider/04-settings-and-flags.md
T
cesnimda 4ce2df0a2b
CI / backend (push) Successful in 52s
CI / frontend (push) Successful in 14s
Deploy Staging / deploy (push) Successful in 18s
CI / backend (pull_request) Successful in 52s
CI / frontend (pull_request) Successful in 15s
Security / secrets (push) Successful in 4s
Security / dependencies (push) Successful in 55s
Security / secrets (pull_request) Successful in 4s
Security / dependencies (pull_request) Successful in 54s
docs: discovery blueprint + multi-provider design (#8)
2026-07-01 19:59:53 +02:00

3.7 KiB

04 — Settings & Feature Flags (Part 3)

Two layers of configuration — per-user preferences and org-wide system settings / feature flags — with a clear precedence. Critically: AI is governed by a feature flag (admin, global), not merely a user preference.

User settings (per user)

Stored in user_settings; editable by the user.

Setting Values
theme system · light · dark (dark-first default)
inbox_layout density, pane layout, default view/lane, per-account or unified
notifications channels, quiet hours, priority-only
ai_prefs per-feature opt-in (summaries, replies, semantic, ask-inbox…) — only effective if the flag allows
provider_prefs default account, sync frequency, signature per account

System settings (admin, org-wide)

Stored in system_settings (singleton); Admin-only (05).

  • maintenance_mode (off · read-only · locked-except-admin) · default_theme · registration_open · org display name · retention defaults.

Feature flag system

feature_flags rows: key · enabled · scope · rollout · description · updated_by/at.

  • scope = SystemOnly — a hard org-wide switch; users cannot override (e.g., provider.microsoft, maintenance.readonly).
  • scope = UserOverridable — a default that a user preference can turn off (never on beyond what the flag permits) — e.g., ai.summaries.
  • rollout (jsonb) — optional per-role/percentage gating (e.g., enable a beta for Admins first).

Evaluation service

public interface IFeatureFlags {
    bool IsEnabled(string key, UserContext user);   // system flag ∧ scope ∧ role rollout
}
public interface IAiGate {                          // the AI-specific resolver
    bool IsAiEnabled(UserContext user);             // ai.enabled (system) ∧ user.ai_prefs.master
    bool IsAiFeatureEnabled(string feature, UserContext user); // ∧ ai.<feature> ∧ user opt-in
}
  • Flags are cached with change notification (hot-reload on admin edit); every read is cheap.
  • All flag reads are fail-closed: unknown/errored flag ⇒ treated as off.

AI gating precedence (the key requirement)

Effective AI availability is an AND down a chain — the system flag is the master gate:

AI feature X is available for user U  ⇔
    feature_flags["ai.enabled"].enabled              (admin master switch — SYSTEM)
  ∧ feature_flags["ai." + X].enabled                 (per-feature flag — SYSTEM)
  ∧ providerCapability(X)                             (Ollama/provider actually available)
  ∧ user.ai_prefs.master_opt_in                       (user hasn't disabled AI for themselves)
  ∧ user.ai_prefs[X]                                  (user opted into this feature)
  • Admin turns ai.enabled off ⇒ AI vanishes for everyone, regardless of any user preference. This is the behaviour the brief mandates.
  • With AI on at the system level, users still choose per-feature. The Null AI provider + capability flags (blueprint 06) mean a disabled path falls back or hides — never errors, never blocks core email.

Settings precedence (general)

system default  →  feature flag (may hard-disable)  →  user override (only where UserOverridable)

Maintenance mode

  • read-only: mutations (send/cleanup/label) blocked with a banner; browsing/search stay up.
  • locked-except-admin: only Admins can use the app (for migrations/upgrades).
  • Enforced at the API via a middleware policy + surfaced as a global banner in the UI.

Auditing

Flag and system-setting changes are admin actions → audit-logged (who/what/old→new/when).