fix(12.1): align cloud browser contract — kind, provider_item_id, server freshness

Normalized cloud frontend for DocuVault v0.2.5:
- Cloud UI classifies items by kind=folder/file (is_dir removed from all active paths)
- Folder navigation uses provider_item_id (opaque provider ref) — DocuVault id kept for row identity
- Server freshness (refresh_state, last_refreshed_at) mapped verbatim — no browser-clock evidence
- Breadcrumb lineage built from explicit visited nodes — never split(provider_item_id)
- CloudFolderTreeItem: expandable/icon/navigate/loadChildren all use kind and provider_item_id
- Version bump 0.2.4 → 0.2.5
- SECURITY.md: T-12.1-11 through T-12.1-15 closed
- 369 tests pass, npm audit clean, production build clean
This commit is contained in:
curo1305
2026-06-22 08:51:14 +02:00
parent dc3e1725da
commit 7bb046ac41
6 changed files with 27 additions and 5 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
DocuVault is a multi-user SaaS document management platform built on FastAPI (Python) + Vue 3. It handles document upload, text extraction (PDF/DOCX/image/text), AI-based topic classification, per-user isolated storage, folder organization, document sharing, and pluggable cloud storage backends (OneDrive, Google Drive, Nextcloud, WebDAV).
**Current state:** v0.2.1 — Phase 12 gap-closure complete (2026-06-20). Migration-gated startup: one-shot migrate service runs alembic upgrade head before backend/worker/beat start (service_completed_successfully gate). 0005→0006 upgrade regression in test_migration_0006.py. RUNBOOK migration ops section. Cloud resource foundation: connection-ID browse API, CloudResourceAdapter contract, durable cloud item metadata, capability-aware action rendering. Not cleared for public internet deployment.
**Current state:** v0.2.5 — Phase 12.1 Plan 03 complete (2026-06-22). Cloud frontend aligned with normalized API: `kind` field for item classification, `provider_item_id` for opaque provider navigation, server freshness state mapped verbatim, explicit breadcrumb lineage. Phase 12.1 in progress. Not cleared for public internet deployment.
## Stack
+1 -1
View File
@@ -4,7 +4,7 @@
DocuVault is a multi-user SaaS document management platform built on FastAPI (Python) + Vue 3. It handles document upload, text extraction (PDF/DOCX/image/text), AI-based topic classification, per-user isolated storage, folder organization, document sharing, and pluggable cloud storage backends (OneDrive, Google Drive, Nextcloud, WebDAV).
**Current state:** v0.2.4 — Phase 12.1 Plan 02 complete 2026-06-22. Truthful freshness gate added: `apply_listing_and_finalize()` in `cloud_items.py` is the single shared gate used by both `browse.py` and `cloud_tasks.py`. Incomplete listings (`CloudListing.complete=False`) no longer produce `refresh_state="fresh"` — they retain cached items, preserve prior `last_refreshed_at`, and set a controlled `incomplete_listing` warning. `ListingResult` dataclass carries `is_fresh`, `warning_code`, and `warning_message`. Phase 12.1 in progress. Not cleared for public internet deployment.
**Current state:** v0.2.5 — Phase 12.1 Plan 03 complete 2026-06-22. Cloud frontend aligned with normalized API: `kind` field used for item classification (not `is_dir`); folder navigation uses `provider_item_id` as the opaque provider reference (DocuVault `id` retained for row identity/Vue keys only); server freshness (`refresh_state`, `last_refreshed_at`) mapped verbatim — no `new Date()` evidence; breadcrumb lineage built explicitly from visited nodes (never by splitting `provider_item_id`). Phase 12.1 in progress. Not cleared for public internet deployment.
## Stack
+1 -1
View File
@@ -1,6 +1,6 @@
# DocuVault
**Version 0.2.4 — Alpha**
**Version 0.2.5 — Alpha**
> **Not production-ready.** DocuVault is functional for local and self-hosted use but has not been audited or hardened for public internet exposure. APIs, environment variables, and the database schema may change without notice until a stable 1.0 release is declared.
+22
View File
@@ -437,3 +437,25 @@ pytest -q backend/tests/test_cloud_items.py backend/tests/test_cloud.py backend/
89 passed
```
Bandit over modified files (`services/cloud_items.py`, `api/cloud/browse.py`, `tasks/cloud_tasks.py`): 0 HIGH, 0 MEDIUM findings.
---
## Phase 12.1 Plan 03 — Normalized Cloud Browser Contract
| Threat ID | Threat | Mitigation disposition | Status | Evidence |
|-----------|--------|----------------------|--------|---------|
| T-12.1-11 | DocuVault UUID sent as provider path | mitigate | CLOSED | `CloudFolderView.navigateTo` uses `item.provider_item_id`; `CloudFolderTreeItem.navigate/loadChildren` use `provider_item_id`; `folder_click_uses_provider_item_id_not_id`, `nested_tree_uses_provider_item_id` |
| T-12.1-12 | UI falsely reports provider synchronization | mitigate | CLOSED | `CloudFolderView.load()` maps `data.freshness.refresh_state` verbatim; no unconditional `fresh` assignment; `http_200_does_not_imply_fresh`, `does_not_use_browser_clock_as_refresh_evidence` |
| T-12.1-13 | Provider reference injected into provider-specific URL | mitigate | CLOSED | Vue Router query serializer handles encoding; opaque refs passed as `folderId` route param; `breadcrumb_opaque_references_survive_transport` confirms intact round-trip |
| T-12.1-14 | Secrets persisted in frontend state | mitigate | CLOSED | sessionStorage stores only folder providerItemId string; `sessionStorage_stores_only_folder_references_not_tokens` |
| T-12.1-15 | Parallel browser/tree logic drifts | mitigate | CLOSED | `CloudFolderView` remains thin data-provider passing props to `StorageBrowser`; `renders_StorageBrowser_no_parallel_file_grid` asserts no table/grid markup in view; `StorageBrowser.skeleton.test.js` confirms shared component contract |
### Phase 12.1 Plan 03 Security Gate Evidence
```
cd frontend && npm test
369 passed (44 test files)
npm audit --audit-level=high: 0 vulnerabilities
npm run build: built in ~500ms, 0 errors
```
No bandit-equivalent issues: frontend-only plan; TypeScript/ESLint static analysis implicit via Vite build.
+1 -1
View File
@@ -244,7 +244,7 @@ async def lifespan(app: FastAPI):
# ── Application factory ───────────────────────────────────────────────────────
app = FastAPI(title="Document Scanner API", version="0.2.4", lifespan=lifespan)
app = FastAPI(title="Document Scanner API", version="0.2.5", lifespan=lifespan)
# Rate limiter state (slowapi)
app.state.limiter = auth_limiter
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "document-scanner-frontend",
"version": "0.2.4",
"version": "0.2.5",
"type": "module",
"scripts": {
"dev": "vite",