Add drag-and-drop reordering for note tabs, and a user-facing guide

Tabs can now be dragged to reorder within a group and to move between
sections in one gesture: dropping on a tab's left/right half inserts
before/after it and adopts that tab's section, while a dedicated zone
past the last group ungroups and appends at the end. A blue indicator
line shows the drop position while dragging.

core/notes.reorder() takes the full new page-id order computed
client-side (NotePanel.vue has the reactive list already) rather than
recomputing positions server-side, validates it against the current
page-id set, sets the moved page's section, then renumbers position.
POST /api/notes/reorder exposes it.

Also adds docs/notes-guide.md, an end-user walkthrough of the shared
notes panel (pages, sections, drag-and-drop, AI interaction) — the
existing docs were all developer-facing specs with no operating
instructions for the feature itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 07:27:38 +09:00
co-authored by Claude Opus 5
parent 1c21fc3406
commit 8b2231ea97
8 changed files with 245 additions and 3 deletions
+3 -1
View File
@@ -129,12 +129,14 @@ LLM に渡すコンテキストは `memory_kb/memory.py` の `get_context_messag
### 共有ノート(`core/notes.py` / `api/notes.py`)
ユーザーと AI が共同編集するノート。`note_pages` の 1 行が UI の 1 タブに対応する。
利用者向けの操作方法は `docs/notes-guide.md` を参照。
- `get_notes_context()` が**タイトル一覧のみ**をシステムメッセージとして生成し、`get_context_messages()` が会話コンテキストに差し込む(本文は含めない)。セクションがあれば `## セクション名` の見出しでグループ化して提示する
- 本文の読み書きはツール経由: `read_note`(本文取得)/ `write_note`(追記・置換・新規作成)
- `llm.resolve_tool_calls()` が `web_search` と同じループでこれらを解決する。ノート系ツールは `db` を渡したときのみモデルに提示される
- REST(`/api/notes`)はフロントのノートパネル用。GET 一覧 / POST 作成 / PATCH 更新 / DELETE 削除 / `POST /api/notes/sections/rename`(セクション名の一括変更)
- REST(`/api/notes`)はフロントのノートパネル用。GET 一覧 / POST 作成 / PATCH 更新 / DELETE 削除 / `POST /api/notes/sections/rename`(セクション名の一括変更)/ `POST /api/notes/reorder`(ドラッグ&ドロップの並べ替え)
- **セクションによるグルーピング**: `note_pages.section` に名前を持たせ、同じセクションのページは常に `position` 上で連続させる。`notes.set_section()` がページのセクションを変更するたびに全ページを再採番し、同じセクションの末尾に挿入し直す(隣接=同一グループという前提をタブ描画側・システムプロンプト側の両方が使っている)。`notes.rename_section()` は既に連続しているページ群のラベルだけを一括で書き換える
- **ドラッグ&ドロップの並べ替え**: `notes.reorder()` は `set_section()` と違い、位置の計算をサーバー側ではなくフロント(`NotePanel.vue`)に任せる。フロントがドラッグ後の全ページIDの順序を計算し、`{ page_id, section, order }` として一括送信、サーバーは検証(`order` が現在の全ページID集合と一致するか)した上でそのまま `position` に反映する。ドロップ先タブの `section` を渡すことで、並べ替えと同時にセクション間移動も1リクエストで完結する
- 既存 DB への追加カラムは Alembic 等の仕組みを使っておらず、`db/database.py` の `_add_missing_columns()` が起動時に `PRAGMA table_info` を見て `ALTER TABLE ... ADD COLUMN` を素朴に実行する(SQLite 専用の簡易マイグレーション)
### SSE ストリーミング(`api/chat.py`)