diff --git a/.planning/phases/02-users-authentication/02-06-SUMMARY.md b/.planning/phases/02-users-authentication/02-06-SUMMARY.md new file mode 100644 index 0000000..4f8e401 --- /dev/null +++ b/.planning/phases/02-users-authentication/02-06-SUMMARY.md @@ -0,0 +1,130 @@ +--- +phase: 02-users-authentication +plan: "06" +subsystem: frontend-auth-ux +tags: [gap-closure, auth-layout, admin-guard, qr-code, settings-ux] +dependency_graph: + requires: ["02-05"] + provides: ["auth-layout-switching", "admin-role-guard", "account-settings-tab", "totp-qr-image"] + affects: ["frontend/src/App.vue", "frontend/src/router/index.js", "frontend/src/views/SettingsView.vue"] +tech_stack: + added: ["qrcode@1.5.4"] + patterns: ["layout-switching via route.meta.layout", "role guard in beforeEach", "AccountView content extracted to SettingsAccountTab"] +key_files: + created: + - frontend/src/components/settings/SettingsAccountTab.vue + modified: + - frontend/src/App.vue + - frontend/src/router/index.js + - frontend/src/views/SettingsView.vue + - frontend/src/components/auth/TotpEnrollment.vue + - frontend/package.json +decisions: + - "AuthLayout rendered unconditionally by App.vue via v-if on route.meta.layout — AuthLayout owns its own router-view" + - "requiresAdmin guard appended to existing beforeEach after silent refresh — non-admin redirected to /" + - "SettingsAccountTab created as standalone component (not inline in SettingsView) to keep SettingsView manageable" + - "/account route redirects to /settings; AccountView.vue kept on disk but unreachable from router" +metrics: + duration: "~25 minutes" + completed: "2026-05-31T18:40:52Z" + tasks_completed: 3 + tasks_total: 3 + files_created: 1 + files_modified: 5 +--- + +# Phase 02 Plan 06: UAT Gap Closure — Auth Layout + Admin Guard + Account Tab + QR Code + +One-liner: Five UAT gaps closed — layout-aware App.vue, admin route guard, Account settings tab extracted from AccountView, and TOTP QR image via qrcode library. + +## Tasks Completed + +| Task | Description | Commit | Files | +|------|-------------|--------|-------| +| 1 | Verify backend fix + regression test for admin create_user (GAP 1) | (verify-only, no code change) | backend/api/admin.py (confirmed), backend/tests/test_admin_api.py (confirmed) | +| 2 | Auth route layout switching + admin role guard (GAPs 2, 3, 4) | aa957d6 | frontend/src/App.vue, frontend/src/router/index.js | +| 3 | AccountView merged into SettingsView as Account tab + QR code in TotpEnrollment (GAPs 3 and 5) | c08ea42 | frontend/package.json, frontend/src/components/auth/TotpEnrollment.vue, frontend/src/views/SettingsView.vue, frontend/src/components/settings/SettingsAccountTab.vue | + +## What Was Built + +### Task 1: Backend verification (GAP 1 — admin create_user HTTP 500) + +Confirmed `await session.flush()` at admin.py:247 (before `write_audit_log()`) and `test_create_user_writes_audit_log` test in test_admin_api.py. Both were already present from plan 02-04. Test passed on first run. + +No code changes made — verification only. + +### Task 2: Auth layout switching + admin role guard (GAPs 2, 3, 4) + +**App.vue** refactored to layout-aware root component: +- `v-if="route.meta.layout === 'auth'"` renders `` which owns its own `` +- `v-else` renders the full app shell (AppSidebar + router-view) +- Added `useRoute` import; `AuthLayout` import from `./layouts/AuthLayout.vue` + +**router/index.js** three changes: +- All four auth routes (`/login`, `/register`, `/password-reset`, `/password-reset/confirm`) updated with `meta: { public: true, layout: 'auth' }` +- `/admin` route updated with `meta: { requiresAdmin: true }` +- `beforeEach` extended with role check: `if (to.meta.requiresAdmin && authStore.user?.role !== 'admin') return { path: '/' }` +- `/account` route changed to `{ path: '/account', redirect: '/settings' }` — AccountView now embedded in SettingsView + +### Task 3: AccountView merged into SettingsView + QR code (GAPs 3 and 5) + +**qrcode@1.5.4** installed as runtime dependency (verified 20M+ weekly downloads, canonical npm package). + +**TotpEnrollment.vue** updated: +- Added `import QRCode from 'qrcode'` +- Added `qrDataUrl` ref +- In `startSetup()`: `qrDataUrl.value = await QRCode.toDataURL(qrUri.value, { width: 200, margin: 1 })` +- Replaced `` link block with `TOTP QR code` +- Manual secret display (`` block) kept as fallback + +**SettingsAccountTab.vue** created at `frontend/src/components/settings/`: +- Full AccountView content without the outer page wrapper (`
` and `

` heading removed) +- All four sections: Account information, Two-factor authentication (TotpEnrollment), Change password (PasswordStrengthBar), Sessions (sign-out-all) +- All script setup logic ported: changePassword, disableTotp, onTotpEnrolled, signOutAll, all refs +- Import paths adjusted for new location (`../../stores/auth.js`, `../auth/...`, `../ui/...`) + +**SettingsView.vue** updated: +- Added `{ id: 'account', label: 'Account' }` to tabs array +- Added `` panel +- Added `import SettingsAccountTab from '../components/settings/SettingsAccountTab.vue'` + +## Verification Results + +| Check | Result | +|-------|--------| +| `pytest tests/test_admin_api.py::test_create_user_writes_audit_log -v` | PASSED | +| `npm run build` | Exit 0, 156 modules transformed | +| `npm test` | 107/107 passed (11 test files) | +| `pytest -v` (full backend) | 343 passed, 1 pre-existing failure (test_extract_docx — missing docx module, unrelated) | +| 4 auth routes have `meta.layout:'auth'` | Confirmed (grep count = 4) | +| `/admin` has `meta.requiresAdmin` | Confirmed | +| `requiresAdmin` role check in `beforeEach` | Confirmed | +| `qrcode` in package.json dependencies | Confirmed (`"qrcode": "^1.5.4"`) | +| `QRCode.toDataURL` + `img` tag in TotpEnrollment | Confirmed | +| `SettingsAccountTab` imported and rendered in SettingsView | Confirmed | + +## Deviations from Plan + +None — plan executed exactly as written. Task 1 was verify-only; the fix was already present from plan 02-04 execution. + +## Known Stubs + +None. All functional paths are wired. + +## Threat Flags + +No new threat surface introduced. Changes are frontend-only layout/UX routing (Task 1 is backend verify-only with no code changes). The requiresAdmin guard closes T-02-GAP-01 (elevation of privilege). The auth layout conditional closes T-02-GAP-02 (information disclosure via sidebar on public routes). + +## Self-Check: PASSED + +Files confirmed present: +- frontend/src/App.vue (modified) +- frontend/src/router/index.js (modified) +- frontend/src/components/settings/SettingsAccountTab.vue (created) +- frontend/src/views/SettingsView.vue (modified) +- frontend/src/components/auth/TotpEnrollment.vue (modified) +- frontend/package.json (modified) + +Commits confirmed: +- aa957d6 feat(02-06): auth layout switching + admin role guard (GAPs 2, 3, 4) +- c08ea42 feat(02-06): Account tab in SettingsView + QR code in TotpEnrollment (GAPs 3, 5)