Skip to main content

ADR-021: Cloud Provider Selection and Settings UI

Table of Contents​

  1. Status
  2. Context
  3. Decision drivers
  4. Decision
  5. UX / Information architecture
  6. Provider roadmap
  7. Why only one provider at a time
  8. Multi-provider future (non-blocking)
  9. Implementation notes
  10. Testing & validation
  11. Consequences
  12. Related ADRs
  13. Review

Status​

Accepted (implemented β€” initial UI refactor complete)

Context​

Cloud Sync / Remote Backups were introduced in ADR-015 and the merge model in ADR-016.

As additional providers are added (e.g. Google Drive), the Settings UI must:

  • Scale without becoming a long, confusing list of controls.
  • Make the currently active provider obvious.
  • Keep setup actions scoped to the selected provider.
  • Preserve the security boundary: OAuth and secrets live in Electron main.

Decision drivers​

  1. Scalability: the UI must support multiple providers without growing vertically into a wall of buttons.
  2. Clarity: users must understand which provider is active and what actions are safe.
  3. Safety: avoid ambiguous β€œtwo remotes” state until conflict semantics are designed.
  4. Consistency: provider setup must follow a consistent pattern across providers.
  5. Extensibility: adding a provider should be incremental (new provider implementation + a new provider panel).

Decision​

1) Provider setup is presented as tabs​

The Cloud settings section exposes providers using a single tabbed selector:

  • Dropbox
  • Google Drive
  • WebDAV (planned β€” UI tab exists, provider implementation deferred)
  • Local folder (filesystem provider)

Tabs act as an information architecture boundary: provider-specific setup lives inside the tab panel.

2) Single active provider at a time (initially)​

Uptime Watcher enforces a single configured provider for Cloud Sync / Remote Backups.

When a provider is configured, other provider tabs remain visible, but setup actions are disabled with an explicit callout.

3) Runtime validation is owned by Electron main​

The renderer must not attempt to β€œvalidate” provider configurations by duplicating business rules.

Rules:

  • All configuration requests are validated in Electron main using shared contracts (ADR-009).
  • Provider setup is considered successful only after main verifies the configuration is usable.
  • On verification failure, main must roll back any partial configuration so the Settings UI does not get stuck in a confusing state.

Examples (current implementation):

  • Filesystem provider base directory is validated and canonicalized in main before being persisted.
  • OAuth providers verify connectivity immediately after storing tokens; if the verification fails, main restores the previous provider configuration.

UX / Information architecture​

The Cloud settings section is organized into stable groups that do not multiply per provider:

  1. Provider

    • Provider tabs
    • Provider setup panel
    • Status indicator
    • Refresh status / Disconnect / Clear configuration
  2. Connection & Status

    • Last Sync / Last Backup
  3. Sync

    • Enable Sync toggle
    • Sync now
  4. Encryption

    • Passphrase setup / unlock / lock
  5. Backups

    • Upload latest / list / restore / delete
  6. Advanced

    • Backup migration (encrypt/decrypt)
    • Sync maintenance (preview + reset remote sync state)

Provider roadmap​

Dropbox (implemented)​

  • OAuth 2.0 Authorization Code + PKCE via system browser.
  • Tokens stored via main-process secret storage.
  • Provider details expose a safe account label to the renderer.

Google Drive (implemented)​

For each provider we will add:

  • A CloudStorageProvider implementation in Electron main.
  • A connect<Provider>() flow owned by main.
  • Secret storage via the existing SecretStore abstraction.
  • A dedicated provider setup tab panel.

Implementation notes:

  • Google Drive must follow the same security properties as Dropbox:
    • system browser OAuth
    • PKCE
    • no embedded auth webviews
    • no secrets in the renderer

Why only one provider at a time​

Supporting multiple providers simultaneously (e.g. Dropbox + Google Drive) is not β€œjust add another remote.”

It introduces non-trivial questions:

  • Namespacing: are there separate remote roots per provider?
  • Conflict semantics: which remote is authoritative for sync objects?
  • Cost/latency: duplicate uploads, additional rate limiting, and more failure modes.
  • UX: how do we explain β€œSync enabled for two remotes” without confusing or misleading users?

Given those costs, the default policy is:

  • Exactly one configured provider at a time.

Multi-provider future (non-blocking)​

If multi-provider support is ever required, it must be designed explicitly.

A plausible path (not committed):

  • Treat each provider as a separate remote namespace (e.g. remote/<provider>/sync/*).
  • Persist and display a per-provider connection/config status.
  • Require users to choose a single β€œsync authority” provider, while allowing additional providers for backups only.
  • Add explicit migration tools between providers.

Implementation notes​

Key renderer modules:

  • Cloud settings entry: src/components/Settings/CloudSettingsSection.tsx
  • Provider tabs + setup panels:
    • src/components/Settings/cloud/CloudProviderSetupPanel.tsx
    • src/components/Settings/cloud/CloudProviderSetupPanel.*.tsx
  • Cloud store (toasts + OS notifications): src/stores/cloud/useCloudStore.ts

Key main-process modules:

  • Orchestration: electron/services/cloud/CloudService.ts
  • Provider configuration + validation: electron/services/cloud/CloudService.providerOperations.ts
  • Provider: electron/services/cloud/providers/dropbox/*
  • Provider: electron/services/cloud/providers/googleDrive/*
  • Provider: electron/services/cloud/providers/FilesystemCloudStorageProvider.ts
  • Provider resolution: electron/services/cloud/internal/resolveCloudProviderOrNull.ts

Renderer-facing validation posture:

  • The renderer treats CloudStatusSummary as the source of truth.
  • UI must handle the three distinct states:
    • not configured
    • configured but not connected (for example, auth revoked or offline)
    • connected
  • Do not infer β€œconnected” based on which tab is selected; only the status summary determines readiness.

Testing & validation​

  • npm run lint:fix
  • npm run type-check:all
  • npm test

Provider setup UI is validated indirectly through store/service tests and static typing.

Consequences​

  • Pro: Settings stays readable and scalable as providers are added.
  • Pro: Clear constraints around β€œone provider at a time” reduce user confusion and correctness risk.
  • Con: Users cannot enable redundant remotes (e.g. Dropbox + Google Drive) until an explicit multi-provider design exists.
  • ADR-005: IPC Communication Protocol
  • ADR-009: Validation Strategy
  • ADR-012: Notifications and Alerting
  • ADR-015: Cloud Sync and Remote Backup Providers
  • ADR-016: Multi-Device Sync Model

Review​

  • 2025-12-15: Initial version created alongside provider-tab UI refactor.