Files
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

175 lines
9.1 KiB
Markdown

---
phase: "13"
plan: "05"
type: execute
wave: 3
depends_on:
- "13-01"
- "13-03"
- "13-04"
files_modified:
- backend/api/cloud/operations.py
- backend/api/cloud/schemas.py
- backend/services/cloud_operations.py
- backend/storage/google_drive_backend.py
- backend/storage/onedrive_backend.py
- backend/storage/webdav_backend.py
- backend/tests/test_cloud_mutations.py
- backend/tests/test_cloud_backends.py
- backend/tests/test_cloud_provider_contract.py
autonomous: true
requirements:
- CLOUD-03
must_haves:
truths:
- "Cloud upload uses typed conflict and error bodies instead of hidden overwrite semantics."
- "Provider upload differences stay behind the mutable adapter and service contract."
- "Refreshed provider credentials can be handed upward during upload work without provider-owned database writes."
artifacts:
- path: "backend/api/cloud/operations.py"
provides: "Connection-ID upload endpoint with typed conflict and retry result bodies."
- path: "backend/services/cloud_operations.py"
provides: "Upload dispatch that normalizes keep-both, replace, retryable error, and unsupported-replace outcomes."
key_links:
- from: "provider upload result"
to: "shared queue resume decisions"
via: "typed kind/reason response bodies"
pattern: "conflict"
- from: "refreshed provider credentials"
to: "service-layer persistence handoff"
via: "upload success and retry paths"
pattern: "credentials"
---
<objective>
Implement the bounded backend upload mechanics slice of Phase 13: connection-ID upload routing, typed conflict and retry bodies, provider-normalized keep-both or replace handling, and refreshed-credential handoff without yet folding in reconcile or audit follow-through.
Purpose: Finish the provider and route mechanics the shared upload queue needs before the authoritative success path is layered on top.
Output: Upload-capable provider adapters, route and service dispatch, and passing backend upload mechanics suites.
</objective>
<execution_context>
@$HOME/.codex/gsd-core/workflows/execute-plan.md
@$HOME/.codex/gsd-core/templates/summary.md
</execution_context>
<context>
@AGENTS.md
@.planning/phases/13-virtual-local-cloud-operations/13-CONTEXT.md
@.planning/phases/13-virtual-local-cloud-operations/13-RESEARCH.md
@.planning/phases/13-virtual-local-cloud-operations/13-PATTERNS.md
@backend/api/cloud/operations.py
@backend/services/cloud_operations.py
@backend/storage/google_drive_backend.py
@backend/storage/onedrive_backend.py
@backend/storage/webdav_backend.py
</context>
## Artifacts this phase produces
- Upload support in `backend/api/cloud/operations.py` and `backend/services/cloud_operations.py`.
- Provider-normalized keep-both, replace, retry, skip, and unsupported-replace semantics across Google Drive, OneDrive, Nextcloud-via-WebDAV, and generic WebDAV.
- Passing upload and provider-contract suites for the mechanics half of `CLOUD-03`.
## Pattern analogs
- `backend/api/documents/upload.py` — multipart upload proxy pattern.
- `backend/tests/test_cloud_backends.py` and `backend/tests/test_cloud_provider_contract.py` — four-provider normalization assertions.
- `backend/services/cloud_operations.py` from 13-03 — refreshed-credential handoff and typed domain-result pattern.
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Implement provider-normalized upload conflict semantics across the adapter boundary</name>
<files>backend/storage/google_drive_backend.py, backend/storage/onedrive_backend.py, backend/storage/webdav_backend.py, backend/tests/test_cloud_backends.py, backend/tests/test_cloud_provider_contract.py</files>
<read_first>
- backend/storage/google_drive_backend.py
- backend/storage/onedrive_backend.py
- backend/storage/webdav_backend.py
- backend/tests/test_cloud_backends.py
- backend/tests/test_cloud_provider_contract.py
- .planning/phases/13-virtual-local-cloud-operations/13-CONTEXT.md
</read_first>
<behavior>
- Test 1: upload can return success, typed conflict, typed retryable error, or explicit unsupported-replace results
- Test 2: keep-both naming is authoritative and inserts the counter before the file extension
- Test 3: provider-specific conflict semantics normalize into one shared contract across all four providers
</behavior>
<action>
Implement D-03 and D-04 inside the provider layer so Google Drive, OneDrive, and the shared WebDAV path normalize upload conflicts, replace support, keep-both suffixing, and retryable transient failures into one mutable-operation contract. Preserve broader Google Drive access assumptions, OneDrive refreshed-credential handoff, and SSRF validation on every WebDAV upload request. Keep Nextcloud on the shared WebDAV mutation path unless a narrow override is strictly required.
</action>
<acceptance_criteria>
- upload provider suites pass for all four supported providers
- keep-both naming is authoritative and consistent across providers
- provider code returns typed results and never writes `cloud_items`, audit rows, or router-visible provider payloads directly
</acceptance_criteria>
<verify>
<automated>docker compose run --rm backend pytest -v tests/test_cloud_backends.py tests/test_cloud_provider_contract.py -k "upload or replace or conflict" -x</automated>
</verify>
<done>The adapter layer now exposes typed, provider-normalized upload mechanics for the shared queue.</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Expose connection-ID upload dispatch with typed route and service results</name>
<files>backend/api/cloud/operations.py, backend/api/cloud/schemas.py, backend/services/cloud_operations.py, backend/tests/test_cloud_mutations.py</files>
<read_first>
- backend/api/cloud/operations.py
- backend/api/cloud/schemas.py
- backend/services/cloud_operations.py
- backend/tests/test_cloud_mutations.py
- .planning/phases/13-virtual-local-cloud-operations/13-CONTEXT.md
</read_first>
<behavior>
- Test 1: the upload route returns typed success, conflict, retryable error, and unsupported-replace bodies
- Test 2: the service layer owns refreshed-credential persistence handoff above the provider boundary
- Test 3: queue-control semantics come from backend-authored results instead of Vue-side inference
</behavior>
<action>
Wire the connection-ID upload endpoint through `backend/services/cloud_operations.py` and `backend/api/cloud/schemas.py` so the route returns stable `kind` and `reason` bodies for Keep both, Replace, Skip, Retry, Cancel all, or unsupported-replace outcomes. Keep this plan bounded to mechanics: normalize provider results, surface refreshed credentials upward for encrypted persistence, and leave centralized reconciliation plus metadata-only audit follow-through to the next plan.
</action>
<acceptance_criteria>
- upload route and mutation suites pass for typed mechanics and credential-safe results
- queue-control semantics are backend-authored and credential-safe
- this plan does not yet add upload-specific reconciliation or success-audit behavior outside the existing foundations
</acceptance_criteria>
<verify>
<automated>docker compose run --rm backend pytest -v tests/test_cloud_mutations.py tests/test_cloud_backends.py tests/test_cloud_provider_contract.py -k "upload or replace or conflict" -x</automated>
</verify>
<done>The backend now exposes the bounded upload mechanics the next follow-through plan can finish.</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| browser upload → provider write | User content enters a provider-owned mutation path through DocuVault authorization only. |
| provider SDK/HTTP → route result | Provider conflict, retry, and replace behavior must be normalized before Vue consumes it. |
## STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-13-16 | T | upload conflict handling | mitigate | Typed upload result bodies and provider-contract tests forbid silent overwrite behavior. |
| T-13-17 | I | route result typing | mitigate | Upload route tests verify no provider URLs, tokens, or raw payloads escape typed responses. |
| T-13-18 | T | provider boundary | mitigate | WebDAV SSRF and OneDrive refresh handoff remain covered by provider suites. |
</threat_model>
<verification>
- Pass the bounded backend upload and provider-contract suites.
- Confirm all backend pytest invocations are direct containerized commands.
- Confirm upload mechanics stop at typed route and service results, leaving reconcile and audit follow-through to the next plan.
</verification>
<success_criteria>
- The backend can upload into the current cloud folder with typed conflict and retry semantics.
- Provider-specific differences remain behind the shared contract and service layer.
- The upload mechanics plan stays within 9 files and leaves reconcile plus audit follow-through for the next bounded plan.
</success_criteria>
<output>
Create `.planning/phases/13-virtual-local-cloud-operations/13-05-SUMMARY.md` when done
</output>