docs(05): add UAT, UI-SPEC, deferred items, debug notes; refine plans 09-11

Plan refinements: Vitest tests added to 09/10 must-haves, explicit
mock_flow two-tuple pattern in 10, test_admin_api.py fixture usage in 11.
New artifacts: UAT checklist, UI-SPEC, deferred-items, debug investigation
for cloud-doc-operations-fail.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
curo1305
2026-05-30 11:57:54 +02:00
parent 34f012b4e8
commit 67edc19a36
7 changed files with 1115 additions and 23 deletions
@@ -10,6 +10,7 @@ files_modified:
- frontend/src/components/cloud/CloudCredentialModal.vue
- frontend/src/components/ui/ConfirmBlock.vue
- backend/tests/test_cloud.py
- frontend/src/components/settings/__tests__/SettingsCloudTab.test.js
autonomous: true
requirements: [CLOUD-01, CLOUD-04]
gap_closure: true
@@ -20,6 +21,7 @@ must_haves:
- "Nextcloud custom endpoint is preserved when re-editing an existing connection"
- "Edit button appears on ERROR-state Nextcloud/WebDAV rows"
- "Disconnect confirmation text renders fully within its container without overflow"
- "handleConnect on OAuth providers calls initiateOAuth and navigates to the returned URL (verified by Vitest)"
artifacts:
- path: "backend/api/cloud.py"
provides: "oauth_initiate returns JSON {url} (200) instead of RedirectResponse (302)"
@@ -29,6 +31,8 @@ must_haves:
provides: "watch handler detects custom endpoint on edit and repopulates showAdvanced + customEndpoint"
- path: "frontend/src/components/ui/ConfirmBlock.vue"
provides: "break-words on message paragraph"
- path: "frontend/src/components/settings/__tests__/SettingsCloudTab.test.js"
provides: "Vitest test asserting handleConnect calls initiateOAuth and sets window.location.href"
key_links:
- from: "frontend/src/components/settings/SettingsCloudTab.vue"
to: "/api/cloud/oauth/initiate/{provider}"
@@ -112,7 +116,7 @@ From frontend/src/components/ui/ConfirmBlock.vue:
In backend/tests/test_cloud.py, add test `test_oauth_initiate_returns_json_url`:
- Creates a regular user + token.
- Mocks Redis setex (the app state redis client).
- For google_drive provider: mocks `google_auth_oauthlib.flow.Flow.from_client_config` to return a mock whose `authorization_url` returns ("https://accounts.google.com/test", "state123").
- For google_drive provider: mocks `google_auth_oauthlib.flow.Flow.from_client_config` to return a mock flow object. Set the mock explicitly: `mock_flow.authorization_url.return_value = ("https://accounts.google.com/test", "state123")` — do not use a generic "returns a URL" — this exact two-tuple assignment is required because `flow.authorization_url(...)` returns `(url, state)` and the handler unpacks both values.
- Calls GET /api/cloud/oauth/initiate/google_drive with Bearer header.
- Asserts response.status_code == 200.
- Asserts response.json()["url"].startswith("https://accounts.google.com/").
@@ -125,8 +129,8 @@ From frontend/src/components/ui/ConfirmBlock.vue:
</task>
<task type="auto">
<name>Task 2: Frontend OAuth fetch, Nextcloud edit fix, Edit on ERROR, text overflow</name>
<files>frontend/src/components/settings/SettingsCloudTab.vue, frontend/src/components/cloud/CloudCredentialModal.vue, frontend/src/components/ui/ConfirmBlock.vue, frontend/src/api/client.js</files>
<name>Task 2: Frontend OAuth fetch, Nextcloud edit fix, Edit on ERROR, text overflow + Vitest test</name>
<files>frontend/src/components/settings/SettingsCloudTab.vue, frontend/src/components/cloud/CloudCredentialModal.vue, frontend/src/components/ui/ConfirmBlock.vue, frontend/src/api/client.js, frontend/src/components/settings/__tests__/SettingsCloudTab.test.js</files>
<action>
### 1. client.js — add initiateOAuth helper
Export `initiateOAuth(provider)` that calls `request(`/api/cloud/oauth/initiate/${provider}`)`. This uses the existing `request()` helper which injects the Bearer header and handles 401 → refresh → retry.
@@ -165,11 +169,22 @@ From frontend/src/components/ui/ConfirmBlock.vue:
### 6. ConfirmBlock.vue — add break-words to message paragraph
Change `<p class="text-sm text-gray-700">` to `<p class="text-sm text-gray-700 break-words">`.
### 7. SettingsCloudTab.test.js — add Vitest test for handleConnect OAuth flow
The file `frontend/src/components/settings/__tests__/SettingsCloudTab.test.js` already exists. Add a new test asserting the corrected OAuth connect flow:
- Mock `initiateOAuth` from `../../../../api/client.js` using `vi.mock`: `vi.mock('../../../../api/client.js', () => ({ initiateOAuth: vi.fn() }))`.
- In the test, set `initiateOAuth.mockResolvedValue({ url: 'https://accounts.google.com/o/oauth2/auth?state=xyz' })`.
- Assign `window.location = { href: '' }` (use `Object.defineProperty` or `vi.stubGlobal` to make `window.location.href` writable in the test environment).
- Mount `SettingsCloudTab` with a stubbed auth store that has a valid accessToken.
- Find a Connect button for a provider with `key === 'google_drive'` and trigger a click event simulating `handleConnect({ key: 'google_drive' })`.
- Assert: `initiateOAuth` was called with `'google_drive'`.
- Assert: `window.location.href` was set to `'https://accounts.google.com/o/oauth2/auth?state=xyz'` (the exact URL returned by the mock — confirming the component navigates to `data.url` and not directly to `/api/cloud/...`).
- Use `afterEach(() => vi.restoreAllMocks())`.
</action>
<verify>
<automated>cd /Users/nik/Documents/Progamming/document_scanner/frontend && npm run build 2>&1 | tail -5</automated>
<automated>cd /Users/nik/Documents/Progamming/document_scanner/frontend && npm run test -- --reporter=verbose --run src/components/settings/__tests__/SettingsCloudTab.test.js 2>&1 | tail -20 && npm run build 2>&1 | tail -5</automated>
</verify>
<done>Frontend build passes with zero errors. All four UI changes are applied: OAuth uses fetch, ERROR rows have Edit button, Nextcloud watch handler preserves custom endpoint, ConfirmBlock message has break-words.</done>
<done>Vitest test for handleConnect OAuth flow passes. Frontend build passes with zero errors. All four UI changes are applied: OAuth uses fetch, ERROR rows have Edit button, Nextcloud watch handler preserves custom endpoint, ConfirmBlock message has break-words.</done>
</task>
</tasks>
@@ -196,6 +211,7 @@ From frontend/src/components/ui/ConfirmBlock.vue:
<verification>
After both tasks complete:
- `pytest backend/tests/test_cloud.py::test_oauth_initiate_returns_json_url backend/tests/test_cloud.py::test_oauth_initiate_requires_auth -v`
- `npm run test -- --run src/components/settings/__tests__/SettingsCloudTab.test.js` — Vitest test for handleConnect OAuth flow passes
- `npm run build` — zero errors
- Manual: click Connect on Google Drive — browser navigates to accounts.google.com (not localhost 401)
- Manual: edit Nextcloud connection with custom endpoint — Advanced section opens with endpoint pre-filled
@@ -205,8 +221,9 @@ After both tasks complete:
<success_criteria>
- oauth_initiate returns 200 JSON {url} (not 302 redirect)
- Two new pytest tests pass for OAuth initiate
- Two new pytest tests pass for OAuth initiate; mock uses explicit `mock_flow.authorization_url.return_value = ("https://accounts.google.com/test", "state123")` two-tuple
- handleConnect in SettingsCloudTab uses fetch() + initiateOAuth(); no window.location.href to /api path
- Vitest test asserts initiateOAuth called with provider key and window.location.href set to returned URL
- ERROR status template block has Edit button for non-OAuth providers
- CloudCredentialModal watch handler repopulates customEndpoint and showAdvanced when stored URL differs from auto-constructed pattern
- ConfirmBlock message paragraph has break-words class