Files
kite/.planning/phases/12.1-fix-nextcloud-root-listing-and-sync-visibility/12.1-03-PLAN.md
T
curo1305andClaude Sonnet 4.6 73328eee0b docs(12.1): add phase 12.1 planning artifacts — Nextcloud root listing fix
Plans 01–04, CONTEXT, PATTERNS, RESEARCH, UAT, and .gitkeep for
the fix-nextcloud-root-listing-and-sync-visibility sub-phase.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 20:34:47 +02:00

15 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
12.1 03 tdd 3
12.1-02
frontend/src/views/CloudFolderView.vue
frontend/src/stores/cloudConnections.js
frontend/src/components/cloud/CloudProviderTreeItem.vue
frontend/src/components/cloud/CloudFolderTreeItem.vue
frontend/src/components/storage/StorageBrowser.vue
frontend/src/views/__tests__/CloudFolderView.test.js
frontend/src/stores/__tests__/cloudConnections.test.js
frontend/src/components/cloud/__tests__/CloudProviderTreeItem.test.js
frontend/src/components/cloud/__tests__/CloudFolderTreeItem.test.js
frontend/src/components/storage/__tests__/StorageBrowser.skeleton.test.js
frontend/src/components/cloud/__tests__/CloudBreadcrumbNavigation.test.js
backend/main.py
frontend/package.json
frontend/package-lock.json
AGENTS.md
README.md
RUNBOOK.md
SECURITY.md
true
CLOUD-01
CONN-04
SYNC-01
truths artifacts key_links
Cloud UI classifies items only with kind and never relies on the absent is_dir field
Folder navigation sends provider_item_id while stable DocuVault id remains the row key/metadata identity
The frontend renders response.freshness and never manufactures fresh state or a browser-clock refresh timestamp after HTTP 200
Cached rows remain visible and navigable while freshness is refreshing or warning
Opaque provider references, including slashes, question marks, hashes, percent signs, spaces, and Unicode, are transported without path interpretation
Breadcrumbs come from explicit navigation lineage and never split provider_item_id into path segments
CloudFolderView remains a thin data provider and StorageBrowser remains the single file browser
path provides contains
frontend/src/views/CloudFolderView.vue Normalized item split, provider-reference navigation, and server freshness mapping provider_item_id
path provides contains
frontend/src/views/__tests__/CloudFolderView.test.js kind/provider_item_id/truthful-freshness regressions warning
path provides contains
frontend/src/components/cloud/__tests__/CloudFolderTreeItem.test.js Nested folder kind and provider reference tests provider_item_id
from to via pattern
CloudBrowseResponse.items[].kind StorageBrowser folders/files props CloudFolderView computed classification kind === 'folder'
from to via pattern
folder click/tree expansion GET /api/cloud/connections/{id}/items?parent_ref= provider_item_id, never CloudItem.id provider_item_id
from to via pattern
CloudBrowseResponse.freshness StorageBrowser/BreadcrumbBar freshness props Pinia browse state refresh_state|last_refreshed_at
Align the cloud frontend with the normalized API. Use `kind` for classification, `provider_item_id` for provider navigation, stable `id` for DocuVault row identity, and backend freshness as the only source of synchronization truth.

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/phases/12.1-fix-nextcloud-root-listing-and-sync-visibility/12.1-CONTEXT.md @.planning/phases/12.1-fix-nextcloud-root-listing-and-sync-visibility/12.1-PATTERNS.md @.planning/phases/12-cloud-resource-foundation/12-03-PLAN.md @frontend/src/views/CloudFolderView.vue @frontend/src/stores/cloudConnections.js @frontend/src/components/storage/StorageBrowser.vue Task 1: Add red normalized-item and navigation regressions frontend/src/views/__tests__/CloudFolderView.test.js, frontend/src/components/cloud/__tests__/CloudProviderTreeItem.test.js, frontend/src/components/cloud/__tests__/CloudFolderTreeItem.test.js, frontend/src/components/storage/__tests__/StorageBrowser.skeleton.test.js, frontend/src/components/cloud/__tests__/CloudBreadcrumbNavigation.test.js - frontend/src/views/CloudFolderView.vue — current is_dir filtering, item.id navigation, and fabricated freshness - frontend/src/components/cloud/CloudProviderTreeItem.vue — root folder filtering - frontend/src/components/cloud/CloudFolderTreeItem.vue — nested filtering and navigation - frontend/src/components/storage/StorageBrowser.vue — shared row keys/events and freshness props - frontend/src/components/cloud/__tests__/CloudBreadcrumbNavigation.test.js — explicit lineage and opaque-reference breadcrumb regressions - backend/api/cloud/schemas.py — canonical response shape Replace legacy-shaped fixtures with realistic CloudItemOut objects containing distinct `id` and `provider_item_id`, `kind`, nullable metadata, and no `is_dir`. Add tests named `renders_kind_folder_and_file_in_shared_browser`, `folder_click_uses_provider_item_id_not_id`, `tree_expansion_filters_kind_folder`, `nested_tree_uses_provider_item_id`, and `stable_docuvault_id_remains_row_key`. Include duplicate display names with distinct IDs/references so tests cannot pass accidentally by name.
Add opaque-reference fixtures containing `/`, `?`, `#`, `%`, spaces, and Unicode. Assert CloudFolderView only passes props/emits events through StorageBrowser and does not add another grid/tree implementation. Verify root sentinel remains `parent_ref=null` at the API boundary and nested folders pass their opaque provider reference unchanged through named Vue Router navigation and the API client's query serializer—never manual route-string interpolation.

Add breadcrumb tests proving labels and navigation refs come from an explicit session-only lineage of visited `{name, provider_item_id}` folder nodes (or equivalent API-provided ancestors), not `split('/')` or any other parsing of provider references. Breadcrumb clicks must restore the exact stored opaque reference.
- tests fail against current is_dir and item.id behavior - fixtures omit is_dir and distinguish id from provider_item_id - root and nested provider navigation are both covered - StorageBrowser remains the rendered browser component - no test relies on provider-specific path reconstruction in Vue - reserved-character provider references survive route/query transport and breadcrumb navigation unchanged cd frontend && npm test -- --run src/views/__tests__/CloudFolderView.test.js src/components/cloud/__tests__/CloudProviderTreeItem.test.js src/components/cloud/__tests__/CloudFolderTreeItem.test.js src/components/storage/__tests__/StorageBrowser.skeleton.test.js src/components/cloud/__tests__/CloudBreadcrumbNavigation.test.js Red frontend tests reproduce invisible folders and wrong-reference navigation using the actual API shape. Task 2: Make backend freshness authoritative in Pinia and the view frontend/src/stores/cloudConnections.js, frontend/src/views/CloudFolderView.vue, frontend/src/stores/__tests__/cloudConnections.test.js, frontend/src/views/__tests__/CloudFolderView.test.js - frontend/src/stores/cloudConnections.js — folderFreshness and lastRefreshedAt state API - frontend/src/views/CloudFolderView.vue — unconditional fresh/browser-clock assignment - frontend/src/components/ui/BreadcrumbBar.vue — expected refreshing/fresh/warning values and timestamp rendering - frontend/src/views/__tests__/CloudFolderView.test.js — existing fetch/error behavior - frontend/src/stores/__tests__/cloudConnections.test.js — store reset/persistence conventions Add tests `maps_server_refreshing_freshness`, `maps_server_warning_and_last_success`, `http_200_does_not_imply_fresh`, `does_not_use_browser_clock_as_refresh_evidence`, and `cached_items_remain_visible_during_warning`. Map `response.freshness.refresh_state`, `last_refreshed_at`, `error_code`, and controlled `error_message` into Pinia. Keep a request-in-flight UI state only if it cannot overwrite the last authoritative server state; after the response, render the server object verbatim. A successful cached browse response is not proof of provider synchronization.
Remove `new Date().toISOString()` and any unconditional `fresh` assignment from CloudFolderView. On request failure without a server freshness payload, preserve cached items and prior last successful timestamp while showing a controlled client transport warning; never invent a provider refresh time.
- HTTP 200 plus warning freshness renders warning, not fresh - server last_refreshed_at is preserved exactly and browser Date is not called to create evidence - error code/message remain controlled display data and do not affect item ownership/navigation - cached items remain usable during refreshing/warning states - store reset clears cloud browse state without persisting secrets cd frontend && npm test -- --run src/stores/__tests__/cloudConnections.test.js src/views/__tests__/CloudFolderView.test.js The UI reports backend freshness truthfully and preserves cached navigation through warnings. Task 3: Implement normalized item use across cloud view and trees frontend/src/views/CloudFolderView.vue, frontend/src/components/cloud/CloudProviderTreeItem.vue, frontend/src/components/cloud/CloudFolderTreeItem.vue, frontend/src/components/storage/StorageBrowser.vue, frontend/src/views/__tests__/CloudFolderView.test.js, frontend/src/components/cloud/__tests__/CloudProviderTreeItem.test.js, frontend/src/components/cloud/__tests__/CloudFolderTreeItem.test.js, frontend/src/components/cloud/__tests__/CloudBreadcrumbNavigation.test.js - frontend/src/components/ui/TreeItem.vue — shared expand/collapse state contract - frontend/src/components/storage/StorageBrowser.vue — single browser row/event contract - frontend/src/views/CloudFolderView.vue — thin view boundary - frontend/src/components/cloud/CloudProviderTreeItem.vue — root folder source - frontend/src/components/cloud/CloudFolderTreeItem.vue — nested folder source Replace all cloud `is_dir` checks with `item.kind === "folder"` and file checks with `item.kind === "file"`. Route and browse nested folders with `provider_item_id`; retain `id` for Vue keys, selection, and DocuVault metadata identity. Do not add an alias field, provider-specific mapper, alternate browser, or duplicate expand/collapse state. Keep CloudProviderTreeItem and CloudFolderTreeItem wrapped by TreeItem.vue.
Use named-route objects for connection routing and keep `parent_ref` in serialized query/API state; do not interpolate it into a route path. Ensure folder references are encoded only by Vue Router/API query serializers, not manually concatenated or decoded. Maintain explicit session-only breadcrumb lineage from root to visited folders; never reconstruct hierarchy by splitting `provider_item_id`, because Drive/OneDrive IDs and DAV references are opaque. Preserve connection UUID routing from Phase 12. Remove dead compatibility logic in the same change.
- no active cloud component references item.is_dir - every provider browse/navigation call uses provider_item_id for nested parent_ref - stable id remains the rendering/metadata identity and is never sent to a provider adapter - CloudFolderView contains no grid/layout duplication - focused and full cloud frontend suites pass - opaque IDs containing reserved characters and breadcrumb back-navigation round-trip exactly cd frontend && npm test -- --run src/views/__tests__/CloudFolderView.test.js src/components/cloud/__tests__/CloudProviderTreeItem.test.js src/components/cloud/__tests__/CloudFolderTreeItem.test.js src/components/storage/__tests__/StorageBrowser.skeleton.test.js src/stores/__tests__/cloudConnections.test.js src/components/cloud/__tests__/CloudBreadcrumbNavigation.test.js && ! rg '\.is_dir' src/views/CloudFolderView.vue src/components/cloud Cloud folders render and navigate with the canonical API fields while shared component boundaries remain intact. Task 4: Document, security-review, commit, and push Plan 03 AGENTS.md, README.md, RUNBOOK.md, SECURITY.md, .planning/phases/12.1-fix-nextcloud-root-listing-and-sync-visibility/12.1-03-SUMMARY.md Update required docs for normalized cloud UI routing, breadcrumb lineage, and server freshness. Bump the backend/frontend patch version once and synchronize package-lock metadata because the plan changes user-visible behavior. Run a dedicated security agent against this plan's diff, resolving or escalating findings. Run focused/full frontend tests, production build, npm audit, Compose validation, and diff checks. Stage only Plan 03 files, exclude `.env` and unrelated work, commit atomically as `fix(12.1): align cloud browser contract`, and push immediately. docker compose config --quiet && cd frontend && npm test && npm run build && npm audit --audit-level=high && cd .. && git diff --check Plan 03 has independent documentation, security approval, green gates, commit, and push.

<threat_model>

Threat ID Threat Mitigation and evidence
T-12.1-11 DocuVault UUID sent as provider path Distinct-ID fixtures and provider_item_id navigation assertions
T-12.1-12 UI falsely reports provider synchronization Server freshness mapping; no browser-clock evidence
T-12.1-13 Provider reference injected into provider-specific URL API query serialization; adapters own provider translation/validation
T-12.1-14 Secrets persisted in frontend state Existing memory/session rules; tests store folder reference only
T-12.1-15 Parallel browser/tree logic drifts StorageBrowser and TreeItem remain canonical shared components
</threat_model>
1. Demonstrate actual API-shaped fixtures fail current is_dir/item.id code. 2. Verify kind-based root and nested classification. 3. Verify provider_item_id navigation while id remains row identity. 4. Verify warning/refreshing/fresh server payloads and exact timestamps. 5. Search for legacy is_dir usage in active cloud components and run the focused frontend suite.

<success_criteria>

  • Users can see folders/files returned by every normalized provider adapter.
  • Folder clicks and tree expansion use valid provider references.
  • Synchronization wording reflects backend state rather than HTTP status or client time.
  • Shared StorageBrowser/TreeItem architecture remains unchanged. </success_criteria>

Create .planning/phases/12.1-fix-nextcloud-root-listing-and-sync-visibility/12.1-03-SUMMARY.md when complete.