Commit Graph
87 Commits
Author SHA1 Message Date
curo1305 20183e9c5e chore: merge executor worktree (10-03 BreadcrumbBar) 2026-06-15 20:17:57 +02:00
curo1305 8e1fb9e1db chore: merge executor worktree (10-02 EmptyState) — kept 10-01 AppIcon.vue (resolvedPaths vs paths[name]; 10-01 is canonical) 2026-06-15 20:17:49 +02:00
curo1305 5ed6ae9565 chore: merge executor worktree (10-05 Nyquist stubs) 2026-06-15 20:17:06 +02:00
curo1305 7e584e032a feat(10-03): implement BreadcrumbBar.vue — shared breadcrumb component (GREEN)
- Options API component with segments/{id?,label}, rootLabel, showRoot props
- Emits navigate(segment.id) for intermediate clicks, navigate(null) for root
- Computed visibleSegments collapses >4 segments to first+ellipsis+last two
- Segments without id render as plain non-clickable spans (admin static segments)
- Uses AppIcon for chevronRight separator (no inline SVG)
- All 10 Vitest tests pass
- Also creates AppIcon.vue (Rule 3: BreadcrumbBar imports it)
2026-06-15 20:13:29 +02:00
curo1305 794ff42bf5 test(10-05): Wave 0 keyboard + OS-drag + drag-to-move stubs (UX-05..09, UX-11)
- keyboard.test.js: 11 it.todo stubs for UX-05 search focus, UX-06 escape clear, UX-07 upload picker, UX-08 new folder
- OsDragOverlay.test.js: 7 it.todo stubs for UX-09 OS file drag overlay depth-counter + teleport
- StorageBrowser.dragmove.test.js: 6 it.todo stubs for UX-11 drag-to-move ring highlight + toast wiring
2026-06-15 20:12:39 +02:00
curo1305 e56d17efcb feat(10-02): implement EmptyState.vue — shared empty-state component (GREEN)
- Options API component with props: icon, headline, subtext, size
- Computed containerClass/iconClass/headlineClass/subtextClass for md and sm variants
- Named #cta slot with no fallback content
- Imports AppIcon from ./AppIcon.vue (child component)
- Also creates AppIcon.vue (deviation Rule 3: required to resolve EmptyState import)
- All 7 EmptyState tests pass; all 144 tests pass
2026-06-15 20:12:09 +02:00
curo1305 75970352fc test(10-05): Wave 0 skeleton + dropdown stubs (UX-02, UX-03, UX-04, UX-13, UX-14)
- StorageBrowser.skeleton.test.js: 7 it.todo stubs for UX-02 skeleton rows + UX-13 Teleport dropdown
- AppSidebar.empty.test.js: 10 it.todo stubs for UX-03 skeleton, UX-01 micro empty states, UX-14 inline-New removal
- AdminAuditView.skeleton.test.js: 5 it.todo stubs for UX-04 audit skeleton + UX-01 empty state
- AdminUsersView.skeleton.test.js: 3 it.todo stubs for UX-04 users skeleton
- dropdown.test.js: 4 it.todo stubs for UX-13 Teleport+getBoundingClientRect pattern
2026-06-15 20:11:40 +02:00
curo1305 b6ea858c9b test(10-03): add failing BreadcrumbBar tests (RED)
- 10 Vitest unit tests covering showRoot, rootLabel, navigate emits
- Tests segments shape {id?, label} (not {id, name})
- Covers ellipsis collapse for >4 segments, no-id static segments
- AppIcon stubbed via global.stubs for isolated rendering
2026-06-15 20:11:37 +02:00
curo1305 f92d98d067 feat(10-04): implement toast store, ToastContainer, mount in App.vue
- toast.js: reactive toasts array, show/dismiss with auto-dismiss via setTimeout
- ToastContainer.vue: Options API, Teleport to body, TransitionGroup, data-test attr
- type-to-class maps: accentClass/iconName/iconColorClass for success/error/warning/info
- App.vue: import and mount <ToastContainer /> after layout div
- all 10 tests pass; SettingsAccountTab and TotpEnrollment regressions green
2026-06-15 20:11:12 +02:00
curo1305 74fc41cefa feat(10-01): implement AppIcon.vue with full ICON_PATHS registry
- Options API component with inheritAttrs: false for class forwarding
- 32 named icons: 31 single-path + 1 dual-path (cog as Array)
- resolvedPaths computed warns in DEV for unknown icon names
- v-if guard renders nothing for unknown names
- Array.isArray check renders v-for paths for dual-path icons
- All 6 AppIcon tests pass (GREEN)
2026-06-15 20:10:41 +02:00
curo1305 96f4b5f80e test(10-02): add failing EmptyState tests (RED)
- 7 it() blocks covering prop rendering, slot rendering, and size variants
- Tests stub AppIcon via global.stubs to avoid ordering dependency
- All 7 tests fail with module-not-found (EmptyState.vue not yet created)
2026-06-15 20:10:15 +02:00
curo1305 b12137c4ce test(10-04): add failing tests for toast store and ToastContainer
- 6 toast store tests: show/dismiss/auto-dismiss/duration=0/stacking
- 4 ToastContainer tests: empty/render count/click dismiss/accent class
- uses vi.useFakeTimers() for timer-based assertions
- Teleport and AppIcon stubbed for DOM-safe mounting
2026-06-15 20:10:00 +02:00
curo1305 4a45dd4801 test(10-01): add failing AppIcon tests for icon registry contract
- 6 tests covering name→path rendering, class forwarding, dual-path (cog), svg attrs, unknown-name warn, and path stroke attrs
- RED phase: AppIcon.vue does not exist yet; tests fail on import
2026-06-15 20:09:21 +02:00
curo1305andClaude Sonnet 4.6 7ef65de046 refactor(09-05): CODE-09 purge — Phase 9 files (WHAT comments removed)
Frontend: AdminLayout, AdminSidebar, AdminOverviewView, AdminUsersView,
AdminQuotasView, AdminAiView, AdminAuditView, router/index.js, LoginView,
tailwind.config.js, api/admin.js — WHAT labels stripped; WHY constraints
preserved (D-16 anchors, security notes, api_key write-only invariant,
router guard rationale, D-08/D-09/D-10 decision refs, fetchWithRetry reason).
Backend: overview.py was already clean (no WHAT comments present).
Frontend: 137 tests pass, build succeeds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 21:52:30 +02:00
curo1305 e6467d18cf feat(09-04): delete AdminView + 4 tab files; update tests + router guard test
- git rm AdminView.vue, AdminUsersTab.vue, AdminQuotasTab.vue, AdminAiConfigTab.vue, AuditLogTab.vue
- Migrate tab tests to import from views/admin/Admin*View.vue
- Update router.guard.test.js: replace AdminView mock with AdminLayout + 5 admin view mocks
- Add D-09 redirect test (admin on / → /admin)
- Fix stale api/admin.js JSDoc consumer list
- Fix SettingsView.vue stale AdminView comment reference
2026-06-12 16:11:00 +02:00
curo1305 bdd68b2edf feat(09-04): wire admin login redirect in LoginView.vue (D-08)
- After successful login, admin users redirect to /admin; regular users to /
- Honors ?redirect= query param for non-admin users as before
- authStore.user.role is synchronously populated before handleLoginResult fires
2026-06-12 16:08:25 +02:00
curo1305 5dbfb6c1d8 feat(09-04): rewire /admin nested route + guard + Tailwind safelist
- Replace flat /admin route with nested AdminLayout subtree (5 children)
- Fix beforeEach guard to use to.matched.some(r => r.meta.requiresAdmin)
- Add D-09 admin-on-user-route redirect and D-10a non-admin-on-admin redirect
- Add Tailwind safelist covering sky+amber color families (formatters + AuditLogTab)
2026-06-12 16:07:56 +02:00
curo1305 164003b19b feat(09-03): extract AdminAiView + AdminAuditView from tab components
- Created frontend/src/views/admin/AdminAiView.vue (extracted from AdminAiConfigTab.vue)
  - Import path for SearchableModelSelect rewritten to ../../components/ui/SearchableModelSelect.vue
  - System AI Providers (Global) section preserved above per-user table (Phase 7 constraint)
- Created frontend/src/views/admin/AdminAuditView.vue (verbatim from AuditLogTab.vue per D-13)
  - actionTypeClass() helper preserved verbatim with all bg-amber-50, bg-purple-50 dynamic classes
  - Filter bar, paginated table, CSV download, daily-export list all preserved as-is
- Both files have no defineProps, no top-level padding, identical line counts to sources
- Build succeeds: 143 modules transformed, no errors
2026-06-12 16:01:29 +02:00
curo1305 d690a445b9 feat(09-03): extract AdminUsersView + AdminQuotasView from tab components
- Created frontend/src/views/admin/AdminUsersView.vue (verbatim extraction of AdminUsersTab.vue)
- Created frontend/src/views/admin/AdminQuotasView.vue (verbatim extraction of AdminQuotasTab.vue)
- Both files have no defineProps, no top-level padding, identical import paths (../../api/client.js, ../../utils/formatters.js)
- Line counts match source exactly (480 and 182 lines respectively)
- Build succeeds with no Vite errors referencing new view files
2026-06-12 15:58:51 +02:00
curo1305 1e14e15cbf feat(09-02): create AdminOverviewView.vue
- Single-fetch view calling getAdminOverview() on mount with loading/error states
- Four stat cards grid (Users, Storage, Processing, Ready) per ADMIN-11 and D-01
- Recent audit table with 5 columns (When/Event/Actor/Target/IP) matching AuditLogTab.vue structure
- Uses formatSize/formatDate from shared utils/formatters.js (no duplication)
- No top-level padding (AdminLayout owns p-8 max-w-5xl mx-auto)
- No Pinia store — single-fetch component consistent with admin tab pattern
2026-06-12 15:48:19 +02:00
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 fd12ee2a22 feat(09-02): add getAdminOverview() to api/admin.js
- Export async function calling request('/api/admin/overview')
- Follows existing GET helper pattern (no extra wrapping)
- Auto-re-exported via client.js barrel (Phase 8 CODE-04 invariant preserved)
2026-06-12 15:46:00 +02:00
curo1305andClaude Sonnet 4.6 6bda133c81 chore(08-08): PERF-01 packages + Vite 6 upgrade + pin requirements.txt
- Upgraded vite 5.4.21 → 6.4.3 (fixes CVE-2026-39363, CVE-2026-39364)
- Upgraded @vitejs/plugin-vue 5.2.4 → 6.0.7 (Vite 6 peer dep)
- Installed @vueuse/core@14.3.0, @vueuse/integrations@14.3.0,
  sortablejs@1.15.7, @tailwindcss/forms@0.5.11,
  rollup-plugin-visualizer@7.0.1, @types/sortablejs@1.15.9
- Wired @tailwindcss/forms plugin in tailwind.config.js (VISUAL-02 ready)
- Pinned backend/requirements.txt to exact == versions per D-17 (32 packages)
- Frontend: 136/136 tests pass on Vite 6; 0 npm audit vulnerabilities
- Backend: 408 passed, 4 skipped, 7 xfailed (baseline 405+1)
- Phase 8 complete (8/8 plans)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 10:54:34 +02:00
curo1305 02bf04cc63 feat(08-07): decompose frontend api/client.js into domain modules + utils — CODE-04 CODE-08
- Rewrite client.js as 20-line barrel re-export (was 636 lines)
- All 35+ consumer files continue to resolve named exports unchanged
- Fix pre-existing bug: testAiConnection was POST but tests expected GET with query params
- All 136 frontend tests pass; production build succeeds
2026-06-10 18:43:41 +02:00
curo1305 a895b1812f feat(08-07): create domain modules admin.js, folders.js, shares.js, cloud.js — CODE-04
- admin.js: 17 functions; adminExportAuditLogCsv + adminDownloadDailyExport use fetchWithRetry
- folders.js: 6 functions — import request from utils.js
- shares.js: 5 functions — import request from utils.js
- cloud.js: 7 functions including initiateOAuth — import request from utils.js
- Blob-download retry boilerplate eliminated from admin.js (CODE-08)
2026-06-10 18:42:01 +02:00
curo1305 fd9188b53c feat(08-07): create domain modules documents.js, auth.js, topics.js — CODE-04
- documents.js: 10 functions; fetchDocumentContent refactored to use fetchWithRetry
- auth.js: 15 functions (login through getMyQuota) — import request from utils.js
- topics.js: 5 functions — import request from utils.js
- All functions copied verbatim from client.js; no consumer files modified
2026-06-10 18:40:32 +02:00
curo1305 80d6f376b0 feat(08-07): create api/utils.js with request() and fetchWithRetry() — CODE-08
- Move request() verbatim from client.js to utils.js (breaks circular dep)
- Add fetchWithRetry() consolidating 3 blob-download 401-retry patterns
- Lazy import of authStore preserved for Pinia bootstrap cycle safety
- Bearer token from authStore memory only per CLAUDE.md security rule
2026-06-10 18:39:41 +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
curo1305 e417b71539 feat(08-03): create useToastStore Pinia stub with locked show() contract
- Defines show(message, type='success', duration=4000) as silent no-op
- Positional parameters only per UI-SPEC.md contract
- Phase 10 (UX-10) must implement rendering without modifying call sites
2026-06-08 16:30:30 +02:00
curo1305 61b1e045c4 feat(07.4-02): update api/auth.py call sites, promote FGP tests, version bump 0.1.3
- api/auth.py login + refresh call sites pass User-Agent and Accept-Language
  headers to create_access_token (D-05 — fgp binding at token issuance)
- test_auth_fgp.py: promote all 4 xfail stubs to real assertions (FGP-01..04)
- conftest.py: add _TEST_USER_AGENT constant; configure async_client to send
  consistent User-Agent; update auth_user/second_auth_user/admin_user fixtures
  to bind fgp to _TEST_USER_AGENT so tokens validate correctly in tests
- test_auth_deps.py: import _TEST_USER_AGENT; update auth_client fixture and
  all create_access_token calls to use the constant
- test_cloud.py: update _create_user_and_token to bind fgp to _TEST_USER_AGENT
- test_documents.py: update 3 inline create_access_token calls to pass user_agent
- test_security_headers.py: import _TEST_USER_AGENT; update headers_client +
  token creation to use the constant
- Version bump: backend 0.1.2 → 0.1.3, frontend 0.1.2 → 0.1.3
- [Rule 1 - Bug] Fix httpx default User-Agent vs empty-string fgp mismatch in
  test infrastructure: 10 tests were failing due to fgp check rejecting tokens
  created with fgp="" when client sent "python-httpx/X.Y.Z"
2026-06-06 22:12:57 +02:00
curo1305 21e5d27c90 feat(07.3-03): frontend remember_me — checkbox + ref threading + store pass-through
- LoginView.vue: add rememberMe ref(false) + "Stay signed in for 30 days" checkbox in password step; thread rememberMe.value through all 3 submit handlers (submitPassword, submitTotp, submitBackupCode) (D-12)
- stores/auth.js: login() forwards options.rememberMe as remember_me in api.login body (D-12)
- api/client.js: no change needed — already forwards full body verbatim
- Frontend build passes (vite build exits 0)
2026-06-06 17:23:02 +02:00
curo1305 8be792ab4c feat(07.3-02): ES256 JWT algorithm upgrade + startup rotation hook
- config.py: add refresh_token_expire_hours=16, jwt_private_key, jwt_public_key fields (D-01, D-09)
- services/auth.py: swap all 4 JWT sites to ES256 via base64-decoded PEM keys; remove HS256 (D-02, D-03)
- main.py: add _rotate_tokens_on_algorithm_change lifespan hook — bulk-revokes refresh tokens on algorithm change; idempotent on repeat boots (D-04, D-05)
- test_auth_es256.py: promote ES256-01..05 + CFG-01 stubs to 6 passing tests; RM-01..03 remain xfail
- docker-compose.yml: inject JWT_PRIVATE_KEY + JWT_PUBLIC_KEY into backend + celery-worker (D-07)
- README.md: add JWT key env vars + key generation Python one-liner snippet
- .env.example: add JWT_PRIVATE_KEY= and JWT_PUBLIC_KEY= lines
- Version bump to 0.1.2
2026-06-06 17:19:50 +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 d771f0805d fix(06.2): shared badge and recipient handle missing in FileManagerView
- shares.py grant_share: include recipient_handle in response so ShareModal shows the name immediately without reload
- FileManagerView: add Shared pill badge next to document name (badge only existed in DocumentCard, not the main file manager view)
- FileManagerView ShareModal: wire @unshared to clear is_shared flag when last recipient is removed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 19:47:00 +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 9e8f8d5bbc fix(06.2): WR-06 use URLSearchParams in listShares for consistent encoding 2026-06-01 14:31:50 +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 3fa7e8b866 fix(06.2): CR-04 WR-05 audit export functions use 401-refresh-retry and safe URL.revokeObjectURL 2026-06-01 14:26:05 +02:00