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
+20
View File
@@ -158,6 +158,26 @@ SSE でストリーミング応答を返す。
---
### POST /api/notes/reorder
タブのドラッグ&ドロップによる並べ替えを反映する。`order` には**全ページID**をドラッグ後の
新しい順序で渡す(サーバー側では計算しない。フロントが `store.pages` から算出する)。
`page_id` のページには先に `section` を設定してから、`order` の順に `position` を振り直す。
別セクションのタブの前後にドロップした場合は、そのセクションへの移動も兼ねる。
`order` が現在の全ページIDの集合と一致しない場合は `400` を返す。
**リクエスト**
```json
{ "page_id": 3, "section": "生活", "order": [1, 3, 2, 4] }
```
**レスポンス**
```json
{ "reordered": 4 }
```
---
### DELETE /api/notes/{page_id}
ページを削除。`204 No Content` を返す。
+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`)
+58
View File
@@ -0,0 +1,58 @@
# 共有ノートの使い方
ユーザーとAIが同じノートを一緒に編集できる機能。ページをタブで切り替え、関連するページ同士は
セクションでグループ化できる。実装の詳細は `docs/architecture.md` の「共有ノート」節、
API 仕様は `docs/api.md` の「共有ノート」節を参照。
## 開き方
画面右上ヘッダーの **「ノート」** ボタンをクリックすると、右側にノートパネルが開く。
もう一度クリックすると閉じる。
## ページの操作
| 操作 | 方法 |
|---|---|
| ページを開く | タブをクリック |
| ページを新規作成 | タブ列右端の **+** をクリック(末尾に「新しいページ」が追加される) |
| タイトルを変更 | タブを**ダブルクリック**すると入力欄になるので書き換えて Enter(または欄外をクリック) |
| ページを削除 | タブ内の **×** をクリック(確認ダイアログあり) |
| 本文を編集 | ページを開いた状態で下の編集エリアに直接入力 |
本文は入力を止めてから少し待つと自動保存される。保存待ちの間はタブに **●**(未保存マーク)が付く。
ページが1つも無い場合は「+ 最初のページを作成」から始められる。
## セクションでまとめる
複数のページを1つのグループとしてタブ上にまとめられる。
| 操作 | 方法 |
|---|---|
| ページをセクションに入れる | タブにマウスを乗せると出てくる **🏷** をクリックし、セクション名を入力 |
| セクション名を変更する | セクションのラベル(タブ群の左上に表示される名前)をクリックし、新しい名前を入力 |
| セクションを解除する | 🏷 またはセクションラベルをクリックした際、名前を**空欄**にして確定 |
同じセクションに入れたページは、タブ列上で必ず隣り合って表示される
(新しくセクションに追加したページは、そのセクションの末尾に自動的に移動する)。
セクション名を変更すると、そのグループに属する全ページのラベルが一括で変わる。
## タブをドラッグで動かす
タブは**ドラッグ&ドロップ**でも操作できる(🏷 やセクションラベルのクリックと同等の結果になる)。
| 操作 | 方法 |
|---|---|
| 同じグループ内で順番を変える | タブを掴んで、移動先のタブの左半分/右半分にドロップ(左=そのタブの前、右=後ろに入る) |
| 別のセクションへ移動する | 移動先のセクション内のタブにドロップ(そのタブと同じセクションに入る) |
| セクションから外す | 未分類のタブにドロップ、またはタブ列の一番右(+ボタンの手前の細い枠)にドロップ |
ドラッグ中はドロップ位置に青い線が表示される。タイトル編集中(ダブルクリックで入力欄になっている間)のタブはドラッグできない。
## AIとの連携
- 全ページの**タイトル一覧**は、会話のたびに自動でAIに渡される(セクションがあれば見出し付きで)。
ただし本文はここには含まれない。
- AIは `read_note` ツールでページ本文を読み、`write_note` ツールで追記・置き換え・新規ページ作成ができる。
「ノートに書いておいて」「〇〇について記録して」のように頼むと、AIが該当ページを判断して書き込む。
- AIがノートを書き換えると、開いているノートパネルは自動的に最新の内容へ更新される。
- 自分が編集中(未保存)のページは、AIの更新で上書きされない。