Files
kite/.planning/phases/13-virtual-local-cloud-operations/13-PATTERNS.md
T
curo1305andClaude Sonnet 4.6 b67e77dd69 docs(13): add phase 13 planning artifacts — virtual local cloud operations
Plans 01–11, CONTEXT, PATTERNS, RESEARCH, REVIEW-FIX, and updated
SUMMARY and CONTEXT for the virtual-local-cloud-operations phase.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 20:34:57 +02:00

560 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 13: Virtual-Local Cloud Operations - Pattern Map
**Mapped:** 2026-06-22
**Files analyzed:** 33 likely new/modified files
**Analogs found:** 33 / 33 (6 are composite/no-exact)
## Inherited phase rules that stay locked
- Keep `StorageBrowser.vue` as the only file browser. Cloud behavior extends emitted events and props; it does not fork layout. See [AGENTS.md], Phase 12 patterns, and [frontend/src/components/storage/StorageBrowser.vue].
- Keep cloud routing owner-scoped by connection UUID plus opaque `provider_item_id`; never parse provider refs on the client. Primary analogs: [backend/api/cloud/browse.py:183], [frontend/src/views/CloudFolderView.vue:42], [frontend/src/components/cloud/CloudFolderTreeItem.vue:42].
- Keep metadata reconciliation centralized in `reconcile_cloud_listing` / `apply_listing_and_finalize`; provider adapters never write `cloud_items` rows directly. Primary analogs: [backend/services/cloud_items.py:163], [backend/services/cloud_items.py:271].
- Keep service-layer exception discipline: services raise domain errors / `ValueError`, routers translate to `HTTPException`. Primary analogs: [AGENTS.md], [backend/services/cloud_items.py:1].
- Keep audit writes metadata-only and in the callers transaction. Primary analog: [backend/services/audit.py:27].
## File Classification
| Likely file | Role | Data flow | Closest analog | Match |
|---|---|---|---|---|
| `backend/api/cloud/operations.py` | route | request-response + file-I/O + CRUD | `backend/api/cloud/browse.py`, `backend/api/documents/content.py`, `backend/api/documents/upload.py`, `backend/api/folders.py` | composite |
| `backend/api/cloud/connections.py` | route | request-response | itself + `backend/tasks/cloud_tasks.py` | exact |
| `backend/api/cloud/schemas.py` | schema | transform | itself | exact |
| `backend/services/cloud_operations.py` | service | CRUD + transform | `backend/services/cloud_items.py` + `backend/services/audit.py` | composite |
| `backend/services/cloud_items.py` | service | CRUD + batch reconcile | itself | exact |
| `backend/storage/cloud_base.py` | contract | transform | itself | exact |
| `backend/storage/cloud_backend_factory.py` | factory | request-response | itself | exact |
| `backend/storage/google_drive_backend.py` | provider | file-I/O + CRUD | itself | exact |
| `backend/storage/onedrive_backend.py` | provider | file-I/O + CRUD | itself | exact |
| `backend/storage/webdav_backend.py` | provider | file-I/O + CRUD | itself | exact |
| `backend/storage/nextcloud_backend.py` | provider | file-I/O | itself + `webdav_backend.py` | exact |
| `backend/tasks/cloud_tasks.py` | task | event-driven + batch | itself | exact |
| `frontend/src/api/cloud.js` | API client | request-response | itself + `frontend/src/api/documents.js` | exact |
| `frontend/src/stores/cloudConnections.js` | store | state transform | itself | exact |
| `frontend/src/views/CloudFolderView.vue` | thin view | request-response + queue orchestration | itself + `frontend/src/views/FileManagerView.vue` | exact |
| `frontend/src/components/storage/StorageBrowser.vue` | smart component | CRUD UI + queue UI | itself | exact |
| `frontend/src/components/settings/SettingsCloudTab.vue` | smart component | request-response | itself | exact |
| `frontend/src/components/cloud/CloudCredentialModal.vue` | modal/form | request-response | itself | exact |
| `backend/tests/test_cloud.py` | integration test | request-response | itself | exact |
| `backend/tests/test_cloud_security.py` | security-negative test | request-response | itself | exact |
| `backend/tests/test_cloud_backends.py` | provider unit/contract test | file-I/O | itself | exact |
| `backend/tests/test_cloud_provider_contract.py` | provider contract test | transform | itself | exact |
| `backend/tests/test_cloud_items.py` | service/task test | CRUD + batch | itself | exact |
| `backend/tests/test_cloud_mutations.py` | integration/contract test | CRUD + file-I/O | `test_cloud.py` + `test_cloud_security.py` + `test_cloud_items.py` | composite |
| `backend/tests/test_cloud_reconnect.py` | integration/security test | request-response + task | `test_cloud.py` + `test_cloud_items.py` | composite |
| `backend/tests/test_cloud_audit.py` | integration test | transform | `backend/tests/test_audit.py` + `backend/tests/test_cloud.py` | partial |
| `frontend/src/views/__tests__/CloudFolderView.test.js` | view unit test | request-response | itself | exact |
| `frontend/src/views/__tests__/CloudFolderRenderedFlow.test.js` | rendered-flow test | request-response | itself | exact |
| `frontend/src/components/storage/__tests__/StorageBrowser.capabilities.test.js` | component unit test | CRUD UI | itself | exact |
| `frontend/src/components/storage/__tests__/StorageBrowser.cloud-queue.test.js` | component unit test | queue UI | `StorageBrowser.capabilities.test.js` + `FileManagerView.vue` upload flow | composite |
| `frontend/src/views/__tests__/CloudFolderOpenPreview.test.js` | rendered-flow test | request-response + preview | `CloudFolderRenderedFlow.test.js` + document content helpers | composite |
| `frontend/src/stores/__tests__/cloudConnections.test.js` | store unit test | state transform | itself | exact |
| `frontend/src/components/settings/__tests__/SettingsCloudTab.test.js` | component unit test | request-response | itself | exact |
| `frontend/src/components/settings/__tests__/SettingsCloudTab.health.test.js` | component unit test | health/reconnect UI | `SettingsCloudTab.test.js` + store freshness tests | partial |
## Pattern Assignments
### `backend/api/cloud/operations.py`
**Primary analogs**
- Route/dependency skeleton: [backend/api/cloud/browse.py:19-42], [backend/api/cloud/browse.py:183-214]
- Connection settings/test/update/disconnect patterns: [backend/api/cloud/connections.py:368-434], [backend/api/cloud/connections.py:492-579], [backend/api/cloud/connections.py:604-635]
- Authorized byte streaming and cloud-error translation: [backend/api/documents/content.py:50-103]
- Multipart upload proxy pattern: [backend/api/documents/upload.py:122-198]
- Local create/rename/delete/move handler shape: [backend/api/folders.py:122-160], [backend/api/folders.py:232-265], [backend/api/folders.py:268-351], [backend/api/folders.py:357-375]
**Copy these conventions**
- Use `get_regular_user`, `get_db`, `account_limiter`, and `request.state.current_user = current_user` exactly like cloud browse/connections.
- Resolve ownership through `resolve_owned_connection(...)` before any provider action.
- Translate provider/service failures to controlled `HTTPException` messages like document content/upload already do; do not surface raw provider text.
- For open/preview/download, copy the `StreamingResponse` + `CloudConnectionError` mapping from `content.py`, but key authorization off cloud connection/item ownership instead of `Document`.
- For upload/create/rename/move/delete, keep router bodies thin: validate request shape, call service, return whitelisted schema, write no inline reconciliation logic.
**No exact analog**
- There is no existing single cloud route file that combines owner-scoped connection actions with content proxying and normalized mutation results. Keep the file shaped like `browse.py`, but borrow handler bodies from the document/folder routers above.
### `backend/api/cloud/connections.py`
**Primary analogs**
- WebDAV connect and health-check flow: [backend/api/cloud/connections.py:368-434]
- Credential update flow: [backend/api/cloud/connections.py:492-579]
- Display-name rename: [backend/api/cloud/connections.py:582-601]
- Disconnect confirmation target: [backend/api/cloud/connections.py:604-635]
**Copy these conventions**
- Keep `_get_owned_connection(...)` for owner checks.
- Keep URL validation before backend construction.
- Keep audit writes adjacent to the successful state change.
- If reconnect/test routes are added, model them after `connect_webdav` + `update_webdav_credentials`: validate, health-check, persist, audit, commit.
**Phase 13-specific caution**
- The current OAuth callback always inserts a new row (`_upsert_cloud_connection = _insert_cloud_connection`) at [backend/api/cloud/connections.py:128-129]. Do not copy that behavior for reconnect; Phase 13 needs connection-row preservation.
### `backend/api/cloud/schemas.py`
**Primary analog**
- Current cloud whitelist schemas: [backend/api/cloud/schemas.py:17-86]
**Copy these conventions**
- Add only explicit allowlist response/request models.
- Keep validators at schema level for user-submitted fields, as in `ConnectionRenameRequest`.
- Keep credentials, provider URLs, and raw provider payloads out of every schema.
**No exact analog**
- There is no current normalized mutation-result schema. Add new result types beside `CloudBrowseResponse`, not in routers.
### `backend/services/cloud_operations.py`
**Primary analogs**
- Owner resolution / stable identity / folder freshness: [backend/services/cloud_items.py:38-62], [backend/services/cloud_items.py:97-159], [backend/services/cloud_items.py:271-342]
- Metadata-only audit helper: [backend/services/audit.py:27-58]
- Background refresh orchestration: [backend/tasks/cloud_tasks.py:50-163]
**Copy these conventions**
- Accept UUIDs/strings the same way `cloud_items.py` does.
- Raise domain errors or `ValueError`, never `HTTPException`.
- Reconcile and finalize folder state before returning success.
- Write audit rows through `write_audit_log(...)`, letting the caller own the transaction.
**No exact analog**
- There is no existing service that turns provider mutation outcomes into normalized API results. Treat this as the new orchestration seam; do not push that logic into routers or providers.
### `backend/services/cloud_items.py`
**Primary analog**
- Keep using the current service itself.
**Copy these conventions**
- Owner resolution: [backend/services/cloud_items.py:38-62]
- Stable upsert-by-`(connection_id, provider_item_id)`: [backend/services/cloud_items.py:97-159]
- Complete-vs-incomplete reconciliation: [backend/services/cloud_items.py:163-213]
- Single freshness gate: [backend/services/cloud_items.py:271-342]
- Controlled folder-state updates: [backend/services/cloud_items.py:345-384]
**Planner note**
- Any mutation service should feed its authoritative provider result back through these primitives instead of adding direct ORM writes elsewhere.
### `backend/storage/cloud_base.py`
**Primary analog**
- Keep extending the current contract file itself: [backend/storage/cloud_base.py:27-245]
**Copy these conventions**
- Stable action vocabulary and reason codes live here, not in routers or Vue.
- Immutable normalized dataclasses (`CloudCapability`, `CloudResource`, `CloudListing`) are the pattern to follow for new mutation result types.
- Keep provider-specific branching out of the shared contract.
**No exact analog**
- There is no Phase-13 mutation result/value type yet. New normalized result dataclasses belong here.
### `backend/storage/cloud_backend_factory.py`
**Primary analog**
- Current factory and adapter assertion: [backend/storage/cloud_backend_factory.py:7-66]
**Copy these conventions**
- Keep lazy imports.
- Keep Nextcloud URL normalization in the factory boundary.
- If a mutable-adapter subclass is introduced, assert the interface here instead of switching on provider names in routers.
### `backend/storage/google_drive_backend.py`
**Primary analog**
- Existing upload/download/delete/list/capability patterns: [backend/storage/google_drive_backend.py:140-172], [backend/storage/google_drive_backend.py:174-207], [backend/storage/google_drive_backend.py:257-272], [backend/storage/google_drive_backend.py:276-417]
**Copy these conventions**
- Wrap SDK calls in `asyncio.to_thread()`.
- Centralize provider error classification in helper methods like `_handle_http_error(...)`.
- Normalize provider metadata into `CloudResource` objects.
- Keep the backend stateless: it may return refreshed credentials or typed errors, but must not write DB state directly.
### `backend/storage/onedrive_backend.py`
**Primary analog**
- Existing token lifecycle + upload/download/delete/list/capabilities: [backend/storage/onedrive_backend.py:83-154], [backend/storage/onedrive_backend.py:158-218], [backend/storage/onedrive_backend.py:220-245], [backend/storage/onedrive_backend.py:280-409]
**Copy these conventions**
- Refresh token on demand inside the backend boundary.
- Keep Graph HTTP async with `httpx`.
- Keep `CloudConnectionError` unified across providers.
**Gap to flag**
- There is no persistence pattern yet for refreshed OneDrive credentials; Phase 13 must add one above the backend, not inside it.
### `backend/storage/webdav_backend.py`
**Primary analog**
- Existing SSRF, PUT/GET/DELETE, list-folder, and capability patterns: [backend/storage/webdav_backend.py:66-137], [backend/storage/webdav_backend.py:139-174], [backend/storage/webdav_backend.py:222-237], [backend/storage/webdav_backend.py:241-370]
**Copy these conventions**
- Re-run `validate_cloud_url(...)` before every outbound request.
- Keep basename/path-traversal protection when building destination names.
- Keep WebDAV-specific overwrite/conflict semantics inside this provider file.
### `backend/storage/nextcloud_backend.py`
**Primary analog**
- Minimal specialization over WebDAV: [backend/storage/nextcloud_backend.py:38-90]
**Copy these conventions**
- Keep Nextcloud as a tiny specialization, not a parallel backend.
- If Phase 13 needs Nextcloud-specific mutation quirks, implement them as narrow overrides that preserve the public contract.
### `backend/tasks/cloud_tasks.py`
**Primary analog**
- Current refresh worker: [backend/tasks/cloud_tasks.py:50-163], [backend/tasks/cloud_tasks.py:175-216]
**Copy these conventions**
- Revalidate ownership inside the worker.
- Decrypt credentials inside the worker, never in broker payload.
- Use sentinel exceptions to separate retryable provider failures from terminal auth failures.
- Reuse this task model if reconnect or stale-metadata recovery needs post-success refresh.
### `frontend/src/api/cloud.js`
**Primary analogs**
- Existing connection browse/config/update methods: [frontend/src/api/cloud.js:11-18], [frontend/src/api/cloud.js:36-50], [frontend/src/api/cloud.js:73-88]
- Cloud upload helper shape: [frontend/src/api/documents.js:48-54]
**Copy these conventions**
- Keep all Phase 13 cloud endpoints behind this domain module.
- Keep connection UUID and encoded `parent_ref` handling here.
- Add new `open/preview/upload/create/rename/move/delete/test/reconnect` helpers here instead of calling raw URLs from views/components.
### `frontend/src/stores/cloudConnections.js`
**Primary analog**
- Current store state and reset/mapping helpers: [frontend/src/stores/cloudConnections.js:33-138]
**Copy these conventions**
- Keep server state translation centralized in the store.
- Keep sessionStorage limited to folder refs only.
- Reset browse state on connection switch.
**No exact analog**
- There is no queue/conflict/resume state machine yet. Add it here only if it is shared across cloud views/settings; otherwise keep queue orchestration in `CloudFolderView`.
### `frontend/src/views/CloudFolderView.vue`
**Primary analogs**
- Existing cloud thin-view contract: [frontend/src/views/CloudFolderView.vue:1-20], [frontend/src/views/CloudFolderView.vue:125-170]
- Local upload / create / rename / move / delete orchestration: [frontend/src/views/FileManagerView.vue:1-30], [frontend/src/views/FileManagerView.vue:103-182]
**Copy these conventions**
- Keep the view thin: store/router/API orchestration only.
- Pass everything into `StorageBrowser`; do not add layout or grid logic here.
- Reuse the local upload queue orchestration style from `FileManagerView`, but Phase 13 needs sequential pause/resume instead of the current all-at-once `Promise.allSettled(...)` placeholder at [frontend/src/views/CloudFolderView.vue:172-181].
- Use toasts and success/error handling the same way `FileManagerView` does.
### `frontend/src/components/storage/StorageBrowser.vue`
**Primary analog**
- Extend the current shared component itself: [frontend/src/components/storage/StorageBrowser.vue:140-275], [frontend/src/components/storage/StorageBrowser.vue:424-681]
**Copy these conventions**
- Props/events are the contract; keep new behavior behind emitted events and prop-driven state.
- Capability-aware buttons and notices stay in this component: [frontend/src/components/storage/StorageBrowser.vue:360-418], [frontend/src/components/storage/StorageBrowser.vue:495-530].
- New folder / rename inline patterns already exist here: [frontend/src/components/storage/StorageBrowser.vue:118-135], [frontend/src/components/storage/StorageBrowser.vue:157-166], [frontend/src/components/storage/StorageBrowser.vue:543-593].
- File move picker and drag-to-move patterns already exist here: [frontend/src/components/storage/StorageBrowser.vue:253-344], [frontend/src/components/storage/StorageBrowser.vue:595-621].
**Gap to flag**
- There is no existing conflict dialog / paused upload queue UI. That is a real no-analog area inside the shared browser and should be added here rather than in a cloud-only component.
### `frontend/src/components/settings/SettingsCloudTab.vue`
**Primary analog**
- Existing settings actions and confirm flows: [frontend/src/components/settings/SettingsCloudTab.vue:21-102], [frontend/src/components/settings/SettingsCloudTab.vue:104-170], [frontend/src/components/settings/SettingsCloudTab.vue:293-359]
**Copy these conventions**
- Keep provider rows, inline status badges, and destructive confirms in one shared settings tab.
- Add Test/Reconnect controls beside existing Connect/Edit/Remove actions; do not create a parallel health screen.
- Keep OAuth initiation in the component and store mutation calls behind the store/API layer.
### `frontend/src/components/cloud/CloudCredentialModal.vue`
**Primary analog**
- Existing submit branching for create vs edit: [frontend/src/components/cloud/CloudCredentialModal.vue:301-323]
**Copy these conventions**
- Keep credential edits inside the modal for WebDAV/Nextcloud.
- If Phase 13 adds explicit “Test connection” before save, hang it off the same API module and modal state machine instead of duplicating form state elsewhere.
### `backend/tests/test_cloud.py`
**Primary analog**
- Current integration coverage for connect/upload/status/browse/rename/refresh: [backend/tests/test_cloud.py:30-65], [backend/tests/test_cloud.py:473-527], [backend/tests/test_cloud.py:532-655], [backend/tests/test_cloud.py:998-1315]
**Copy these conventions**
- Use the shared auth helper pattern and `async_client`.
- Patch provider/network boundaries, not route internals, where possible.
- Assert both HTTP contract and DB side effects.
### `backend/tests/test_cloud_security.py`
**Primary analog**
- Current security-negative suite: [backend/tests/test_cloud_security.py:37-117], [backend/tests/test_cloud_security.py:122-340]
**Copy these conventions**
- Add Phase 13 wrong-owner/admin/credential/no-byte/cross-connection negatives here.
- Keep raw-provider-error sanitization assertions here, not only in happy-path integration tests.
### `backend/tests/test_cloud_backends.py`
**Primary analog**
- Provider backend behavior tests: [backend/tests/test_cloud_backends.py:334-420] and the rest of the files provider sections
**Copy these conventions**
- Provider-specific fixtures, normalized assertions.
- Explicit “never download/mutate while browsing” checks.
- Keep backend tests provider-neutral where possible and provider-specific only where semantics differ.
### `backend/tests/test_cloud_provider_contract.py`
**Primary analog**
- Canonical signature/identity/pagination/no-byte contract: [backend/tests/test_cloud_provider_contract.py:201-276], [backend/tests/test_cloud_provider_contract.py:376-536], [backend/tests/test_cloud_provider_contract.py:659-727]
**Copy these conventions**
- Any new mutable adapter methods should get the same style of canonical contract tests: signature, normalized result, trusted caller identity, no forbidden side effects.
### `backend/tests/test_cloud_items.py`
**Primary analog**
- Owner-scoped service and folder-state tests: [backend/tests/test_cloud_items.py:368-529], [backend/tests/test_cloud_items.py:545-859]
**Copy these conventions**
- Mutation reconciliation tests belong here: stable UUID across rename/move, complete/incomplete behavior, freshness truth, no quota mutation.
### `backend/tests/test_cloud_mutations.py`
**Closest analogs**
- API behavior: [backend/tests/test_cloud.py:473-527], [backend/tests/test_cloud.py:1112-1249]
- Security negatives: [backend/tests/test_cloud_security.py:122-340]
- Reconciliation truth: [backend/tests/test_cloud_items.py:411-499], [backend/tests/test_cloud_items.py:743-859]
**No exact analog**
- There is no existing end-to-end mutation suite for cloud items. Build it as a new file, but follow the helper/fixture style of `test_cloud.py`.
### `backend/tests/test_cloud_reconnect.py`
**Closest analogs**
- Connection lifecycle/status: [backend/tests/test_cloud.py:532-655]
- Worker/freshness behavior: [backend/tests/test_cloud.py:1251-1315], [backend/tests/test_cloud_items.py:545-609]
**No exact analog**
- There is no dedicated reconnect/token-persistence suite today.
### `backend/tests/test_cloud_audit.py`
**Closest analogs**
- Audit helper behavior: [backend/services/audit.py:27-58]
- Inline audit assertions in cloud routes: [backend/api/cloud/connections.py:351-359], [backend/api/cloud/connections.py:422-430], [backend/api/cloud/connections.py:567-575], [backend/api/cloud/connections.py:624-632]
**No exact analog**
- There is no cloud-mutation audit suite today; create one that asserts metadata-only payloads and same-transaction persistence.
### `frontend/src/views/__tests__/CloudFolderView.test.js`
**Primary analog**
- Existing thin-view cloud tests: [frontend/src/views/__tests__/CloudFolderView.test.js:73-294]
**Copy these conventions**
- Stub `StorageBrowser` when the test is about view orchestration only.
- Assert route params, API calls, and props passed to the browser.
### `frontend/src/views/__tests__/CloudFolderRenderedFlow.test.js`
**Primary analog**
- Existing real-browser rendered flow: [frontend/src/views/__tests__/CloudFolderRenderedFlow.test.js:1-260]
**Copy these conventions**
- Render the real `StorageBrowser` when testing end-to-end view/browser interactions.
- Keep only router/API boundaries mocked.
### `frontend/src/components/storage/__tests__/StorageBrowser.capabilities.test.js`
**Primary analog**
- Current accessibility and unsupported-capability suite: [frontend/src/components/storage/__tests__/StorageBrowser.capabilities.test.js:47-257]
**Copy these conventions**
- Assert emitted events, `aria-disabled`, notices, and touch-target classes from the real component.
- Extend this file for new capability buttons only; do not hide cloud actions based on mode.
### `frontend/src/components/storage/__tests__/StorageBrowser.cloud-queue.test.js`
**Closest analogs**
- Capability interaction assertions: [frontend/src/components/storage/__tests__/StorageBrowser.capabilities.test.js:89-190]
- Local upload queue behavior source: [frontend/src/views/FileManagerView.vue:103-128]
**No exact analog**
- There is no existing paused sequential queue test file. Create it as a dedicated component suite around the shared browsers new queue/conflict UI.
### `frontend/src/views/__tests__/CloudFolderOpenPreview.test.js`
**Closest analogs**
- Rendered cloud flow: [frontend/src/views/__tests__/CloudFolderRenderedFlow.test.js:170-260]
- Authorized document content fetch helper: [frontend/src/api/documents.js:60-81]
**No exact analog**
- There is no cloud open/preview rendered-flow test today.
### `frontend/src/stores/__tests__/cloudConnections.test.js`
**Primary analog**
- Existing store tests for selection, freshness, session state: [frontend/src/stores/__tests__/cloudConnections.test.js:28-237]
**Copy these conventions**
- Keep pure store tests focused on mapping and reset behavior.
- If queue state or health-state translation lives in the store, test it here once.
### `frontend/src/components/settings/__tests__/SettingsCloudTab.test.js`
**Primary analog**
- Existing settings-tab tests: [frontend/src/components/settings/__tests__/SettingsCloudTab.test.js:1-132]
**Copy these conventions**
- Mock the store and API module, not network.
- Keep component tests structural and action-trigger oriented.
### `frontend/src/components/settings/__tests__/SettingsCloudTab.health.test.js`
**Closest analogs**
- Existing settings tab structure: [frontend/src/components/settings/__tests__/SettingsCloudTab.test.js:51-132]
- Store freshness/health state assertions: [frontend/src/stores/__tests__/cloudConnections.test.js:160-237]
**No exact analog**
- There is no dedicated health/test/reconnect settings suite yet.
## Shared Patterns to Reuse Everywhere
### Authentication / ownership
- Regular-user-only dependency: [backend/api/cloud/browse.py:29-31], [backend/api/cloud/connections.py:25-27], [backend/api/documents/content.py:24-26]
- Owner resolution before resource work: [backend/api/cloud/browse.py:205-214], [backend/api/cloud/connections.py:132-141], [backend/services/cloud_items.py:38-62]
### Router shape
- Thin routers with typed bodies + `account_limiter`: [backend/api/cloud/connections.py:281-304], [backend/api/cloud/browse.py:183-200], [backend/api/folders.py:122-149]
- Response shaping through explicit Pydantic schemas or dict helpers, never raw ORM/provider payloads: [backend/api/cloud/browse.py:64-97], [backend/api/cloud/schemas.py:17-67]
### Error translation
- `CloudConnectionError` becomes controlled reconnect guidance: [backend/api/documents/upload.py:160-175], [backend/api/documents/content.py:61-76]
- Incomplete/stale provider state becomes controlled warning, not fake success: [backend/services/cloud_items.py:319-342], [backend/api/cloud/browse.py:296-307]
### Audit
- Use `write_audit_log(...)` after successful state change, inside caller-owned transaction: [backend/services/audit.py:27-58]
### Provider boundary
- Providers normalize data and keep SDK/HTTP details private: [backend/storage/google_drive_backend.py:276-362], [backend/storage/onedrive_backend.py:300-386], [backend/storage/webdav_backend.py:241-332]
- Factories own provider construction and URL normalization: [backend/storage/cloud_backend_factory.py:7-66]
### Frontend architecture
- Thin view -> shared browser: [frontend/src/views/CloudFolderView.vue:1-20], [frontend/src/views/FileManagerView.vue:1-30]
- Shared browser owns interaction/layout/state: [frontend/src/components/storage/StorageBrowser.vue:424-681]
- Settings tab owns connection controls, not provider-specific subviews: [frontend/src/components/settings/SettingsCloudTab.vue:21-214]
### Testing
- Integration tests assert API contract plus DB side effect: [backend/tests/test_cloud.py:532-655], [backend/tests/test_cloud.py:1112-1249]
- Security tests assert absence of leaks and forbidden side effects: [backend/tests/test_cloud_security.py:197-301]
- View tests stub the browser for orchestration-only checks; rendered-flow tests use the real browser: [frontend/src/views/__tests__/CloudFolderView.test.js:51-101], [frontend/src/views/__tests__/CloudFolderRenderedFlow.test.js:170-205]
## No-Analog / planner watchlist
1. Provider-neutral mutation result dataclasses do not exist yet. Add them in `backend/storage/cloud_base.py`; do not leak provider payloads.
2. OAuth reconnect that patches an existing connection row does not exist yet. Current callback flow inserts a new row.
3. Shared paused upload queue UI for cloud conflicts/errors does not exist yet. Add it in `StorageBrowser.vue`, not a cloud-only component.
4. Authorized cloud-item preview/open endpoints do not exist yet. Reuse document content streaming patterns, but this is a new endpoint family.
5. Dedicated reconnect/audit/open-preview test suites do not exist yet; create them instead of overloading unrelated files.
## Recommended implementation order from pattern proximity
1. Extend `cloud_base.py` + provider backends + factory.
2. Add `cloud_operations.py` and keep all reconciliation through `cloud_items.py`.
3. Add `api/cloud/operations.py`, then minimally extend `connections.py` / `schemas.py`.
4. Extend `api/cloud.js` + `cloudConnections.js` + `CloudFolderView.vue`.
5. Extend `StorageBrowser.vue` and `SettingsCloudTab.vue`.
6. Add the missing dedicated backend/frontend test files before broad polish.
## PATTERN MAPPING COMPLETE