104 lines
7.7 KiB
Markdown
104 lines
7.7 KiB
Markdown
# 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 project’s 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
|