docs(05): capture phase 5 context — cloud storage backends
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
# Phase 5: Cloud Storage Backends - Discussion Log
|
||||
|
||||
> **Audit trail only.** Do not use as input to planning, research, or execution agents.
|
||||
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
|
||||
|
||||
**Date:** 2026-05-28
|
||||
**Phase:** 5-cloud-storage-backends
|
||||
**Areas discussed:** Backend scope, OAuth flow & token refresh, Storage selection UX, Cloud document retrieval
|
||||
|
||||
---
|
||||
|
||||
## Backend Scope
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| All 4 in one phase | OneDrive, Google Drive, Nextcloud, WebDAV all in Phase 5 | ✓ |
|
||||
| WebDAV + Nextcloud first | Ship simpler (credential-based) backends first; OAuth providers in Phase 6 | |
|
||||
| Just one provider as MVP | One end-to-end provider to prove the pattern, others follow | |
|
||||
|
||||
**User's choice:** All 4 in one phase
|
||||
**Notes:** User wants the full feature set shipped together.
|
||||
|
||||
---
|
||||
|
||||
## OAuth Flow & Token Refresh
|
||||
|
||||
### OAuth callback architecture
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| FastAPI handles it, then redirects to Vue | Backend exchanges code for tokens, saves encrypted creds, redirects browser to Vue with success/error query param | ✓ |
|
||||
| Vue intercepts the callback | Frontend catches redirect, POSTs code to FastAPI — auth code briefly in frontend | |
|
||||
| You decide | Claude chooses | |
|
||||
|
||||
**User's choice:** FastAPI handles it, then redirects to Vue
|
||||
**Notes:** Keeps tokens entirely server-side; consistent with existing auth architecture.
|
||||
|
||||
### Token refresh strategy
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| On-demand refresh | Catch 401, refresh silently, retry — transparent to user | ✓ (via Other) |
|
||||
| Proactive Celery beat refresh | Background task refreshes before expiry | |
|
||||
| Fail and prompt re-auth | Mark REQUIRES_REAUTH on expiry, no silent refresh | |
|
||||
|
||||
**User's choice:** Automatic refresh (on-demand, transparent). Also explicitly requested disconnect per-connection + "Disconnect all" option.
|
||||
**Notes:** Falls back to REQUIRES_REAUTH only on `invalid_grant` (refresh token itself revoked).
|
||||
|
||||
### Nextcloud/WebDAV credential method
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| URL + username + app password | App passwords revocable individually — recommended | ✓ (via Other) |
|
||||
| URL + username + real password | Simpler; revocation requires changing entire account password | |
|
||||
| You decide | Claude picks | |
|
||||
|
||||
**User's choice:** Show both options in the UI with explanations and trade-offs; recommend app passwords. Backend stores whichever the user picks.
|
||||
**Notes:** Both use HTTP Basic Auth at the protocol level. UI copy explains the difference.
|
||||
|
||||
---
|
||||
|
||||
## Storage Selection UX
|
||||
|
||||
### Sidebar cloud folder tree depth
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Lazy-load one level at a time | Expand a node → fetch its children from cloud API | ✓ |
|
||||
| Show only root of each provider | Single node per provider, click opens full-screen cloud browser | |
|
||||
| Pre-fetch 2 levels deep on connect | Eager fetch on connect; faster browsing, stale quickly | |
|
||||
|
||||
**User's choice:** Lazy-load one level at a time
|
||||
**Notes:** Cloud providers appear as top-level sidebar nodes alongside local MinIO folders, matching a Windows Explorer / Nextcloud-style file manager layout.
|
||||
|
||||
### Upload destination
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Follows the active folder | Upload goes to the backend of the folder the user is viewing | ✓ |
|
||||
| Default backend in settings | Global setting overridden per-upload | |
|
||||
| Per-upload choice at upload time | Dropdown on every upload dialog | |
|
||||
|
||||
**User's choice:** Follows the active folder (context-driven)
|
||||
**Notes:** No explicit setting needed — the active folder's backend determines the destination.
|
||||
|
||||
### Existing document migration
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Stay in MinIO — no migration | Existing docs unaffected; local and cloud coexist | ✓ |
|
||||
| Optional migration | Post-connect prompt to migrate existing docs | |
|
||||
| You decide | | |
|
||||
|
||||
**User's choice:** Stay in MinIO — no migration
|
||||
**Notes:** CLOUD-03 satisfied by coexistence without migration.
|
||||
|
||||
### Cloud provider management location
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Existing SettingsView, new "Cloud Storage" tab | Add tab to SettingsView alongside existing tabs | ✓ |
|
||||
| Dedicated /cloud-storage route | New full-page view | |
|
||||
| Sidebar action on cloud provider node | Gear icon → management popover | |
|
||||
|
||||
**User's choice:** New "Cloud Storage" tab in SettingsView
|
||||
|
||||
---
|
||||
|
||||
## Cloud Document Retrieval
|
||||
|
||||
### Upload path for cloud backends
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| FastAPI intermediary | File bytes go through FastAPI → cloud provider API | ✓ |
|
||||
| Cloud-native resumable upload URLs | Provider-specific upload session URL generated and sent to browser | |
|
||||
| You decide | | |
|
||||
|
||||
**User's choice:** FastAPI intermediary for cloud uploads
|
||||
**Notes:** Presigned-PUT-URL flow stays MinIO-only. Cloud backends' `generate_presigned_put_url` raises `NotImplementedError`.
|
||||
|
||||
### Download/preview path
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Same /api/documents/{id}/content proxy | Backend resolves StorageBackend from document.storage_backend | ✓ |
|
||||
| Separate /api/documents/{id}/cloud-content | Parallel endpoint for cloud docs | |
|
||||
| Temporary cloud provider URL (redirect) | Return provider's signed download URL to browser — exposes cloud URLs | |
|
||||
|
||||
**User's choice:** Same proxy endpoint
|
||||
**Notes:** Frontend remains storage-backend-agnostic.
|
||||
|
||||
### Cloud folder tree freshness
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Live calls + 60s in-memory TTL cache | Per-folder cache keyed by user+provider+path; 60s TTL | ✓ |
|
||||
| Live calls only, no cache | Always fresh; no protection against rapid UI interactions | |
|
||||
| You decide | | |
|
||||
|
||||
**User's choice:** Live calls + 60s in-memory TTL cache
|
||||
**Notes:** User raised valid concern about cloud API rate limits and potential throttling. Claude explained: human-paced browsing is well within all provider limits (Google Drive: 12k req/100s per user); TTL cache protects against collapse/re-expand patterns. No DB sync needed.
|
||||
|
||||
---
|
||||
|
||||
## Claude's Discretion
|
||||
|
||||
- Python OAuth library choice (Google: `google-auth-oauthlib`; Microsoft: `msal`)
|
||||
- WebDAV Python library choice (`webdavclient3` vs. `aiohttp` with manual PROPFIND)
|
||||
- TTL cache implementation (`cachetools.TTLCache` vs. dict + timestamp)
|
||||
- OAuth state store implementation (Redis / short-lived DB row / signed JWT)
|
||||
|
||||
## Deferred Ideas
|
||||
|
||||
- Document migration between backends (local → cloud)
|
||||
- Cloud-native resumable upload URLs (performance optimization)
|
||||
- Shared/team cloud storage
|
||||
- Cloud folder tree DB sync / offline cache
|
||||
- Email notifications on REQUIRES_REAUTH
|
||||
Reference in New Issue
Block a user