ADR-021: Cloud Provider Selection and Settings UI
Table of Contentsβ
- Status
- Context
- Decision drivers
- Decision
- UX / Information architecture
- Provider roadmap
- Why only one provider at a time
- Multi-provider future (non-blocking)
- Implementation notes
- Testing & validation
- Consequences
- Related ADRs
- 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β
- Scalability: the UI must support multiple providers without growing vertically into a wall of buttons.
- Clarity: users must understand which provider is active and what actions are safe.
- Safety: avoid ambiguous βtwo remotesβ state until conflict semantics are designed.
- Consistency: provider setup must follow a consistent pattern across providers.
- 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:
-
Provider
- Provider tabs
- Provider setup panel
- Status indicator
- Refresh status / Disconnect / Clear configuration
-
Connection & Status
- Last Sync / Last Backup
-
Sync
- Enable Sync toggle
- Sync now
-
Encryption
- Passphrase setup / unlock / lock
-
Backups
- Upload latest / list / restore / delete
-
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
CloudStorageProviderimplementation in Electron main. - A
connect<Provider>()flow owned by main. - Secret storage via the existing
SecretStoreabstraction. - 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.tsxsrc/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
CloudStatusSummaryas 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:fixnpm run type-check:allnpm 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.
Related ADRsβ
- 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.