diff --git a/.planning/phases/10-ux-interaction/10-REVIEW.md b/.planning/phases/10-ux-interaction/10-REVIEW.md
index b351941..cde8c97 100644
--- a/.planning/phases/10-ux-interaction/10-REVIEW.md
+++ b/.planning/phases/10-ux-interaction/10-REVIEW.md
@@ -1,15 +1,11 @@
---
phase: 10-ux-interaction
-reviewed: 2026-06-16T00:00:00Z
+reviewed: 2026-06-16T12:00:00Z
depth: standard
-files_reviewed: 45
+files_reviewed: 34
files_reviewed_list:
- frontend/src/App.vue
- frontend/src/__tests__/keyboard.test.js
- - frontend/src/components/auth/TotpEnrollment.vue
- - frontend/src/components/cloud/CloudCredentialModal.vue
- - frontend/src/components/cloud/CloudFolderTreeItem.vue
- - frontend/src/components/cloud/CloudProviderTreeItem.vue
- frontend/src/components/documents/DocumentCard.vue
- frontend/src/components/documents/SearchBar.vue
- frontend/src/components/folders/FolderRow.vue
@@ -17,15 +13,12 @@ files_reviewed_list:
- frontend/src/components/layout/OsDragOverlay.vue
- frontend/src/components/layout/__tests__/AppSidebar.empty.test.js
- frontend/src/components/layout/__tests__/OsDragOverlay.test.js
- - frontend/src/components/settings/SettingsAccountTab.vue
- - frontend/src/components/settings/SettingsCloudTab.vue
- frontend/src/components/storage/StorageBrowser.vue
- frontend/src/components/storage/__tests__/StorageBrowser.dragmove.test.js
- frontend/src/components/storage/__tests__/StorageBrowser.skeleton.test.js
- frontend/src/components/ui/AppIcon.vue
- frontend/src/components/ui/BreadcrumbBar.vue
- frontend/src/components/ui/EmptyState.vue
- - frontend/src/components/ui/SearchableModelSelect.vue
- frontend/src/components/ui/ToastContainer.vue
- frontend/src/components/ui/__tests__/AppIcon.test.js
- frontend/src/components/ui/__tests__/BreadcrumbBar.test.js
@@ -35,314 +28,139 @@ files_reviewed_list:
- frontend/src/components/upload/DropZone.vue
- frontend/src/stores/__tests__/toast.test.js
- frontend/src/stores/toast.js
- - frontend/src/views/AccountView.vue
- - frontend/src/views/CloudFolderView.vue
- - frontend/src/views/CloudStorageView.vue
- - frontend/src/views/DocumentView.vue
- frontend/src/views/FileManagerView.vue
- - frontend/src/views/SettingsView.vue
- - frontend/src/views/SharedView.vue
- - frontend/src/views/__tests__/FileManagerView.test.js
- - frontend/src/views/admin/AdminAiView.vue
- frontend/src/views/admin/AdminAuditView.vue
- - frontend/src/views/admin/AdminOverviewView.vue
- - frontend/src/views/admin/AdminQuotasView.vue
- frontend/src/views/admin/AdminUsersView.vue
- frontend/src/views/admin/__tests__/AdminAuditView.skeleton.test.js
- frontend/src/views/admin/__tests__/AdminUsersView.skeleton.test.js
+ - frontend/src/views/SharedView.vue
+ - frontend/src/views/CloudFolderView.vue
+ - frontend/src/views/CloudStorageView.vue
+ - frontend/src/components/sharing/ShareModal.vue
+ - frontend/src/components/folders/FolderDeleteModal.vue
findings:
- critical: 4
- warning: 9
+ critical: 2
+ warning: 6
info: 4
- total: 17
+ total: 12
status: issues_found
---
# Phase 10: Code Review Report
-**Reviewed:** 2026-06-16T00:00:00Z
+**Reviewed:** 2026-06-16T12:00:00Z
**Depth:** standard
-**Files Reviewed:** 45
+**Files Reviewed:** 34
**Status:** issues_found
## Summary
-This phase delivered 10+ UX interaction plans covering keyboard shortcuts, skeleton loading, drag-and-drop, OS-level file drag overlay, toast notifications, Teleport-based dropdowns, and breadcrumb/empty-state polish. The overall architecture is sound and the CLAUDE.md shared-module rules are consistently followed. However, several correctness bugs, one security gap, and multiple quality issues were found.
+Phase 10 delivers skeleton loading states, keyboard shortcuts (`/`, `U`, `N`, `Escape`), OS drag-and-drop overlay, drag-to-move documents, Teleport-based dropdown positioning, a toast notification system, and new shared UI components (`EmptyState`, `BreadcrumbBar`, `ToastContainer`, `AppIcon`). The implementation is well-structured: shared formatters are correctly imported in all reviewed views, event listeners are properly cleaned up in `onUnmounted`, and the Teleport+`getBoundingClientRect` pattern is consistent across components.
-The most critical problems are: (1) a duplicate, diverged implementation of the entire account settings screen split between `AccountView.vue` and `SettingsAccountTab.vue`; (2) `closeFolderPicker` in `DocumentCard.vue` closing on any click inside any `.relative` element across the entire page — not only its own trigger; (3) global `window.addEventListener` calls in `SearchableModelSelect.vue` are registered outside `onMounted`, so they run during SSR or module evaluation in test environments and are never cleaned up when multiple instances mount and unmount; and (4) the `generateRandomPassword` Fisher-Yates shuffle in `AdminUsersView.vue` reuses only 4 bytes for shuffling a 16-character array, which produces a weak shuffle distribution.
+Two blockers were found: a direct Vue prop mutation in `DocumentCard.vue` (raises a runtime warning and can silently fail to update the UI), and a keyboard shortcut bleed-through where pressing Escape while a modal is open fires both the modal's close handler and `clearSearch` simultaneously. Six warnings cover the `closest('.relative')` outside-click detector pattern (present in three files) that prevents pickers from closing correctly, a non-compliant Fisher-Yates shuffle in the admin password generator, an unused import, a custom local date formatter that violates the shared-module rule, an upload count metric that can be unreliable, and a leak of stale DOM references in `StorageBrowser`'s folder picker map.
---
## Critical Issues
-### CR-01: Duplicate account settings implementation — diverged behaviour
+### CR-01: Direct Vue prop mutation in DocumentCard raises runtime warning and can fail silently
-**File:** `frontend/src/views/AccountView.vue:1` and `frontend/src/components/settings/SettingsAccountTab.vue:1`
+**File:** `frontend/src/components/documents/DocumentCard.vue:86`
-**Issue:** Both files implement the identical Account settings UI (account info, TOTP, change password, sign-out all). They have already diverged: `SettingsAccountTab` calls `useToastStore` and shows toasts when sessions are revoked after TOTP disable or password change (lines 154–156, 239–241); `AccountView` does neither. The CLAUDE.md rule "things that look the same are the same in code" and "no dead code — files with no active route and no active import are deleted immediately" is violated. Whichever is currently routed, the other leaks functionality and will continue to diverge.
+**Issue:** The `@unshared` event handler directly assigns `doc.is_shared = false` where `doc` is a component prop declared via `defineProps`. Vue 3 wraps props in a `readonly` proxy; writing to `doc.is_shared` triggers `[Vue warn]: Set operation on key "is_shared" failed: target is readonly` in development and silently does nothing in production builds that enforce the readonly constraint, leaving the card's "Shared" pill stale until the next full data fetch.
-**Fix:** Determine which is the canonical implementation (should be `SettingsAccountTab` because it is the smart component under `SettingsView`). If `AccountView.vue` has an active route pointing directly to it, that route must be removed and the component deleted. If `AccountView.vue` is already orphaned, delete it immediately. Do not keep both alive.
+```html
+
+@unshared="doc.is_shared = false"
+```
+
+**Fix:** Emit the event upward and let the parent manage the mutation. `DocumentCard` already has an `emit` defined:
+
+```js
+// DocumentCard.vue — add 'unshared' to defineEmits
+const emit = defineEmits(['reclassified', 'unshared'])
+```
+
+```html
+
+