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>
175 lines
9.1 KiB
Markdown
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>
|