---
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
updated: 2026-05-31T00:00:00Z
---

## Current Test

[testing complete]

## Tests

### 1. Cold Start Smoke Test
expected: Kill any running server/service. Clear ephemeral state (temp DBs, caches, lock files). Start the application from scratch (docker compose up). Services boot without errors, Alembic migrations (including 0002_add_backup_codes_and_password_must_change) run cleanly, Redis connects, admin bootstrap completes, and a basic API call (GET /api/auth/me → 401) returns a live response.
result: pass

### 2. User Registration
expected: Navigate to /register. Fill in email + password. Password strength bar shows 4 segments as password gets stronger. Submit form. Account is created and you are redirected to login (or logged in). No localStorage/sessionStorage entries for the token.
result: pass

### 3. Login (Email & Password)
expected: Navigate to /login. Enter email and password. On success, you are redirected to the app (or /dashboard). If you try to access a protected route while logged out, you are redirected to /login?redirect=<original-path>.
result: pass

### 4. Login (TOTP — 3-step flow)
expected: With a TOTP-enrolled account, log in: step 1 = enter password, step 2 = enter 6-digit TOTP code from authenticator app. On correct code, you are signed in. An invalid code shows an error without signing you in.
result: issue
reported: "I don't see an option to activate or setup a 2FA method."
severity: major

### 5. Login with Backup Code
expected: On the TOTP step of login, click "Use a backup code instead". Enter one of your 10 backup codes. Login succeeds. That backup code cannot be reused on a second attempt.
result: blocked
blocked_by: prior-phase
reason: "Backup codes are issued during TOTP enrollment, which is blocked by the missing 2FA setup option (test 4 issue)"

### 6. Auth Wall (Route Guard)
expected: While logged out, navigate directly to a protected route (e.g., /account or /admin). You are redirected to /login?redirect=<that-path>. After logging in, you are sent back to the original destination.
result: issue
reported: "Yes but I do see the sidebar everytime when I login. I do not want to the sidebar on the login page and I do not want to leak this information of the previous logged in user when noone is logged in."
severity: major

### 7. Logout
expected: Click sign-out (from sidebar or account page). Session is cleared (no more auth), you are redirected to /login. Attempting to use the old access token returns 401.
result: issue
reported: "I am logged out right now but I still see the sidebar, which is not a desired behaviour."
severity: major

### 8. Change Password
expected: Go to account settings (/account). Enter current password and a new strong password. On success, a confirmation message appears. Logging in again with the new password works; old password is rejected.
result: pass

### 9. TOTP Enrollment
expected: On /account, click to enable 2FA. Step 1: an otpauth:// link (or QR image) and manual secret are shown — open in authenticator app. Step 2: enter the 6-digit code from the app to verify. Step 3: 10 backup codes are displayed in a 2-column grid with a "Copy all" button. An acknowledgment checkbox gates the "Enable 2FA" button. After enabling, account shows 2FA is active.
result: issue
reported: "I don't see a QR-Code, the security key doesn't work (could be misspelled though) and the link opens Passwords on my Mac which I don't use but I suppose it does work."
severity: major

### 10. Disable TOTP
expected: On /account with 2FA active, click to disable. An inline confirmation block appears ("Disable 2FA? …"). Confirm: 2FA is removed and the enrollment section reappears. Cancel: nothing changes.
result: blocked
blocked_by: prior-phase
reason: "Blocked by test 9 — cannot disable TOTP without first successfully enrolling (secret display issue prevents enrollment)"

### 11. Password Reset Request
expected: Navigate to /password-reset. Enter any email (even one that doesn't exist). The page always shows a success-like message ("If an account exists…") — no enumeration of valid emails. A real email account receives the reset link.
result: pass

### 12. Password Reset (New Password)
expected: Click the reset link from email. You arrive at a new-password form. Enter a strong new password. On submit, password is updated and you are NOT automatically logged in — you must go to /login and sign in manually with the new password.
result: pass

### 13. Sign Out All Devices
expected: On /account, click "Sign out all devices". A confirmation dialog appears. On confirm, all active sessions are revoked. You are signed out of the current session too and redirected to /login.
result: pass

### 14. Admin: User List
expected: Sign in as an admin. Navigate to /admin. The Users tab shows a table of all registered users with their email, role, and status. Non-admin users do not see the Admin link in the sidebar and get a 403/redirect if they try to visit /admin directly.
result: issue
reported: "I can navigate to the /admin site as a non-admin user and I do see all tabs but no options or no info is available."
severity: major

### 15. Admin: Create User
expected: In the Admin Users tab, click the create-user form. Fill in email; a temporary password is auto-generated (copy button available). Submit. The new user appears in the table. When that user logs in for the first time with the temp password, they are prompted to change it (password_must_change flow).
result: issue
reported: "I cannot create a new user. If I try it (as admin user) I get the error code 'HTTP 500' in the creation box."
severity: blocker

### 16. Admin: Deactivate User
expected: In the Admin Users tab, click Deactivate for a user. An inline confirmation row appears showing "Deactivate [email]? They will lose access…" with Keep and Deactivate buttons. Confirming deactivates the user (status changes). The sole admin cannot be deactivated (should show an error).
result: pass

### 17. Admin: Quota Management
expected: Navigate to the Quotas tab in the admin panel. Each user's quota is shown in MB with a usage %. Clicking edit on a row lets you change the limit. If you set the limit below current usage, an amber warning appears but the change is still saved.
result: pass

### 18. Admin: AI Config
expected: Navigate to the AI Config tab in the admin panel. Each user has a provider dropdown and model input. Selecting a different provider and saving shows a brief "Saved" confirmation flash. The change persists on reload.
result: pass

## Summary

total: 18
passed: 10
issues: 6
pending: 0
skipped: 0
blocked: 2

## Gaps

- truth: "TOTP enrollment option is visible in account settings, allowing users to set up 2FA before testing TOTP login"
  status: failed
  reason: "User reported: I don't see an option to activate or setup a 2FA method."
  severity: major
  test: 4
  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
  root_cause: "App.vue renders <AppSidebar /> 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: "<AppSidebar /> 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
  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: QR code rendered so desktop users can scan without manually typing a 32-char secret"
  status: failed
  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
  root_cause: "TotpEnrollment.vue renders a plain <a href='otpauth://...'> 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 <a href='otpauth://...'> 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
  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
  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
  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"
