فهرست منبع

update serena memories for jotai migration

Yuki Takei 7 ماه پیش
والد
کامیت
df32208cf0

+ 0 - 72
.serena/memories/apps-app-jotai-migration-fix-errors.md

@@ -1,72 +0,0 @@
-# 概要
-apps/app 配下で pnpm run lint:typecheck をすると沢山のエラーがでるが、これはリファクタの影響である
-そのエラーを潰したい
-
-# エラータイプA
-
-## エラーメッセージ例
-
-```
-src/client/components/Me/BasicInfoSettings.tsx:8:10 - error TS2724: '"~/states/server-configurations"' has no exported member named 'useRegistrationWhitelist'. Did you mean 'registrationWhitelistAtom'?
-
-8 import { useRegistrationWhitelist } from '~/states/server-configurations';
-           ~~~~~~~~~~~~~~~~~~~~~~~~
-```
-
-## 原因・経緯
-
-server-configurations.ts からカスタムフックを消したため、インポートできなくなっている
-
-## 対策
-useFoo() は使えないので、fooAtom を直接 import する
-
-```
-import { fooAtom } from '~/states/server-configurations';
-```
-
-利用側は以下:
-
-```
-// 旧コード例
-const [foo, setFoo] = useFoo();
-const [foo] = useFoo();
-const [, setFoo] = useFoo();
-
-// 置き換え新コード例
-const foo = useAtomValue(fooAtom);
-const setFoo = useSetAtom(fooAtom);
-```
-
-useAtomValue と useSetAtom は以下のようにインポートできる
-
-```
-import { useAtomValue } from 'jotai';
-import { useSetAtom } from 'jotai';
-```
-
-# エラータイプB
-
-## エラーメッセージ例
-```
-src/client/components/PageControls/PageControls.tsx:139:9 - error TS2488: Type 'boolean | null' must have a '[Symbol.iterator]()' method that returns an iterator.
-
-139   const [isSearchPage] = useIsSearchPage();
-```
-
-## 原因・経緯
-`useFoo()` の返り値の型が変わった
-
-具体的には、useAtom() 利用から useAtomValue() 利用に変わった
-
-## 対策
-
-```
-// 旧コード例
-const [foo, setFoo] = useFoo();
-const [foo] = useFoo();
-const [, setFoo] = useFoo();
-
-// 置き換え新コード例
-const foo = useAtomValue(fooAtom);
-const setFoo = useSetAtom(fooAtom);
-```

+ 66 - 32
.serena/memories/apps-app-jotai-migration-progress.md

@@ -1,4 +1,4 @@
-# Jotai 移行進捗
+# Jotai 移行進捗(更新済み)
 
 ## 実装状況
 
@@ -12,24 +12,52 @@
 - ✅ `useCollapsedContentsOpened`: 折りたたまれたコンテンツの開閉状態
 - ✅ `useCurrentProductNavWidth`: プロダクトナビゲーションの幅(永続化対応)
 - ✅ `useDeviceLargerThanXl`: デバイスサイズ判定
-- ✅ `useEditorMode`: エディターモード管理(部分的)
+- ✅ `useEditorMode`: エディターモード管理
+
+#### ページ関連状態(完了)
+- ✅ `useCurrentPageId`: 現在のページID
+- ✅ `useCurrentPageData`: 現在のページデータ
+- ✅ `useCurrentPagePath`: 現在のページパス
+- ✅ `usePageNotFound`: ページが見つからない状態
+- ✅ `usePageNotCreatable`: ページ作成不可状態
+- ✅ `useLatestRevision`: 最新リビジョン
+- ✅ リモートリビジョン関連フック群
+- ✅ `useShareLinkId`, `useTemplateTags`, `useTemplateBody`
+
+#### サーバー設定・グローバル状態(完了)
+- ✅ サーバー設定関連の全atomsとhooks
+- ✅ グローバル状態(現在ユーザーなど)
+- ✅ Socket.IO状態管理
 
 #### SSRハイドレーション対応(完了)
-- ✅ `useHydrateSidebarAtoms`: 統一的なJotai atomsの初期化
+- ✅ `useHydrateSidebarAtoms`: サイドバー用
+- ✅ `useHydratePageAtoms`: ページ用
+- ✅ `useHydrateGlobalAtoms`: グローバル用
+
+### ✅ 型チェック修正(完了済み)
+- ✅ 全てのTS2488エラー(配列分割代入の誤用)を修正済み
+- ✅ `pnpm run lint:typecheck` が成功することを確認済み
+- ✅ 以下のファイルを修正:
+  - `ShareLinkForm.tsx`: `const currentPageId = useCurrentPageId()`
+  - `ShareLink.tsx`: `const currentPageId = useCurrentPageId()`
+  - `LinkEditModal.tsx`: `const currentPath = useCurrentPagePath()`
 
 **実装済みファイル:**
-- `states/ui/sidebar.ts`: サイドバー状態の完全実装
-- `states/ui/sidebar/hydrate.ts`: サイドバー用SSRハイドレーション
+- `states/ui/sidebar/`: サイドバー状態の完全実装
 - `states/ui/device.ts`: デバイス状態
-- `states/ui/editor.ts`: エディター状態(部分)
+- `states/ui/editor/`: エディター状態
+- `states/page/`: ページ関連状態の完全実装
+- `states/server-configurations/`: サーバー設定状態
+- `states/global/`: グローバル状態
+- `states/socket-io/`: Socket.IO状態
 
 ## 🚧 次の実装ステップ(優先度順)
 
-### **優先度 1: ページ関連 UI 状態**
+### **優先度 1: 残りのUI状態(stores/ui.tsx内)**
 
 #### 1. `usePageControlsX` の移行 ← **次の優先タスク**
-- **ファイル**: `/workspace/growi/apps/app/src/stores/ui.tsx:171`
-- **実装先**: `states/ui/page.ts`
+- **ファイル**: `/workspace/growi/apps/app/src/stores/ui.tsx:149`
+- **実装先**: `states/ui/page.ts`(新規作成)
 - **使用箇所**: 
   - `PagePathNavSticky.tsx`
   - `PageControls.tsx`
@@ -38,53 +66,59 @@
 - **実装方針**: シンプルな number atom として実装
 
 #### 2. `useSelectedGrant` の移行
-- **ファイル**: `/workspace/growi/apps/app/src/stores/ui.tsx:192`
-- **実装先**: `states/ui/editor.ts`
+- **ファイル**: `/workspace/growi/apps/app/src/stores/ui.tsx:153`
+- **実装先**: `states/ui/editor.ts`(既存ファイルに追加)
 - **使用箇所**: 
   - `SavePageControls.tsx`
   - `GrantSelector.tsx`
   - `PageEditor.tsx`
 - **特徴**: エディター内の一時的な状態
+- **型**: `IPageSelectedGrant`
 
-### **優先度 2: モーダル状態の一括移行**
+### **優先度 2: 他のUI関連フック(判定・検討が必要)**
+
+以下のフックはSWR継続使用を検討(データフェッチングやcomputed値のため):
+- `useCurrentPageTocNode`: ページ固有の目次データ
+- `useSidebarScrollerRef`: ref管理
+- `useIsMobile`, `useIsDeviceLargerThanMd/Lg`: デバイス判定(一部は既に移行済み)
+- `usePageTreeDescCountMap`: 複雑なMap操作
+- `useCommentEditorDirtyMap`: 複雑なMap操作
+- `useIsAbleToShow*`: computed boolean値群
+
+### **優先度 3: モーダル状態の一括移行**
 
 #### 3. 全モーダル状態の移行
 - **新規ファイル**: `states/ui/modal.ts`
-- **対象モーダル(全9種類)**:
+- **対象モーダル(全18種類)**:
   - `usePageCreateModal`, `useGrantedGroupsInheritanceSelectModal`
-  - `useDeleteModal`, `useEmptyTrashModal`, `useDuplicateModal`
-  - `useRenameModal`, `usePutBackPageModal`, `usePresentationModal`
-  - `usePrivateLegacyPagesMigrationModal`
+  - `usePageDeleteModal`, `useEmptyTrashModal`, `usePageDuplicateModal`
+  - `usePageRenameModal`, `usePutBackPageModal`, `usePagePresentationModal`
+  - `usePrivateLegacyPagesMigrationModal`, `useDescendantsPageListModal`
+  - `usePageAccessoriesModal`, `useUpdateUserGroupConfirmModal`
+  - `useShortcutsModal`, `useDrawioModal`, `useHandsontableModal`
+  - `useConflictDiffModal`, `useBookmarkFolderDeleteModal`
+  - `useDeleteAttachmentModal`, `usePageSelectModal`, `useTagEditModal`
 - **実装方針**: 統一的なパターンでモーダル状態を管理
 - **特徴**: すべて一時的な状態で永続化不要
 
-### **優先度 3: データ関連状態の判定**
-
-以下はSWR継続使用を検討:
-- **Alert系**: `usePageStatusAlert`
-- **YJS関連**: `useCurrentPageYjsData`
-- **リモートページ関連**: revision関連の各種hooks
-- **編集クライアント**: `useEditingClients`
-
 ### **最終フェーズ: クリーンアップ**
 
 #### 4. 不要ファイルの削除とリファクタリング
-- `stores/ui.tsx` の完全削除
+- `stores/ui.tsx` の段階的縮小・最終削除
 - `stores/modal.tsx` の完全削除
 - 残存する SWR ベースの状態の最終判定
 - ドキュメントの更新
 
 ## 📊 進捗サマリー
 
-- **完了**: 8つの主要UI状態 + SSRハイドレーション
-- **次のタスク**: `usePageControlsX` の移行
-- **残り**: ページ関連2つ + モーダル9つ + クリーンアップ
-- **推定残工数**: 2-3週間(優先度3は判定のみ)
-
----
+- **完了**: 主要なUI状態 + ページ関連状態 + SSRハイドレーション + 型チェック修正
+- **次のタスク**: `usePageControlsX`と`useSelectedGrant`の移行
+- **残り**: UI関連フック数個(判定必要) + モーダル18個 + クリーンアップ
+- **推定残工数**: 1-2週間
 
 ## 🔄 更新履歴
 
+- **2025-09-05**: 型チェック修正完了、ページ関連状態移行済みを確認、進捗状況を実態に合わせて更新
 - **2025-07-30**: ドキュメント統合、進捗の実装状況反映
 - **2025-07-XX**: サイドバー関連の移行完了
-- **2025-07-XX**: SSRハイドレーション対応完了
+- **2025-07-XX**: SSRハイドレーション対応完了

+ 98 - 25
.serena/memories/apps-app-jotai-migration.md

@@ -1,4 +1,4 @@
-# Jotai 移行ガイド
+# Jotai 移行ガイド(更新版)
 
 > **📊 最新の進捗状況**: [`jotai-migration-progress.md`](jotai-migration-progress.md) を参照
 
@@ -16,18 +16,40 @@
 
 ## 2. 実装ガイド
 
-### ディレクトリ構造
+### ディレクトリ構造(実装済み)
 
 ```
 states/
 ├── ui/
-│   ├── sidebar.ts      # サイドバー状態 ✅
-│   ├── device.ts       # デバイス状態 ✅
-│   ├── editor.ts       # エディター状態 ✅(部分)
-│   ├── page.ts         # ページ関連状態(次の対象)
-│   └── modal.ts        # モーダル状態(未作成)
-└── hydrate/
-    └── sidebar.ts      # SSRハイドレーション ✅
+│   ├── sidebar/
+│   │   ├── sidebar.ts      # サイドバー状態 ✅
+│   │   ├── index.ts        # エクスポート統合 ✅
+│   │   └── hydrate.ts      # SSRハイドレーション ✅
+│   ├── editor/
+│   │   ├── index.ts        # エクスポート統合 ✅
+│   │   ├── atoms.ts        # エディターatoms ✅
+│   │   ├── hooks.ts        # エディターhooks ✅
+│   │   ├── types.ts        # 型定義 ✅
+│   │   └── utils.ts        # ユーティリティ ✅
+│   ├── device.ts           # デバイス状態 ✅
+│   └── modal.ts            # モーダル状態(未作成)
+├── page/
+│   ├── index.ts            # ページ状態エクスポート ✅
+│   ├── hooks.ts            # ページ関連hooks ✅
+│   ├── internal-atoms.ts   # 内部atoms ✅
+│   ├── hydrate.ts          # SSRハイドレーション ✅
+│   └── *.spec.tsx          # テストファイル ✅
+├── server-configurations/
+│   ├── index.ts            # サーバー設定エクスポート ✅
+│   └── server-configurations.ts  # 設定atoms ✅
+├── global/
+│   ├── index.ts            # グローバル状態エクスポート ✅
+│   ├── global.ts           # グローバルatoms ✅
+│   └── hydrate.ts          # SSRハイドレーション ✅
+├── socket-io/
+│   ├── index.ts            # Socket.IOエクスポート ✅
+│   └── socket-io.ts        # Socket.IO atoms ✅
+└── context.ts              # 共通コンテキスト ✅
 ```
 
 ### 実装パターン
@@ -55,6 +77,14 @@ const temporaryStateAtom = atom(defaultValue);
 export const useTemporaryState = () => useAtom(temporaryStateAtom);
 ```
 
+#### 読み取り専用パターン
+```typescript
+// 読み取り専用の状態
+const readOnlyAtom = atom(defaultValue);
+
+export const useReadOnlyState = () => useAtomValue(readOnlyAtom);
+```
+
 #### SSRハイドレーションパターン
 ```typescript
 // states/hydrate/feature.ts
@@ -70,8 +100,27 @@ export const useHydrateFeatureAtoms = (initialData: InitialData) => {
 - **Atom**: `{feature}Atom`
 - **Hook**: `use{Feature}`
 - **永続化対応**: `{feature}AtomExt`
+- **読み取り専用Hook**: `use{Feature}` (useAtomValue を使用)
+- **書き込み専用Hook**: `useSet{Feature}` (useSetAtom を使用)
+
+## 3. 移行時の注意点
+
+### フックの返り値の変更
+- **従来**: `const [value, setValue] = useHook();` (tuple)
+- **Jotai**: `const value = useHook();` (単一値) または `const [value, setValue] = useHook();` (tuple)
+
+### 型チェックエラーの修正
+移行時に発生するTS2488エラーは、配列分割代入の誤用が原因:
+
+```typescript
+// ❌ エラーの例
+const [value] = useAtomValueHook(); // useAtomValue を使った hook
+
+// ✅ 修正
+const value = useAtomValueHook();
+```
 
-## 3. 判断基準
+## 4. 判断基準
 
 ### Jotai移行対象
 - ✅ クライアントサイド完結のUI状態
@@ -84,8 +133,9 @@ export const useHydrateFeatureAtoms = (initialData: InitialData) => {
 - ❌ 非同期的な状態更新
 - ❌ キャッシュ機能が重要
 - ❌ リアルタイム更新が必要
+- ❌ 複雑な computed値(パフォーマンス重視)
 
-## 4. 移行の成果
+## 5. 移行の成果
 
 ### 技術的改善
 - **コードの簡潔化**: 複雑なSWRベースのカスタムフックがシンプルなatomsに
@@ -98,10 +148,11 @@ export const useHydrateFeatureAtoms = (initialData: InitialData) => {
 - **直感的なAPI**: React の `useState` に近い使用感
 - **デバッグの容易さ**: 状態の変更が追跡しやすい
 - **テストの簡素化**: モックやテストデータの管理が簡単
+- **型安全性**: TS2488エラーの原因となる誤用を防止
 
 ---
 
-## 5. 技術スタック
+## 6. 技術スタック
 
 - **Jotai**: v2.x(アトミックな状態管理)
 - **SSR対応**: `useHydrateAtoms`(公式パターン)
@@ -110,20 +161,42 @@ export const useHydrateFeatureAtoms = (initialData: InitialData) => {
 
 ---
 
-## 6. 今後の対応予定
+## 7. 現在の課題と今後の対応
 
-### 動的ルーティング時に更新が必要な値
-以下の値は Next.js の dynamic routing によるページ遷移時に値の更新が必要な可能性があります:
+### 動的ルーティング時の状態管理
+以下の値は Next.js の dynamic routing によるページ遷移時に適切に管理されています:
 
-- **currentPathname** - ページ遷移時に現在のパスが変更される
-- **isIdenticalPath** - ページごとに異なる値を持つ
-- **isForbidden** - ページのアクセス権限がページごとに異なる
-- **isNotCreatable** - ページの作成可能性がページごとに異なる
-- **csrfToken** - セキュリティ要件によってはページ遷移時に更新が必要(既に対応済み)
+- **currentPagePath** - `useCurrentPagePath()` で適切に管理済み ✅
+- **currentPageId** - `useCurrentPageId()` で適切に管理済み ✅
+- **pageNotFound** - `usePageNotFound()` で適切に管理済み ✅
+- **isNotCreatable** - `usePageNotCreatable()` で適切に管理済み ✅
 
-これらの値については、現在のSWR実装から段階的にJotaiへの移行を検討する必要があります。
-移行時には以下の点を考慮する必要があります:
+### 次のステップ
+1. **残りのUI状態の移行**: `usePageControlsX`, `useSelectedGrant`
+2. **モーダル状態の移行**: 統一的なパターンでの実装
+3. **レガシーファイルのクリーンアップ**: `stores/ui.tsx`, `stores/modal.tsx`
+
+---
+
+## 8. トラブルシューティング
+
+### よくある移行エラー
+
+#### TS2488: Type must have a '[Symbol.iterator]()' method
+```typescript
+// ❌ 問題のあるコード
+const [value] = useAtomValueHook();
+
+// ✅ 修正版
+const value = useAtomValueHook();
+```
+
+#### TS2724: no exported member
+```typescript
+// ❌ 削除されたfook
+import { useOldHook } from '~/states/somewhere';
 
-1. **ページ遷移時の同期**: `useEffect` と `useRouter` を使用した値の同期
-2. **初期値の設定**: `useHydrateAtoms` による SSR からの初期値設定
-3. **永続化の必要性**: 一時的な状態かユーザー設定として永続化が必要かの判断
+// ✅ 新しいatom-based hook
+import { useNewHook } from '~/states/somewhere';
+const value = useNewHook(); // または [value, setValue]
+```

+ 89 - 48
.serena/memories/apps-app-jotai-typecheck-handover.md

@@ -1,51 +1,92 @@
-Handover Tips for Jotai migration & TS typecheck (support/use-jotai)
+# Jotai Migration Handover (Updated - 2025-09-05)
 
-Context:
-- Goal: Eliminate TS2488 errors caused by legacy tuple-style custom hooks after migrating to Jotai single-value hooks.
-- Command per CLAUDE.md: `cd apps/app && pnpm run lint:typecheck` (ONLY this for type checking).
+## Current Status: ✅ TYPECHECK ERRORS RESOLVED
+
+**Context:**
+- Goal: Complete Jotai migration for UI state management
 - Branch: support/use-jotai
+- Command: `cd apps/app && pnpm run lint:typecheck` ✅ PASSES
+
+## ✅ COMPLETED TASKS
+
+### Type Check Issues Fixed
+- **All TS2488 errors resolved** ✅
+- Fixed tuple destructuring patterns in:
+  - `PageAccessoriesModal/ShareLink/ShareLinkForm.tsx`
+  - `PageAccessoriesModal/ShareLink/ShareLink.tsx`  
+  - `PageEditor/LinkEditModal.tsx`
+- **Current status**: `pnpm run lint:typecheck` exits 0
+
+### Major Migration Completed
+- **Sidebar state**: Complete ✅
+- **Device state**: Complete ✅
+- **Editor state**: Complete ✅
+- **Page state**: Complete ✅
+- **Server configurations**: Complete ✅
+- **Global state**: Complete ✅
+- **Socket.IO state**: Complete ✅
+- **SSR hydration**: Complete ✅
+
+## 🚧 NEXT PRIORITIES
+
+### Immediate Tasks (Priority 1)
+1. **`usePageControlsX` migration**
+   - Location: `src/stores/ui.tsx:149`
+   - Target: Create `states/ui/page.ts`
+   - Pattern: Simple number atom (no persistence needed)
+
+2. **`useSelectedGrant` migration**
+   - Location: `src/stores/ui.tsx:153`
+   - Target: Add to `states/ui/editor.ts`
+   - Pattern: Temporary state for editor
+
+### Future Tasks (Priority 2-3)
+3. **Modal states migration** (18 modals in `stores/modal.tsx`)
+4. **Other UI hooks evaluation** (determine if SWR should remain)
+5. **Legacy cleanup** (`stores/ui.tsx`, `stores/modal.tsx` removal)
+
+## 🔧 Technical Notes
+
+### Migration Pattern Recognition
+- **useAtomValue hooks**: Return single value → `const value = useHook()`
+- **useAtom hooks**: Return tuple → `const [value, setValue] = useHook()`
+- **Legacy SWR patterns**: May need data fetching evaluation
+
+### File Structure (Established)
+```
+states/
+├── ui/sidebar/     ✅ Complete
+├── ui/editor/      ✅ Complete  
+├── ui/device.ts    ✅ Complete
+├── page/           ✅ Complete
+├── server-configurations/ ✅ Complete
+├── global/         ✅ Complete
+└── socket-io/      ✅ Complete
+```
+
+## 🎯 Definition of Done
+
+**Phase 1 (Current)**: ✅ Type checking passes
+**Phase 2 (Next)**: Migrate remaining 2 UI hooks
+**Phase 3 (Future)**: Modal migration + cleanup
+
+## 🚨 Important Notes
+
+- **DO NOT** reintroduce tuple destructuring for single-value hooks
+- **Pattern**: If hook uses `useAtomValue` → single value return
+- **Pattern**: If hook uses `useAtom` → tuple return
+- Avoid modifying unrelated lint issues (console logs, img tags, any types)
+
+## Quick Commands
+```bash
+# Type check
+cd apps/app && pnpm run lint:typecheck
+
+# Find remaining legacy patterns
+grep -r "const \[.*\] = use" apps/app/src --include="*.tsx" --include="*.ts"
+```
 
-Current Status (at interruption):
-- All identified tuple destructuring patterns converted to single-value usage (e.g. `const value = useXxx();`).
-- Last edited file: `src/client/components/Sidebar/SidebarNav/SecondaryItems.tsx` (removed `[isAdmin]`, `[growiCloudUri]`, `[isGuestUser]`).
-- A rerun of typecheck after this final change was attempted but the command execution was cancelled, so confirmation of 0 remaining TS2488 errors is still pending.
-- Previously remaining single TS error (TS2488) was always of the same form: `const [something] = useHook();`.
-- Other non-blocking lint issues still present (console logs in `PageView.tsx`, `<img>` tags without `alt` or Next.js `<Image>` replacement, `any` types). These do NOT affect `vue-tsc` typecheck success but will appear when running full lint tasks.
-
-Likely Next Step:
-1. Run: `cd apps/app && pnpm run lint:typecheck`.
-2. If TS2488 still appears, fix by:
-   - Change `const [name] = useSomeHook();` to `const name = useSomeHook();`.
-   - Remove unused variable names if no longer needed.
-3. Repeat until typecheck passes with no errors.
-
-Useful Grep (do manually in next session):
-- Search residual tuple patterns: `grep -R "const \[" apps/app/src/client apps/app/src/components | grep use`.
-
-Patterns Already Normalized:
-- `useCurrentUser`, `useCurrentPageData`, `useCurrentPageId`, `useCurrentPagePath`, `useLatestRevision`, `usePageNotFound`, `useIsEditable`, all `useIsGuestUser|ReadOnlyUser|SharedUser|Admin|DefaultLogo`, server config atoms (showPageLimitation*, isMailerSetup, etc.), remote revision hooks.
-
-Remote Revision Migration:
-- All former imports from `~/stores/remote-latest-page` replaced by hooks in `~/states/page` (e.g. `useSetRemoteLatestPageData`, `useRemoteRevisionId`, etc.). If any stragglers appear, replace path and remove tuple destructuring.
-
-Caveats:
-- Do NOT reintroduce tuple destructuring; hooks now return single values.
-- Avoid modifying console logs, `<img>` tags, or lint-only issues unless explicitly tasked (keep scope focused so auto-approve remains stable).
-
-Definition of Done:
-- `pnpm run lint:typecheck` exits 0 with no TS errors.
-
-If Additional Errors Appear:
-- TS2307 (old remote-latest-page path): update import to `~/states/page` and adjust variable names to direct values.
-- TS2724/TS2305 (missing exports for removed legacy hooks): replace usage with the new atom-based hook listed in `/states/*` directories.
-
-After Success (Optional Future Tasks):
-- Remove debug `console.log` in `PageView.tsx`.
-- Replace `<img>` with Next `<Image>` and add `alt` attributes where flagged.
-- Tighten `any` usages in files like `ProfileImageSettings.tsx`, `CustomizeLogoSetting.tsx`.
-
-Quick Checklist For Next Session:
-[ ] Run typecheck command
-[ ] Fix any residual TS2488
-[ ] Re-run until clean
-[ ] Commit with message: "chore(app): remove remaining tuple destructuring for jotai migration"
+---
+**Status**: Ready for next migration phase
+**Last Updated**: 2025-09-05
+**Next Session Focus**: usePageControlsX migration