Compare commits

...
2 Commits
Author SHA1 Message Date
curo1305 97c30c3a15 docs(12): plan cloud UAT gap fixes 2026-06-21 22:21:05 +02:00
curo1305 70ed1219a9 test(12): pause UAT - 1 passed, 2 issues, 3 blocked 2026-06-21 22:18:14 +02:00
2 changed files with 302 additions and 18 deletions
@@ -0,0 +1,216 @@
---
phase: "12"
plan: "06"
type: gap_closure
wave: 1
depends_on:
- "12-05"
files_modified:
- backend/api/cloud/connections.py
- backend/tests/test_cloud.py
- backend/tests/test_cloud_security.py
- frontend/src/api/cloud.js
- frontend/src/api/utils.js
- frontend/src/components/cloud/CloudCredentialModal.vue
- frontend/src/components/cloud/CloudProviderTreeItem.vue
- frontend/src/components/cloud/CloudFolderTreeItem.vue
- frontend/src/components/layout/AppSidebar.vue
- frontend/src/components/settings/SettingsCloudTab.vue
- frontend/src/components/storage/StorageBrowser.vue
- frontend/src/views/CloudFolderView.vue
- frontend/src/views/CloudStorageView.vue
- frontend/src/components/cloud/__tests__/CloudCredentialModal.test.js
- frontend/src/components/cloud/__tests__/CloudProviderTreeItem.test.js
- frontend/src/components/cloud/__tests__/CloudFolderTreeItem.test.js
- frontend/src/components/layout/__tests__/AppSidebar.test.js
- frontend/src/components/settings/__tests__/SettingsCloudTab.test.js
- frontend/src/views/__tests__/CloudFolderView.test.js
- frontend/src/views/__tests__/CloudStorageView.test.js
- backend/main.py
- frontend/package.json
- frontend/package-lock.json
- AGENTS.md
- CLAUDE.md
- README.md
- SECURITY.md
autonomous: true
requirements:
- CONN-04
- CLOUD-01
- CLOUD-08
must_haves:
truths:
- "A successful Nextcloud connection opens through its UUID and never calls the UUID browse endpoint with a provider slug"
- "A user can create, rename, edit, browse, and remove two independent connections for the same provider"
- "Cloud folder breadcrumbs read Cloud > connection display name > folder hierarchy and every non-current segment navigates correctly even when synchronization fails"
- "Only the deepest applicable cloud sidebar node is highlighted; the generic Cloud Storage link is active only on the provider overview"
- "Validation failures show a useful field/provider message rather than bare HTTP 422"
artifacts:
- path: "backend/api/cloud/connections.py"
provides: "Independent connection creation and connection-ID credential update semantics"
contains: "connection_id"
- path: "frontend/src/components/cloud/CloudProviderTreeItem.vue"
provides: "UUID-based provider root browsing and route-aware selection"
contains: "connection.id"
- path: "frontend/src/views/CloudFolderView.vue"
provides: "Cloud > connection > folder breadcrumb mapping"
contains: "connectionRoot"
- path: "frontend/src/components/settings/SettingsCloudTab.vue"
provides: "Per-provider connection lists with Add account action"
contains: "connectionsFor"
- path: "backend/tests/test_cloud.py"
provides: "Two same-provider connections and exact successful-connect-to-browse regression"
contains: "same_provider"
key_links:
- from: "frontend/src/components/cloud/CloudProviderTreeItem.vue"
to: "GET /api/cloud/connections/{connection_id}/items"
via: "connection UUID passed to API and /cloud/:connectionId route"
pattern: "getCloudFoldersByConnectionId.*connection.id"
- from: "frontend/src/components/settings/SettingsCloudTab.vue"
to: "backend/api/cloud/connections.py"
via: "POST creates; connection-ID update edits exactly one account"
pattern: "connectionsFor|connectionId"
- from: "frontend/src/views/CloudFolderView.vue"
to: "frontend/src/components/ui/BreadcrumbBar.vue"
via: "Cloud root plus connection and folder segment IDs"
pattern: "Cloud.*connectionRoot"
---
<objective>
Close the second Phase 12 UAT gap set: remove the remaining provider-keyed cloud navigation, implement genuinely independent same-provider connections, and make breadcrumb/sidebar state accurately represent the active cloud location.
The observed Nextcloud POST succeeded with HTTP 201. The subsequent sidebar navigation used `/cloud/nextcloud/root`, causing `CloudFolderView` to send `nextcloud` to the UUID endpoint and receive HTTP 422. Same-provider creation is separately blocked by backend provider upsert semantics and Settings' `connectionFor(provider)` first-match rendering.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/phases/12-cloud-resource-foundation/12-UAT.md
@.planning/phases/12-cloud-resource-foundation/12-UI-SPEC.md
@.planning/phases/12-cloud-resource-foundation/12-VALIDATION.md
@backend/api/cloud/connections.py
@backend/api/cloud/browse.py
@frontend/src/views/CloudFolderView.vue
@frontend/src/components/layout/AppSidebar.vue
@frontend/src/components/settings/SettingsCloudTab.vue
</context>
<tasks>
<task type="auto">
<name>Task 1: Make cloud connection lifecycle connection-ID native</name>
<files>backend/api/cloud/connections.py, backend/tests/test_cloud.py, backend/tests/test_cloud_security.py, frontend/src/api/cloud.js, frontend/src/api/utils.js, frontend/src/components/cloud/CloudCredentialModal.vue, frontend/src/components/settings/SettingsCloudTab.vue, frontend/src/components/settings/__tests__/SettingsCloudTab.test.js, frontend/src/components/cloud/__tests__/CloudCredentialModal.test.js</files>
<read_first>
- backend/api/cloud/connections.py — provider upsert, OAuth state, WebDAV create/config/delete paths
- backend/api/cloud/schemas.py — whitelisted credential-free output schemas
- backend/tests/test_cloud.py — existing Nextcloud create and connection-ID regressions
- backend/tests/test_cloud_security.py — owner scoping and credential-exclusion assertions
- frontend/src/components/settings/SettingsCloudTab.vue — first-match connectionFor rendering
- frontend/src/components/cloud/CloudCredentialModal.vue — create/edit currently share provider POST
- frontend/src/api/utils.js — structured 422 detail is currently discarded
</read_first>
<action>
Replace `_upsert_cloud_connection(user_id, provider)` semantics with explicit operations: creating a connection always inserts a new UUID row; editing/reconnecting credentials targets an owner-scoped connection ID and never changes another same-provider row. Add a credential-update endpoint for WebDAV/Nextcloud keyed by connection UUID; preserve the existing password when an edit omits a replacement, and validate/health-check the resulting credentials before commit. Keep OAuth creation independent as well: initiation state must distinguish a new account from a connection-ID reconnect/edit, and callback updates only the explicitly owner-scoped connection when reconnecting. Never put credentials in OAuth state, broker payloads, responses, logs, or audit metadata.
Refactor SettingsCloudTab from `connectionFor(provider)` to `connectionsFor(provider)`: render every connection as its own named row with Rename/Edit/Remove actions and retain an always-visible Add account control for each provider. CloudCredentialModal receives an existing connection ID and calls the ID update endpoint for edits; new connections call POST. Use effective custom/default names consistently and disambiguate duplicate defaults without exposing UUIDs beyond a short visual suffix where required by the UI contract.
Improve `request()` error normalization so FastAPI validation arrays become concise field messages and controlled API detail strings remain intact. This is diagnostic hardening; do not leak response internals or credentials.
</action>
<acceptance_criteria>
- two POSTs for Nextcloud by one user create two distinct connection UUIDs and retain independent encrypted credentials
- editing/reconnecting one connection changes only that connection; wrong-owner IDs return 404 and disclose nothing
- Settings shows both same-provider accounts plus Add Nextcloud, and actions address the selected UUID
- bare HTTP 422 is replaced by a controlled actionable message
- create/update/list responses exclude `credentials_enc`, passwords, tokens, and raw provider objects
</acceptance_criteria>
<verify><automated>docker compose exec -T backend pytest -q tests/test_cloud.py tests/test_cloud_security.py &amp;&amp; cd frontend &amp;&amp; npm test -- --run src/components/settings/__tests__/SettingsCloudTab.test.js src/components/cloud/__tests__/CloudCredentialModal.test.js</automated></verify>
<done>Cloud accounts are independent UUID resources across create/edit/reconnect/settings, with owner-scoped security and useful validation errors.</done>
</task>
<task type="auto">
<name>Task 2: Remove provider-keyed navigation and repair cloud location state</name>
<files>frontend/src/components/cloud/CloudProviderTreeItem.vue, frontend/src/components/cloud/CloudFolderTreeItem.vue, frontend/src/components/layout/AppSidebar.vue, frontend/src/components/storage/StorageBrowser.vue, frontend/src/views/CloudFolderView.vue, frontend/src/views/CloudStorageView.vue, frontend/src/components/cloud/__tests__/CloudProviderTreeItem.test.js, frontend/src/components/cloud/__tests__/CloudFolderTreeItem.test.js, frontend/src/components/layout/__tests__/AppSidebar.test.js, frontend/src/views/__tests__/CloudFolderView.test.js, frontend/src/views/__tests__/CloudStorageView.test.js</files>
<read_first>
- frontend/src/components/ui/TreeItem.vue — shared expansion and isActive contract
- frontend/src/components/ui/BreadcrumbBar.vue — root/segment emission behavior
- frontend/src/components/storage/StorageBrowser.vue — single shared browser and current root-label substitution
- frontend/src/components/cloud/CloudProviderTreeItem.vue — stale provider API/route
- frontend/src/components/cloud/CloudFolderTreeItem.vue — stale provider propagation
- frontend/src/views/CloudFolderView.vue — current connection lookup and folder-only breadcrumb
- frontend/src/components/layout/AppSidebar.vue — broad startsWith('/cloud') active state
</read_first>
<action>
Make every sidebar cloud request and route connection-ID based. CloudProviderTreeItem passes `connection.id` to `getCloudFoldersByConnectionId`, routes to `/cloud/{connection.id}/root`, and passes the same ID through nested CloudFolderTreeItem instances. Nested folders browse and route by connection ID and provider item/path reference; remove all active frontend use of the deprecated provider-keyed folder API.
Build the cloud breadcrumb as `Cloud > {effective connection name} > {provider folder segments}`. The Cloud root emits navigation to `/cloud`; the connection segment emits navigation to `/cloud/{id}/root`; folder segments navigate within that connection. Preserve the breadcrumb when browse refresh fails so users can always escape a stale/error view. Do this through StorageBrowser/BreadcrumbBar props and emitted events without creating a parallel breadcrumb component or mutating child props.
Make selection route-aware using TreeItem's existing `isActive` prop: generic Cloud Storage is active only when route path is exactly `/cloud`; the connection node is active at its root and while no deeper loaded node is selected; the deepest matching folder node is active for its provider reference. Use route params, not display labels or provider slugs. Keep connection nodes distinct for duplicate providers.
</action>
<acceptance_criteria>
- no frontend cloud component calls `getCloudFolders(provider, ...)` or constructs `/cloud/{provider}`
- the exact sequence POST Nextcloud 201 → click sidebar connection calls the UUID endpoint and never returns UUID-validation 422
- failed refresh still shows a clickable Cloud crumb leading to `/cloud`
- root and nested views show Cloud > custom/default connection name > folders
- generic, connection, and folder sidebar highlighting are mutually consistent with the current route
</acceptance_criteria>
<verify><automated>cd frontend &amp;&amp; npm test -- --run src/components/cloud/__tests__/CloudProviderTreeItem.test.js src/components/cloud/__tests__/CloudFolderTreeItem.test.js src/components/layout/__tests__/AppSidebar.test.js src/views/__tests__/CloudFolderView.test.js src/views/__tests__/CloudStorageView.test.js &amp;&amp; ! rg "getCloudFolders\(|/cloud/\$\{[^}]*provider" src/components/cloud src/views src/components/layout</automated></verify>
<done>Cloud navigation uses connection UUIDs end-to-end, breadcrumbs expose the full hierarchy, and the sidebar highlights the actual active resource.</done>
</task>
<task type="auto">
<name>Task 3: Run cross-layer regressions, security gate, documentation, and release protocol</name>
<files>backend/main.py, frontend/package.json, frontend/package-lock.json, AGENTS.md, CLAUDE.md, README.md, SECURITY.md</files>
<read_first>
- .planning/phases/12-cloud-resource-foundation/12-UAT.md — exact five user-reported symptoms and diagnosed artifacts
- AGENTS.md — tests, documentation, version, security, commit, and push requirements
- CLAUDE.md — mirrored development-agent contract
- SECURITY.md — Phase 12 threat register and accepted risks
</read_first>
<action>
Add/complete regression coverage for all UAT failures: successful Nextcloud creation followed by UUID browse; two same-provider connections; owner-scoped credential update; credential exclusion; Cloud overview/connection/folder breadcrumb navigation during provider failure; and exact active sidebar node. Run focused backend/frontend tests, full suites, production build, Bandit, npm audit, available pip-audit, and secret checks. Resolve introduced failures and high-severity findings without skips or suppressions. Bump patch version from 0.2.1 to 0.2.2 in backend/main.py and frontend package files. Update AGENTS.md and CLAUDE.md current state and shared architecture rules, README user-facing multi-account/navigation behavior, and SECURITY.md evidence. Commit and push atomically under `fix(12-uat): repair cloud connection navigation and multi-account support`.
</action>
<acceptance_criteria>
- all focused regressions and full backend/frontend suites pass with zero new failures
- frontend production build and mandatory security gates pass
- no provider-keyed frontend browse path remains active
- versions are 0.2.2 and documentation describes true multi-account behavior
- Phase 12 UAT is ready to resume at Test 2, with Tests 46 still awaiting user verification
</acceptance_criteria>
<verify><automated>docker compose exec -T backend pytest -q &amp;&amp; cd frontend &amp;&amp; npm test -- --run &amp;&amp; npm run build &amp;&amp; npm audit --audit-level=high</automated></verify>
<done>The five reported cloud defects have regression coverage, security and full-suite gates pass, release/docs are current, and UAT can resume.</done>
</task>
</tasks>
<threat_model>
| Threat ID | Threat | Mitigation and evidence |
|-----------|--------|-------------------------|
| T-12-06-01 | IDOR while editing/browsing one of several connections | Resolve every connection ID with owner scope before decrypting, updating, browsing, or deleting; negative tests use another user's UUID |
| T-12-06-02 | Credential disclosure through multi-account list/edit/errors | Whitelisted responses only; password omission means preserve existing secret; logs/audit/errors contain no credentials |
| T-12-06-03 | OAuth state confusion updates another connection | Bind reconnect state to authenticated user plus explicit connection ID in expiring Redis state and re-check ownership at callback |
| T-12-06-04 | SSRF bypass during credential edit | Re-run canonical `validate_cloud_url` and provider health check before storing updated WebDAV/Nextcloud credentials |
| T-12-06-05 | Cross-connection metadata collision | Continue scoping durable cloud items and folder states by connection UUID; same-provider regression asserts isolation |
| T-12-06-06 | Route/provider identifier confusion | UUID route parsing plus frontend tests prove provider slugs never enter connection-ID endpoints |
| T-12-06-SC | Dependency/supply-chain risk | No new runtime dependencies; rerun Bandit, pip/npm audits, and secret scan |
</threat_model>
<verification>
1. Plan structure contains three executable tasks, explicit files, acceptance criteria, and automated checks.
2. Backend tests prove independent same-provider lifecycle and owner isolation.
3. Frontend tests prove UUID-only sidebar navigation, full breadcrumb hierarchy, and deepest-node selection.
4. A cross-layer regression captures the observed POST 201 followed by sidebar browse without 422.
5. Full tests, build, security gates, version/docs, commit, and push complete before UAT resumes.
</verification>
<success_criteria>
- The connected Nextcloud account opens from every UI entry point without a provider-slug/UUID mismatch.
- Users can manage multiple accounts from any supported provider as independent connection resources.
- Cloud breadcrumbs and sidebar selection truthfully represent overview, connection, and nested folder state.
- Failures remain navigable and actionable instead of trapping the user or displaying bare HTTP status text.
</success_criteria>
<output>Create `.planning/phases/12-cloud-resource-foundation/12-06-SUMMARY.md` when complete.</output>
@@ -1,68 +1,136 @@
---
status: resolved
status: diagnosed
phase: 12-cloud-resource-foundation
source:
- 12-01-SUMMARY.md
- 12-02-SUMMARY.md
- 12-03-SUMMARY.md
- 12-04-SUMMARY.md
- 12-05-SUMMARY.md
started: 2026-06-19T20:21:31+02:00
updated: 2026-06-20T00:00:00+02:00
updated: 2026-06-21T22:17:40+02:00
---
## Current Test
[testing paused — 4 items blocked by cloud provider connection failure]
[testing paused — 3 items blocked by diagnosed cloud connection/navigation defects]
## Tests
### 1. Cold Start Smoke Test
expected: Start DocuVault from a clean stopped state. PostgreSQL migration 0006 completes, the backend and frontend become healthy without startup errors, and the authenticated Cloud Storage page loads normally.
result: issue
reported: "GET /api/cloud/connections raises an ASGI exception: psycopg.errors.UndefinedColumn because cloud_connections.display_name_override does not exist in the live PostgreSQL schema."
severity: blocker
result: pass
verified: "Automated cold start: Compose migration gate exited 0 at Alembic 0006; backend and frontend returned 200; regular-user /cloud loaded; startup logs and browser console had no warnings or errors."
### 2. Connection Roots and Custom Names
expected: Cloud Storage shows each connected account as its own top-level row. Two accounts from the same provider remain distinct; default duplicate names are disambiguated, and renaming one connection in Settings updates only that connection.
result: issue
reported: "Cannot connect Nextcloud test users; POST /api/cloud/connections/webdav raises psycopg.errors.UndefinedColumn because cloud_connections.display_name_override does not exist."
reported: |
1. I connected a test account on my nextcloud instance and I still cannot connect. It shows "HTTP 422" Please check whats wrong.
5. It seems that I still can only connect one storage per provider. I connected a nextcloud storage and cannot connect another one.
severity: blocker
### 3. Shared Cloud Folder Browser
expected: Opening a connection shows its files and folders in the same StorageBrowser layout used for local documents. The breadcrumb begins with the connection name, folder navigation works, and provider IDs or technical metadata do not clutter normal rows.
result: blocked
blocked_by: server
reason: "Cannot test because cloud provider connection fails with the live database schema error."
result: issue
reported: |
2. If I am on the nextcloud connection, which fails to synchronize, I cannot click on "Cloud" in the breadcrumb to go back to the cloud provider overview.
3. The "CloudStorage" navigator button on the sidebar is always highlighted if I am on a specific cloud storage folder and not either the cloud provider I am currently in or even the folder itself I am in.
4. It seems that the breadcumb in the cloud storage is not working as intended. If I am in my nextcloud connection I want there to be shown "Cloud > Nextcloud (or the custom name) > Folder1 > ...."
severity: major
### 4. Unsupported Action Explanations
expected: Unsupported cloud actions remain visible in their normal positions but appear gray; temporarily unavailable actions appear amber. Hover or keyboard focus shows the specific explanation, and tapping/clicking an unavailable action explains it without executing it.
result: blocked
blocked_by: server
reason: "Cannot reach a connected cloud folder while provider connection creation is failing."
blocked_by: prior-phase
reason: "I cannot procede with the verification until the cloud storage is fixed as mentioned before."
### 5. Cached-First Refresh and Warning State
expected: Revisiting a previously browsed folder shows saved metadata immediately while a subtle refresh indicator runs. If provider refresh fails, cached rows remain usable and a warning reports the last successful refresh and automatic retry instead of replacing the folder with an error.
result: blocked
blocked_by: server
reason: "Cannot establish the cloud connection needed to seed and revisit provider metadata."
blocked_by: prior-phase
reason: "I cannot procede with the verification until the cloud storage is fixed as mentioned before."
### 6. Session-Only Folder Memory
expected: Leaving and reopening a connection in the same browser session resumes its last folder. Starting a fresh tab/session begins at the connection root, and no credentials or document content are stored in browser session storage.
result: blocked
blocked_by: server
reason: "Cannot enter a connected cloud folder while provider connection creation is failing."
blocked_by: prior-phase
reason: "I cannot procede with the verification until the cloud storage is fixed as mentioned before."
## Summary
total: 6
passed: 0
passed: 1
issues: 2
pending: 0
skipped: 0
blocked: 4
blocked: 3
## Gaps
- truth: "Each cloud connection is addressed by its UUID, and a user can create and manage multiple independent connections for the same provider."
status: failed
reason: "User reported that a successfully connected Nextcloud account opens as HTTP 422 and that a second Nextcloud connection cannot be added."
severity: blocker
test: 2
root_cause: "The connection POST succeeded with 201, but CloudProviderTreeItem still routes and browses by provider slug; /cloud/nextcloud/root makes CloudFolderView call the UUID endpoint with 'nextcloud', producing FastAPI's 422 UUID validation response. Separately, _upsert_cloud_connection selects by (user_id, provider) and SettingsCloudTab.connectionFor() renders only the first provider match, so same-provider connections are overwritten/hidden."
artifacts:
- path: "frontend/src/components/cloud/CloudProviderTreeItem.vue"
issue: "Uses deprecated provider-keyed browse API and pushes /cloud/{provider}/root instead of the connection UUID."
- path: "frontend/src/components/cloud/CloudFolderTreeItem.vue"
issue: "Propagates provider slugs rather than connection IDs through nested sidebar navigation."
- path: "backend/api/cloud/connections.py"
issue: "_upsert_cloud_connection updates the first (user_id, provider) row instead of creating an independent connection."
- path: "frontend/src/components/settings/SettingsCloudTab.vue"
issue: "connectionFor(providerKey) collapses all same-provider connections to one row and removes the add-another flow."
missing:
- "Use connection UUIDs for all sidebar browse requests and routes."
- "Replace provider upsert semantics with independent connection creation plus connection-ID editing."
- "Render every connection in Settings and retain an explicit Add connection action per provider."
- "Show structured FastAPI validation details instead of reducing them to HTTP 422."
debug_session: ""
- truth: "Cloud navigation identifies the active connection/folder and exposes a working Cloud > connection > folder hierarchy."
status: failed
reason: "User reported that Cloud cannot be clicked from a failed connection, the generic Cloud Storage sidebar entry stays highlighted, connection/folder nodes are not highlighted, and the breadcrumb hierarchy is incomplete."
severity: major
test: 3
root_cause: "StorageBrowser substitutes the connection name for the breadcrumb root and CloudFolderView maps only folder path segments; its null-root handler returns to the connection root rather than /cloud. AppSidebar marks the generic Cloud Storage link active for every /cloud path, while TreeItem receives no route-aware selected state. The stale provider-keyed sidebar route compounds all three symptoms."
artifacts:
- path: "frontend/src/components/storage/StorageBrowser.vue"
issue: "Uses connectionRoot.name as rootLabel, eliminating the separate Cloud overview crumb."
- path: "frontend/src/views/CloudFolderView.vue"
issue: "Breadcrumb excludes Cloud and connection segments; null navigation targets the connection root."
- path: "frontend/src/components/layout/AppSidebar.vue"
issue: "Generic Cloud Storage link is active for every path beginning with /cloud."
- path: "frontend/src/components/cloud/CloudProviderTreeItem.vue"
issue: "Connection node is not route-selected and routes by provider slug."
- path: "frontend/src/components/cloud/CloudFolderTreeItem.vue"
issue: "Folder nodes are not route-selected and route by provider slug."
missing:
- "Render Cloud > connection display name > provider folder segments with independently navigable IDs."
- "Route the Cloud crumb to /cloud even when refresh fails."
- "Highlight the deepest active sidebar node; highlight generic Cloud Storage only on /cloud."
debug_session: ""
- truth: "A developer can start the complete local stack from the repository root without missing-variable errors or configuration warnings."
status: resolved
reason: "User reported: To verify is create a complete development .env file and exclude it from git. Please remeber (codex and claude) to edit this .env file so I can spin up the app without errors or warnings."
severity: major
test: 1
root_cause: "The ignored local .env predated later cloud and observability configuration: CLOUD_CREDS_KEY and the Compose-required GRAFANA_ADMIN_PASSWORD were missing, and no agent-facing rule required .env to stay synchronized with .env.example."
artifacts:
- path: ".env"
issue: "Local development configuration lacked required Phase 5/6 variables and explicit defaults."
- path: ".env.example"
issue: "Template omitted observability, auth-duration, AI-default, and MINIO_PUBLIC_ENDPOINT entries."
- path: "AGENTS.md"
issue: "No Codex maintenance contract for the ignored local environment file."
- path: "CLAUDE.md"
issue: "No Claude maintenance contract for the ignored local environment file."
missing: []
debug_session: ""
- truth: "A clean start applies migration 0006 and the authenticated Cloud Storage page loads without backend schema errors."
status: resolved
reason: "User reported: GET /api/cloud/connections raises psycopg.errors.UndefinedColumn because cloud_connections.display_name_override does not exist in the live PostgreSQL schema."