diff --git a/.planning/phases/02-users-authentication/02-UAT.md b/.planning/phases/02-users-authentication/02-UAT.md index 224a24d..e14b877 100644 --- a/.planning/phases/02-users-authentication/02-UAT.md +++ b/.planning/phases/02-users-authentication/02-UAT.md @@ -1,5 +1,5 @@ --- -status: complete +status: diagnosed phase: 02-users-authentication source: [02-01-SUMMARY.md, 02-02-SUMMARY.md, 02-03-SUMMARY.md, 02-04-SUMMARY.md, 02-05-SUMMARY.md] started: 2026-05-31T00:00:00Z @@ -116,53 +116,96 @@ blocked: 2 reason: "User reported: I don't see an option to activate or setup a 2FA method." severity: major test: 4 - artifacts: [] - missing: [] + root_cause: "AccountView.vue (which contains TotpEnrollment) is registered at /account but unreachable through the UI. The sidebar links to /settings (SettingsView.vue), which has only Preferences/AI/Cloud tabs — no Account or Security tab. /account is an orphaned route." + artifacts: + - path: "frontend/src/components/layout/AppSidebar.vue" + issue: "No navigation link to /account — sidebar only links to /settings" + - path: "frontend/src/views/SettingsView.vue" + issue: "No Account/Security tab that would surface AccountView's TOTP content" + missing: + - "Add Account/Security tab to SettingsView.vue (or sidebar link to /account)" + - "User account page should be discoverable from main navigation" - truth: "Auth/login pages use AuthLayout (no sidebar, no user identity) so previously logged-in user info is never shown on public pages" status: failed reason: "User reported: I do see the sidebar every time when I login. I do not want the sidebar on the login page and I do not want to leak this information of the previous logged in user when no one is logged in. Confirmed again on logout: sidebar still visible while logged out." severity: major test: 6 - artifacts: [] - missing: [] + root_cause: "App.vue renders unconditionally in the root template — no route-meta check, no layout switching. AuthLayout.vue exists and is correctly implemented but is never imported or used anywhere. Auth routes only have meta: { public: true }; there is no meta.layout hint and App.vue never reads it." + artifacts: + - path: "frontend/src/App.vue" + issue: " is an unconditional child in the root template — no v-if or layout switch" + - path: "frontend/src/router/index.js" + issue: "Auth routes missing meta: { layout: 'auth' } — no layout hint for App.vue to consume" + - path: "frontend/src/layouts/AuthLayout.vue" + issue: "Correctly implemented but dead — never imported or activated by any code path" + missing: + - "App.vue must become layout-aware: read route.meta.layout and conditionally render AuthLayout vs app shell" + - "Auth routes (/login, /register, /password-reset, /password-reset/confirm) need meta: { layout: 'auth' }" - truth: "After logout, the sidebar (including user identity footer) is no longer visible — user is on the login page with AuthLayout only" status: failed reason: "User reported: I am logged out right now but I still see the sidebar, which is not a desired behaviour." severity: major test: 7 - artifacts: [] - missing: [] + root_cause: "Same root cause as test 6 — App.vue always renders AppSidebar regardless of route. Fixed by the same App.vue layout-aware change." + artifacts: + - path: "frontend/src/App.vue" + issue: "Same as test 6 — AppSidebar always rendered" + missing: + - "Same fix as test 6 — covered by same plan task" -- truth: "TOTP enrollment flow: no QR code required (otpauth:// link + manual secret is acceptable), but the manual secret must be valid and correctly rendered so users can add it to an authenticator app" +- truth: "TOTP enrollment flow: QR code rendered so desktop users can scan without manually typing a 32-char secret" status: failed - reason: "User reported: no QR code visible (expected — known MVP stub), security key doesn't work (possibly misspelled in display), otpauth:// link opens macOS Passwords app (expected behavior on Mac)." + reason: "User reported: no QR code visible, security key doesn't work (possibly misspelled in display), otpauth:// link opens macOS Passwords app instead of working on desktop." severity: major test: 9 - artifacts: [] - missing: [] + root_cause: "TotpEnrollment.vue renders a plain hyperlink instead of a QR image. No QR library is installed (package.json has no qrcode/qr.js). The otpauth:// protocol has no default handler on desktop browsers. The backend secret is correct (valid base32, correct URI) — only the frontend rendering is wrong." + artifacts: + - path: "frontend/src/components/auth/TotpEnrollment.vue" + issue: "Renders text link instead of QR image — comment says 'no QR library dependency' confirming intentional omission" + - path: "frontend/package.json" + issue: "No QR code library installed (qrcode, qr.js, etc.)" + missing: + - "Add qrcode npm package" + - "Render QR image from qrUri in TotpEnrollment.vue step 1" - truth: "Account settings (/account) is presented as a tab within a unified Settings page, not a standalone route" status: failed reason: "User requested: account page should be a tab inside a settings page (UX improvement)" severity: minor test: 9 - artifacts: [] - missing: [] + root_cause: "AccountView.vue is a standalone route at /account. SettingsView.vue exists but has no Account/Security tab. User wants a unified settings experience." + artifacts: + - path: "frontend/src/views/SettingsView.vue" + issue: "Missing Account/Security tab" + - path: "frontend/src/views/AccountView.vue" + issue: "Standalone orphaned view — should be merged into settings as a tab" + missing: + - "Merge AccountView content into SettingsView as a new Account/Security tab" + - "Update router to redirect /account to /settings (account tab)" - truth: "Non-admin users are blocked from /admin (redirected or shown 403); the Admin link is hidden in the sidebar for non-admins" status: failed reason: "User reported: can navigate to /admin as a non-admin user; all tabs visible but no data shown (backend blocks data but frontend does not block the route)" severity: major test: 14 - artifacts: [] - missing: [] + root_cause: "The /admin route in router/index.js has no meta field at all. The beforeEach guard only checks accessToken — it never reads user.role. Any authenticated user passes through. The authStore.user (including role) is reliably populated before the guard completes, so there is no timing issue — the guard simply never checks role." + artifacts: + - path: "frontend/src/router/index.js" + issue: "/admin route definition has no meta property; beforeEach guard has zero role-checking logic" + missing: + - "Add meta: { requiresAdmin: true } to /admin route" + - "Add admin role check in beforeEach: if to.meta.requiresAdmin && user.role !== 'admin' → redirect to /" - truth: "Admin can create a new user via the Users tab form — POST /api/admin/users returns 201 and the new user appears in the table" status: failed reason: "User reported: cannot create a new user as admin; form returns HTTP 500 error." severity: blocker test: 15 - artifacts: [] - missing: [] + root_cause: "Missing 'await session.flush()' before write_audit_log() in the admin create_user handler. Three pending objects (User, Quota, AuditLog) flush without guaranteed ordering — on PostgreSQL, the FK constraint on audit_log.user_id causes an IntegrityError when AuditLog is flushed before the User row exists. SQLite (used in tests) has FK enforcement disabled by default, so all unit tests pass silently." + artifacts: + - path: "backend/api/admin.py" + issue: "Missing 'await session.flush()' after session.add(quota) and before write_audit_log() — User+Quota not persisted when AuditLog FK references users.id" + missing: + - "Add 'await session.flush()' after session.add(quota) in create_user handler — matches pattern already used in auth/register and bootstrap_admin"