Files
2026-06-18 22:30:07 +02:00

7.7 KiB
Raw Permalink Blame History

Phase 12: Cloud Resource Foundation - Pattern Map

Mapped: 2026-06-18 Status: Complete

Purpose

Map Phase 12 files and data flow to existing DocuVault patterns so implementation extends established architecture without duplicating helpers, grids, or provider-specific UI logic.

Backend Pattern Map

New/changed area Closest analog Pattern to preserve
backend/migrations/versions/0006_cloud_resource_foundation.py 0005_system_settings.py Typed Alembic table creation, named constraints/indexes, timezone timestamps, exact down_revision="0005", reversible downgrade
CloudItem and connection fields in backend/db/models.py CloudConnection, Document, Folder UUID PKs, explicit owner FKs with cascade, compound owner/navigation indexes, human names in DB only
backend/storage/cloud_base.py backend/storage/base.py, backend/ai/base.py Small abstract interface; normalized domain values; provider adapters own translation
Provider capability/metadata normalization Existing Google/OneDrive/Nextcloud adapters Keep SDK/HTTP details inside provider files, wrap synchronous SDK calls with asyncio.to_thread(), preserve canonical CloudConnectionError import
backend/services/cloud_items.py Owner-scoped query patterns in api/folders.py, service exception policy in AGENTS.md Filter by owner in every statement; service raises ValueError/domain exceptions, never HTTPException; use shared deps.utils.parse_uuid at router boundary
backend/api/cloud/ package backend/api/documents/ and backend/api/admin/ One aggregator owns /api/cloud; sub-routers have no prefix; root empty-path routes register on parent if FastAPI requires it
Cloud response schemas CloudConnectionOut in backend/api/schemas.py Explicit field whitelist with from_attributes; never serialize ORM objects or credentials_enc directly
Metadata refresh/backoff Celery retry conventions in document tasks Bounded exponential retry, idempotent upsert/reconciliation, no retry around ownership/validation failures

Required Backend Corrections

  • Current _upsert_cloud_connection() and _get_active_connection() use (user_id, provider) and must not be copied. Phase 12 uses connection UUID as identity to support multiple same-provider accounts.
  • Current listing cache key {user_id}:{provider}:{folder_id} is insufficient. Any transitional key includes connection UUID; durable metadata belongs in PostgreSQL.
  • Current provider listing dictionaries contain only id, name, is_dir, size. New adapters normalize parent, MIME/type, mtime, etag/version, per-item capabilities, and completeness/pagination.
  • api/folders.py contains a private _parse_uuid; new cloud routers must import parse_uuid from backend/deps/utils.py under the projects shared-helper rule.

Frontend Pattern Map

New/changed area Closest analog Pattern to preserve
Capability-aware rows frontend/src/components/storage/StorageBrowser.vue This remains the only grid; props drive layout/state and generic events travel upward
Sync indicator frontend/src/components/ui/BreadcrumbBar.vue Extend shared breadcrumb rather than adding cloud-only breadcrumb markup
Connection roots Current CloudStorageView.vue plus StorageBrowser.vue View owns store/router only; feed normalized root rows into shared browser
Cloud folder route CloudFolderView.vue, FileManagerView.vue Thin data provider; no duplicated toolbar, row, action, or tooltip layout
API functions frontend/src/api/cloud.js + client.js barrel Change route arguments behind the domain module; consumers retain barrel imports
Connection state frontend/src/stores/cloudConnections.js Pinia owns connection/folder state and errors; components stay store-agnostic
Shared formatting frontend/src/utils/formatters.js Reuse formatDate, formatSize, and provider helpers; do not redefine locally
Icons frontend/src/components/ui/AppIcon.vue Add registry entries only when an existing icon name cannot express status/action

UI Contract Patterns

  • Unsupported actions use aria-disabled="true", remain focusable/tappable, and suppress action emission while surfacing explanation.
  • Permanent unsupported state is gray; temporary unavailable state is amber. Do not hide actions based on mode === "local".
  • StorageBrowser receives capabilities, folder freshness, connection root, last refresh time, and byte availability as props.
  • Local storage supplies a supported capability set so local/cloud share one rendering path.
  • Minimum touch target stays 36x36 px and all controls use existing indigo focus-ring utilities.
  • Session-only last folder state uses sessionStorage keyed by connection UUID; JWT tokens remain Pinia-memory-only.

Testing Pattern Map

Coverage Existing analog Phase 12 use
API/ownership backend/tests/test_cloud.py Multiple same-provider accounts, foreign connection/item 404, admin rejection, credential exclusion
Adapter contracts backend/tests/test_cloud_backends.py Shared normalized fixtures, async methods, pagination/completeness, no destructive probes
DB/service async fixtures in backend/tests/conftest.py Fast SQLite unit loop plus marked real-PostgreSQL constraint/index/cascade tests
Pinia frontend/src/stores/__tests__/cloudConnections.test.js Connection UUID routes, duplicate providers, freshness/error transitions
Storage browser StorageBrowser.dragmove/showSearch/skeleton.test.js Capability rendering, action suppression, focus/tap explanations, local regression
Breadcrumb components/ui/__tests__/BreadcrumbBar.test.js Refreshing/fresh/warning labels, timestamps, fade behavior
Thin views views/__tests__/FileManagerView.test.js Cloud views pass props/handle events without grid duplication

Data Flow

  1. Router authenticates regular user and parses connection_id with shared request helpers.
  2. Service resolves (connection_id, user_id) and reads durable children by connection/parent.
  3. Provider adapter normalizes a complete paginated listing and capability states.
  4. Service upserts metadata using (connection_id, provider_item_id) and reconciles only after complete success.
  5. Explicit Pydantic schemas return rows, capability messages, freshness, and connection identity without credentials.
  6. Pinia/view maps API data into StorageBrowser; the browser renders shared rows/actions and emits generic commands.
  7. Browse never calls provider byte download, writes MinIO, or changes quota.

Files Likely Modified

Backend

  • backend/migrations/versions/0006_cloud_resource_foundation.py
  • backend/db/models.py
  • backend/storage/cloud_base.py
  • backend/storage/cloud_backend_factory.py
  • provider backend modules
  • backend/services/cloud_items.py
  • backend/api/cloud/__init__.py, connections.py, browse.py, schemas.py
  • backend/main.py only if aggregator import changes
  • focused backend tests and PostgreSQL integration coverage

Frontend

  • frontend/src/api/cloud.js
  • frontend/src/stores/cloudConnections.js
  • frontend/src/router/index.js
  • frontend/src/views/CloudStorageView.vue
  • frontend/src/views/CloudFolderView.vue
  • frontend/src/components/storage/StorageBrowser.vue
  • frontend/src/components/ui/BreadcrumbBar.vue
  • focused component/store/view tests

Documentation/Versioning

  • AGENTS.md, README.md, backend/main.py, and frontend/package.json per the project documentation/version protocol after user-facing plan completion.

PATTERN MAPPING COMPLETE