Commit Graph
93 Commits
Author SHA1 Message Date
curo1305 4eb489feb8 feat(09-02): create AdminLayout.vue and AdminSidebar.vue
- AdminLayout: flex h-screen shell with AdminSidebar + main content area (p-8 max-w-5xl mx-auto router-view)
- AdminSidebar: 5 nav links in D-07 order (Overview/Users/Quotas/AI Config/Audit Log) with SVG icons
- Admin badge subtitle ("Admin" in indigo-500 per D-05) replaces "Document Manager"
- No Back-to-app link (D-06 applied)
- User identity footer + sign-out reused verbatim from AppSidebar.vue pattern
- Scoped nav-link/nav-link-active CSS identical to AppSidebar.vue
2026-06-12 15:47:35 +02:00
curo1305 3b8e2c1bd4 refactor(08-03): migrate session-revoked inline toast to toastStore.show()
- Remove sessionRevokedToast ref + setTimeout + inline HTML from SettingsAccountTab.vue
- Remove sessionRevokedToast ref + setTimeout + inline HTML from TotpEnrollment.vue
- Add toastStore.show('Other sessions have been terminated.', 'success') in changePassword
- Add toastStore.show('Other sessions have been terminated.', 'success') in disableTotp
- Add toastStore.show('Other sessions have been terminated.', 'success') in confirmEnrollment
- Update SettingsAccountTab.test.js to assert on mockShow instead of DOM text
- Update TotpEnrollment.test.js to assert on mockShow instead of DOM text
2026-06-08 16:34:44 +02:00
curo1305andClaude Sonnet 4.6 8f8bfa5539 test(phase-07.1): add Nyquist validation tests for sessions_revoked frontend behavior
3 positive + 2 negative Vitest tests covering CR-01/02/03 toast UX:
- SettingsAccountTab: toast appears/hidden after changePassword (CR-01)
- SettingsAccountTab: toast appears after disableTotp (CR-03)
- TotpEnrollment: inline alert appears/hidden after enable_totp (CR-02)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:54:14 +02:00
curo1305andClaude Sonnet 4.6 c38c6b1c01 feat(07.1): session revocation on privilege change — CR-01/CR-02/CR-03
- revoke_all_refresh_tokens: add skip_token_hash optional param (exclude
  current session while revoking others)
- change_password, enable_totp, disable_totp: call revoke with skip hash
  derived from refresh cookie; return sessions_revoked in response and
  write to audit log metadata_
- 3 new tests: test_{change_password,enable_totp,disable_totp}_revokes_other_sessions
  — all PASSED; 373 total passing, 0 regressions
- Frontend toasts: SettingsAccountTab + TotpEnrollment show
  "Other sessions have been terminated." when sessions_revoked > 0
- Companion fixes: rate_limiting get_client_ip refactor, deps/auth.py
  request.state.current_user, locustfile refresh-token task removal
- Version bump: 0.1.0 → 0.1.1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:47:16 +02:00
curo1305andClaude Sonnet 4.6 3b11b9a596 feat(07-uat): admin AI panel UX enhancements + DocumentCard status indicators
- GET /api/admin/ai-config/models — fetch model list from provider's /models endpoint
- POST /api/admin/ai-config/test-connection — replaced GET; accepts unsaved form
  values (api_key, base_url, model_name) so admins can test before saving
- TestConnectionRequest Pydantic model with provider_id validation
- SearchableModelSelect.vue — new reusable combobox; Teleport to body avoids
  overflow:hidden clipping; shows all models on open, filters only on typing;
  static "Enter manually" item always pinned at bottom; caches per provider
- AdminAiConfigTab: model name input replaced with SearchableModelSelect;
  testingProvider ref + spinner added to Test Connection button
- DocumentCard: processing spinner + "Classifying…", pending "Queued" badge,
  classification_failed badge; topics section only shown when status=ready
- FileManagerView: onUnmounted imported (polling wiring pending next session)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 09:26:02 +02:00
curo1305 c45d9e470d feat(07-05): DocumentCard classification_failed badge + Re-analyze button + Vitest coverage
- Add red "Classification failed" pill badge when doc.status === 'classification_failed'
- Re-analyze button calls classifyDocument(doc.id) via @click.stop, emits 'reclassified'
- Spinner text "Re-analyzing…" while in flight; resets after 500ms (via setTimeout)
- Existing is_shared badge block preserved unchanged
- Create frontend/tests/DocumentCard.spec.js: 4 Vitest tests covering badge render,
  no-badge for ready/processing, and reanalyze() calling classifyDocument + emit
- 131 frontend tests pass, build exits 0 (D-11 frontend coverage per CLAUDE.md)
2026-06-04 23:23:12 +02:00
curo1305 0db412d66c feat(07-05): frontend AI config client helpers + AdminAiConfigTab system section + Vitest tests
- Add getAiConfig/saveAiConfig/testAiConnection to frontend/src/api/client.js
- AdminAiConfigTab.vue: add System AI Providers section above existing per-user table
  - Per-provider accordion (10 providers from PROVIDER_DEFAULTS)
  - Write-only API key field (never pre-filled), base URL, model, context_chars inputs
  - Set Active (atomic flip), Save, Test Connection buttons with inline badges
  - Existing per-user ai-config table and saveConfig logic untouched (Pitfall 6)
- Create frontend/tests/api.spec.js: 4 Vitest tests for getAiConfig/saveAiConfig/testAiConnection
- All 127 frontend tests pass, build exits 0 (D-11 frontend coverage)
2026-06-04 23:22:08 +02:00
curo1305andClaude Sonnet 4.6 21366bd288 fix(06): WR-09 show error message when audit log fetch fails
Add fetchError ref initialized to null. Clear it at the start of
fetchLog() and set it on catch. Add <p v-else-if="fetchError"> block
in template between loading and empty states so admin users see
"Failed to load audit log. Please try again." instead of the
empty-state message when an API error occurs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 23:15:49 +02:00
curo1305andClaude Sonnet 4.6 aad7635623 fix(06): CR-05 hash attempted email in audit log to avoid PII storage
Replace raw email in auth.login_failed metadata_ with a 16-char
SHA-256 prefix (attempted_email_hash). Update AuditLogTab.vue to
display the hash field instead. This removes plaintext email PII from
the unencrypted audit_logs JSONB column as required by CLAUDE.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 23:15:48 +02:00
curo1305andClaude Sonnet 4.6 cce70b2ef6 refactor(frontend): extract shared modules, thin views, delete dead code
Shared utilities:
- Add src/utils/formatters.js — formatDate, formatSize, providerColor,
  providerBg, providerLabel; all components import from here, no inline duplicates
- Add src/components/ui/TreeItem.vue — generic expand/collapse tree node;
  FolderTreeItem, CloudFolderTreeItem, CloudProviderTreeItem now wrap it
- Add src/components/storage/StorageBrowser.vue — unified file browser grid
  used by both FileManagerView and CloudFolderView

View refactor (thin data-providers):
- FileManagerView.vue: stripped to props + event wiring; all layout moved to StorageBrowser
- CloudFolderView.vue: same treatment — feeds props into StorageBrowser
- All tree sidebar components delegate expand/collapse to TreeItem.vue

Dead code removed:
- Delete HomeView.vue — no active route, replaced by FileManagerView
- Delete FolderView.vue — no active route, logic merged into FileManagerView

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 16:10:47 +02:00
curo1305andClaude Sonnet 4.6 2686fde2d7 feat(06.2): log attempted email on failed login and surface it in audit log
- auth.py: store attempted_email in metadata_ and link user_id when the account exists (wrong password case); previously logged no PII at all
- AuditLogTab: Email column falls back to metadata_.attempted_email in amber with "(attempted)" label when no confirmed user_email is available

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 21:02:37 +02:00
curo1305andClaude Sonnet 4.6 7027347597 fix(06.2): audit log — add email column, remove @ prefix from handles
- Backend: add user_email to _build_filtered_query_with_handles (UserSubject join) and _audit_to_dict_with_handles; propagate through JSON viewer and CSV export including empty-result path
- Frontend: AuditLogTab adds Email column between User and Action Type; removes @ prefix from handle cell
- Test: update expected CSV header to include user_email

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 20:59:09 +02:00
curo1305andClaude Sonnet 4.6 089da94d8b fix(security): apply two findings from sharing security review
- get_document: strip extracted_text for share recipients (T-04-04-03 consistency)
- ShareModal: emit 'unshared' when last recipient is revoked; DocumentCard clears is_shared badge

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 19:41:15 +02:00
curo1305andClaude Sonnet 4.6 a0f6c2f663 fix(06.2): resolve four sharing UX issues found in re-test UAT
- AccountView: remove hardcoded @ prefix so handle matches what share dialog expects
- documents store: set is_shared=true optimistically after successful share so badge shows without refetch
- GET /api/documents/{id}: allow recipients of an active share to view the document (was returning 404 for non-owners)
- ShareModal: move Share button to its own full-width row so it no longer overflows the input area

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 19:32:51 +02:00
curo1305andClaude Sonnet 4.6 0505beb0a4 test(phase-02): add Nyquist validation tests for plan 06 gaps
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 15:17:25 +02:00
curo1305 1cba903c34 fix(06.2): WR-01 replace fixed-suffix password generation with fully-random positional injection 2026-06-01 14:31:00 +02:00
curo1305 2542c81602 fix(06.2): WR-03 WR-04 fix pagination off-by-one and surface daily exports load errors 2026-06-01 14:27:47 +02:00
curo1305 c08ea42b1b feat(02-06): Account tab in SettingsView + QR code in TotpEnrollment (GAPs 3, 5)
- frontend/package.json: add qrcode@1.5.4 to runtime dependencies
- TotpEnrollment.vue: import QRCode; generate data URL in startSetup(); render img tag
- SettingsAccountTab.vue: new component with all AccountView content (2FA, password, sessions)
- SettingsView.vue: add Account tab rendering SettingsAccountTab; import SettingsAccountTab
2026-05-31 20:40:28 +02:00
curo1305 5d457d68bf feat(06.2-05): clear filters button and active filter count in AuditLogTab
- Add clearFilters() function that resets all filter fields and refetches
- Add activeFilterCount computed property (counts non-empty filter fields)
- Add "Clear filters" button (visible only when activeFilterCount > 0)
- Wrap Export CSV button with filter count indicator (amber text below button)
- Add computed to vue import
2026-05-31 20:11:02 +02:00
curo1305 f5e111bfa2 feat(06.2-05): actionable cloud error + audit log @ prefix
- CloudFolderView: detect no-connection error and show actionable message
  directing user to Settings; add router-link to /settings and Retry button
- AuditLogTab: prefix user handles with @ in the User column
2026-05-31 20:10:22 +02:00
curo1305 045e723f7a feat(06.2-05): show @handle in AccountView and AdminUsersTab
- Add Username row (@handle) to Account information section in AccountView.vue
- Add Handle column (th + td with @prefix) to users table in AdminUsersTab.vue
- Both use existing data already present in API responses (no backend changes)
2026-05-31 20:09:50 +02:00
curo1305 0647e6e9bf feat(06.2-04): frontend — user_handle filter, fetch+Blob export, daily-export section
- adminListAuditLog: rename user_id param to user_handle (backend API change)
- adminExportAuditLogCsv(): fetch+Blob pattern — sends Bearer header (D-13, T-06.2-04-03)
- adminListDailyExports(): raw fetch returning JSON for daily export listing (D-17)
- adminDownloadDailyExport(date): fetch+Blob download with audit-{date}.csv filename (D-17)
- AuditLogTab: rename filters.user_id to filters.user_handle + label 'User handle' (D-12, C-5)
- AuditLogTab: exportCsv() replaced with async fetch+Blob call, exportingCsv loading state
- AuditLogTab: daily exports section below pagination — date dropdown + Download button (D-17, C-4)
- window.location.href removed from AuditLogTab (broken auth bypass closed)
- Build exits 0, full backend suite: 337 passed, 1 pre-existing failure
2026-05-31 15:21:23 +02:00
curo1305andClaude Sonnet 4.6 34b18a9f08 feat(06.2-02): frontend — is_shared badge fix + permission dropdown + View/Edit toggle
- DocumentCard.vue: fix Shared pill to read doc.is_shared (was doc.share_count > 0)
- ShareModal.vue: add permission select between handle input and submit button
- ShareModal.vue: replace static "view" span with View/Edit toggle group per share row
- ShareModal.vue: add handlePermissionChange with optimistic update + rollback on error
- documents.js: update shareDocument(docId, handle, permission='view') signature
- documents.js: add updateSharePermission(shareId, permission) action
- api/client.js: pass permission in createShare POST body
- api/client.js: add updateSharePermission PATCH helper

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 15:07:04 +02:00
curo1305andClaude Sonnet 4.6 d98e3ab7a1 test(phase-02): add Nyquist validation tests — fill SEC-05, AUTH-08, SEC-03 and frontend gaps
8 test files, 60 new tests (14 backend + 46 frontend). All green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 12:04:21 +02:00
curo1305andClaude Sonnet 4.6 5250895587 feat(05): cloud folder browser views, routing, and sidebar nav
Add CloudStorageView (/cloud) and CloudFolderView (/cloud/:provider/:folderId).
Tree items filter to directories only (is_dir) to hide files in the nav tree.
CloudProviderTreeItem root click navigates to /cloud/{provider}/root instead
of /settings. AppSidebar Cloud Storage link upgraded to router-link with
active-class highlighting. Router registers both cloud routes with requiresAuth.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 11:58:08 +02:00
curo1305 72687212a1 feat(05-11): add adminDeleteUser API function + inline delete confirmation panel
- Export adminDeleteUser(id, adminPassword) from client.js — sends JSON body to DELETE /api/admin/users/{id}
- AdminUsersTab: add confirmDelete, deletePassword, deleteError state refs
- AdminUsersTab: add startDelete, cancelDelete, confirmDoDelete functions (mutually exclusive with deactivate panel)
- AdminUsersTab: Delete button added to active and deactivated user rows
- AdminUsersTab: inline password confirmation panel with Argon2 verification via backend
2026-05-30 11:39:10 +02:00
curo1305 87de148a59 feat(05-10): OAuth fetch + Nextcloud edit fix + Edit on ERROR + text overflow
- client.js: add initiateOAuth() and getConnectionConfig() helpers
- SettingsCloudTab: replace window.location.href with initiateOAuth() + fetch/JWT
- SettingsCloudTab: add Edit button to ACTIVE and ERROR blocks for non-OAuth providers
- SettingsCloudTab: wrap ConfirmBlock in w-full overflow-hidden div
- CloudCredentialModal: add existing prop, edit-mode pre-population via /config endpoint
- CloudCredentialModal: add showAdvanced + customEndpoint for Nextcloud custom paths
- ConfirmBlock: add break-words class to message paragraph
- cloud.py: add GET /api/cloud/connections/{id}/config endpoint (non-secret fields)
2026-05-30 11:30:13 +02:00
curo1305 4a42ccee5a feat(05-09): authenticated document preview via fetch + Blob URL
- Add fetchDocumentContent() to client.js: fetch with Bearer auth, 401 refresh
  retry pattern, returns raw Response (not parsed JSON) for blob() calls
- Replace iframe :src=proxyUrl (unauthenticated) in DocumentPreviewModal.vue
  with authenticated fetch → blob → URL.createObjectURL; loading/error states;
  URL.revokeObjectURL on unmount to prevent memory leaks
- Replace window.open(rawUrl) in DocumentView.vue openPdf() with
  fetchDocumentContent → blob → objectUrl → window.open; 60s auto-revoke
- Frontend build exits 0 with zero errors
- Closes T-05-09-04: no persistent unauthenticated content exposure
2026-05-30 11:18:01 +02:00
curo1305 98576ac298 feat(05-08): add Cloud Storage collapsible section to AppSidebar
- Import CloudProviderTreeItem and useCloudConnectionsStore
- Add cloudExpanded ref (default true) and activeCloudConnections/loadingCloudConnections computed
- Insert Cloud Storage section between Folders and Topics sections
- Fetch connections on mount; render one CloudProviderTreeItem per ACTIVE connection
- Empty state: 'No cloud storage connected'; loading state: 'Loading...'
2026-05-29 08:33:33 +02:00
curo1305 34b0593782 feat(05-08): add cloud tree components and getCloudFolders API function
- Add getCloudFolders(provider, folderId) to api/client.js (GET /api/cloud/folders/{provider}/{folderId})
- Create CloudProviderTreeItem.vue: lazy-load folder tree per connection, providerIconColor computed, expand/collapse arrow, loading/error states
- Create CloudFolderTreeItem.vue: recursive folder tree node with is_dir expand arrow, lazy-load children, depth padding
2026-05-29 08:32:19 +02:00
curo1305 63a68296a5 feat(05-07): 3-tab SettingsView, SettingsCloudTab, CloudCredentialModal
- Convert SettingsView to 3-tab layout (Preferences/AI/Cloud) matching AdminView pattern
- Extract SettingsPreferencesTab.vue and SettingsAiTab.vue from original SettingsView
- Create SettingsCloudTab.vue with all 4 providers, status badges, action buttons
- Create CloudCredentialModal.vue for WebDAV/Nextcloud credential input
- Handle OAuth callback query params (cloud_connected/cloud_error) in SettingsView.onMounted
- Add success toast (auto-dismiss 5s) and persistent error banner for OAuth results
- Fix pre-existing build failure: add build.target=esnext to vite.config.js for top-level await support
- 2 SettingsCloudTab mount tests passing (W4 — CLAUDE.md)
2026-05-29 08:12:36 +02:00
curo1305andClaude Sonnet 4.6 d6f742a3c1 chore(phase-4): UAT complete — Phase 4 marked done, sidebar collapse, duplicate-folder fix
UAT: 14/15 passed. Bug fixed: folders/rootFolders array alias in fetchFolders caused
duplicate folder row on creation (rootFolders = [...list] breaks the shared reference).
Sidebar: Folders section now has a collapse/expand chevron, collapsed by default.
State: Phase 4 complete, Phase 5 (Cloud Storage Backends) is next.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 17:34:07 +02:00
curo1305andClaude Sonnet 4.6 87a32b7ee8 feat(phase-4): complete UX redesign — FileManagerView, FolderTreeItem, test suite, and all Phase 4 fixes
Adds the unified file manager view (Windows Explorer-style), collapsible
folder tree sidebar item, full vitest test suite (55 tests, 4 files), and
commits all Phase 4 backend/frontend fixes that were staged but uncommitted.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 17:10:52 +02:00
curo1305 81da251669 fix(phase-4): add Move to folder dropdown on DocumentCard hover 2026-05-25 23:17:35 +02:00
curo1305 a3f5fc2e69 feat(phase-4-09): wire components into views — sidebar, cards, home, folder, shared, settings, admin
- AppSidebar: add 'Shared with me' entry (purple icon, count badge) and Folders section with New folder CTA
- DocumentCard: add group class, hover-reveal share button, ShareModal v-if, shared indicator pill
- HomeView: add SearchBar + SortControls above document list; fetchFolders on mount
- FolderView: new view with FolderBreadcrumb, FolderRow list, inline new-subfolder input, document list
- SharedView: new view fetching /api/shares/received with owner_handle display and empty state
- DocumentView: add PDF preview logic (in_app=DocumentPreviewModal, new_tab=window.open); load preferences on mount
- SettingsView: add Document Preferences card with pdf_open_mode radio buttons, auto-save on change
- AdminView: add Audit Log tab alongside Users/Quotas/AI Config tabs
2026-05-25 22:14:12 +02:00
curo1305 36721575a5 feat(phase-4-09): create new components — FolderRow, FolderBreadcrumb, FolderDeleteModal, ShareModal, DocumentPreviewModal, SearchBar, SortControls, AuditLogTab
- FolderRow: inline rename, three-dot menu, delete/rename callbacks, outside-click close
- FolderBreadcrumb: truncation at depth > 4, nav aria-label, ol structure
- FolderDeleteModal: role=dialog, warning icon, doc count in body, Keep/Delete buttons
- ShareModal: handle input, recipients list with revoke, 404/409 error handling
- DocumentPreviewModal: iframe with proxy URL only (never presigned), Escape/overlay close
- SearchBar: role=search, aria-label, Escape clears
- SortControls: aria-pressed, direction indicator, toggle vs switch logic
- AuditLogTab: filters, paginated table, CSV export via window.location.href
- api/client.js: add adminListAuditLog function
2026-05-25 22:10:23 +02:00
curo1305 23c568ae89 feat(03-05): create QuotaBar.vue; embed in AppSidebar between topics nav and footer
- QuotaBar.vue: new sidebar quota widget — onMounted calls authStore.fetchQuota(); computed pct/barColor/labelColor/label from authStore.quota; color thresholds <80% indigo-500, 80-95% amber-500, >=95% red-500; skeleton loading state (animate-pulse); hides on loadFailed (v-if); role=progressbar with aria-valuenow/aria-valuemin/aria-valuemax/aria-label
- AppSidebar.vue: import QuotaBar; insert <QuotaBar /> between </nav> and settings footer div
- Frontend build exits 0 (verified)
2026-05-23 20:49:07 +02:00
curo1305 eb18428d07 feat(03-05): 3-step presigned upload + quota state in auth store + progress UI
- api/client.js: extend request() to attach .status and .payload on 413 structured errors; remove legacy uploadDocument multipart function
- stores/auth.js: add quota ref({used_bytes:0, limit_bytes:0}) and fetchQuota() action (silent catch); expose in store return
- stores/documents.js: replace single upload() with uploadToMinIO XHR helper + 3-step async action (getUploadUrl→XHR PUT→confirmUpload); track uploadProgress map keyed by filename+timestamp (T-03-25); call fetchQuota after upload success and document delete
- components/upload/UploadProgress.vue: add aria progressbar per row, percentage label, quota rejection error block (role=alert, red-50/red-200) from item.quotaError; use plain anchor for Manage storage link
2026-05-23 20:46:24 +02:00
curo1305 92e3d755d0 feat(02-05): AppSidebar admin link and user identity footer
- Add conditional Admin nav link (v-if authStore.user?.role === 'admin') with shield SVG icon
- Add user identity footer: initials avatar (bg-indigo-100), email (truncate flex-1), sign-out icon button (aria-label="Sign out")
- Import useAuthStore alongside existing topicsStore; add useRouter for post-logout redirect
- All existing nav links, topicsStore reference, and scoped styles preserved unchanged
2026-05-22 20:09:16 +02:00
curo1305 9137f41537 feat(02-05): admin tab components and AdminView
- AdminView.vue: tabbed layout (Users | Quotas | AI Config) with UI-SPEC tab strip classes
- AdminUsersTab.vue: user table with create form (crypto.getRandomValues password), inline deactivation confirmation, reactivate, reset-password, row-level spinner, empty state
- AdminQuotasTab.vue: quota inline edit with MB display, usage %, warning when limit < usage
- AdminAiConfigTab.vue: AI provider/model per-user with 1.5s "Saved" confirmation
- client.js: fix adminDeactivateUser/adminReactivateUser to use PATCH /status endpoint, fix adminResetUserPassword to /password-reset, fix adminUpdateAiConfig to send ai_provider/ai_model, add adminGetUserQuota
- No impersonation UI in any admin component (T-02-31)
2026-05-22 20:09:05 +02:00
curo1305 d73e2f6112 feat(02-03): TOTP enrollment flow, backup codes, AccountView, ConfirmBlock
- TotpEnrollment.vue: three-step enrollment (setup → verify → backup-codes); emits 'enrolled'
- BackupCodesDisplay.vue: 2-column grid, copy-all clipboard, acknowledgment checkbox
- ConfirmBlock.vue: reusable inline confirmation block with 'confirmed'/'cancelled' emits
- AccountView.vue: TOTP section (enrollment or disable), change-password with breach/wrong-pw error handling, sign-out-all with ConfirmBlock
- npm run build exits 0
2026-05-22 19:54:53 +02:00
curo1305andClaude Sonnet 4.6 3b7d362600 feat(02-02): frontend auth store, router guard, Login/Register views
- frontend/src/stores/auth.js: useAuthStore with accessToken in memory
  only (never browser storage); login() accepts options.backupCode
- frontend/src/api/client.js: extended with Bearer token injection,
  401 auto-refresh retry, all auth/admin API functions, changePassword
- frontend/src/router/index.js: auth routes added (/login, /register,
  /password-reset, /account, /admin); beforeEach guard redirects
  unauthenticated users to /login with redirect param
- frontend/src/layouts/AuthLayout.vue: centered bare layout for auth pages
- frontend/src/views/auth/LoginView.vue: three-step flow (password, TOTP,
  backup code); "Use a backup code instead" link; UI-SPEC copywriting
- frontend/src/views/auth/RegisterView.vue: registration with
  PasswordStrengthBar; HIBP error display; UI-SPEC copywriting
- frontend/src/components/auth/PasswordStrengthBar.vue: 4-segment bar
- frontend/src/components/ui/AppSpinner.vue: animate-spin SVG spinner
- Stub views: PasswordResetView, NewPasswordView, AccountView, AdminView
- .gitignore: exclude frontend/node_modules, dist, package-lock.json

npm run build exits 0. All acceptance criteria verified.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 19:45:21 +02:00
curo1305andClaude Sonnet 4.6 7a34807fa0 chore: initial commit — existing single-user document scanner codebase
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 08:53:28 +02:00