← ガイダンス一覧へ戻る

8保存:Notionへの書き込み一式

Zettelkasten Inbox / ブロック詳細

画面上の判断をNotionの書き換えに変える唯一の場所。16工程のうち実際に書くのは4つだけで、残りは「書いてよいか」と「狙いどおりに書けたか」の確認に費やされている。

抽象度 Lv.4(技術用語+システム上のやりとりまで/製品名・ライブラリ名は書かない)

1. 概要

このアプリの心臓部。「Tagを選び、ABC Noteを選び、自分の言葉でコメントを書いた」という 画面上の判断を、Notionの実際の書き換えに変換するただ1つの場所。

やることは大きく4つ。 (1) 送られてきた内容が形として正しいかを16項目で確かめる。 (2) Notionの現在の状態と噛み合うかを確かめる。 (3) ABC Noteの本文「その他」へ、見出し+元ノートへのリンク+コメント+画像を転記する。 (4) 元のLiterature Noteの題名・コメント・タグ・ABC関連を書き換える。

そして最後に、書いた結果をもう一度読み直して、狙いどおりになっているかを照合する。 このブロックだけで、Notionへの往復が最低でも6回、多いと数十回になる。

2. 位置づけ

7. 画像の添付 → 8. 保存:Notionへの書き込み一式 → 2番の控えを捨てて次のノートへ

3. 処理内容(Lv.4)

4. なぜこの位置にあるか(設計意図)

すべての判断が揃うまで、1バイトも書かない。Tagを選んだ時点でも、 ABC Noteを選んだ時点でも、Notionには何も書かれない。 「保存」を押した瞬間に、すべての書き込みがここで一度に起きる。 途中で気が変わっても何も残らない、という単純さと引き換えに、 このブロックが背負う責任が非常に重くなっている。

7番を分けた理由がここで効く。画像を先に預けてあるので、 このブロックが受け取るのは短い番号と指紋だけ。 10MBの送信と、数十回のNotion往復が、同じ1回の要求に同居しない。

検査を3層に分けている。 (1) 形の検査(入口)=送られてきた内容が構造として正しいか。 (2) 状態の検査(Notionを読んだあと)=いまのNotionと噛み合うか。 (3) 結果の照合(書いたあと)=狙いどおりになったか。 この3層が、このブロックの骨格そのもの。

2種類の鍵を使い分ける理由。ノート単位の鍵は「同じノートを二重に処理しない」ため。 ABC Note単位の鍵は「同じ知識ページの本文を2方向から同時に書き換えない」ため。 別々のノートから同じABC Noteへ同時に転記することは普通に起きるので、 ノート単位の鍵だけでは足りない。

5. 詳細プロセス分解

工程主体やりとりの内容方向
8-1ブラウザ → 保存APIID群・題名・コメント・画像の番号と指紋
8-2保存API(内部)16項目の形の検査
8-3保存API(内部)そのノート専用の待ち行列への参加
8-4保存API → Notion預かり画像の状態・形式・大きさの再確認
8-5保存API → Notion対象ノートの取得と、現在の関連の完全な把握
8-6保存API(内部)処理済み/開いてから変更済み/関連の削除の判定
8-7保存API → Notion選んだTagとABC Noteの素性の再確認
8-8保存API → Notion(新規のとき)ABC Noteを本文ごと作成
8-9保存API → 転記処理ABC Note1件ずつ、鍵を取ってから依頼
8-10転記処理 → Notion本文を全部読み、「その他」の位置を特定
8-11転記処理 → Notion既存なら書き換え、無ければ追記
8-12保存API → Notion元ノートへ「マイコメント添付」として画像を貼る
8-13保存API → Notion題名・コメント・タグ・ABC関連の4項目を更新
8-14保存API → Notion(失敗時のみ)作ったABC Noteをゴミ箱へ
8-15保存API → Notion書いた結果の読み直しと照合
8-16保存API → ブラウザ作成したABCの情報と、転記の結果

各行を文章にすると

8-1 保存ボタン(またはCtrl+Enter)を押すと、画面が持っている情報が一度に送られる。 画像は入っていない。番号と指紋だけ。

技術的には POST /api/processapplication/json。項目は、ノートID、TagのID配列、ABCのID配列、 新規ABCの題名と親TagのID、新しい題名、コメント、 画像の {uploadId, digest} の配列、 そして修正モードのときだけ reviewExisting と「開いた時点のID配列」2つ。 画面側でも保存できる条件を判定しているが (Tagが1つ以上、ABCが1つ以上か新規題名あり、題名とコメントが空でない、画像が全部添付済み)、 サーバーはそれを一切信用せず全部やり直す。

8-2 まず、送られてきた内容の「形」だけを16項目にわたって確かめる。 Notionにはまだ触れない。

技術的には ID群は 32桁の16進か 8-4-4-4-12 に一致するかを見て、 ハイフンの位置を正規化してから重複を除き、10件を超えたら不正。 画像は最大5件、番号がIDの形、指紋が64桁の16進であることを見て、 同じ指紋のものは1つにまとめる(同じ画像を2回選んでも1枚になる)。 とくに重要な検査が4つ: (1) 既存ABCの選択と新規作成の同時指定は禁止(どちらか一方でなければならない)。 (2) 新規作成の親Tagは、選択中のTagに含まれていなければならない。 (3) 修正モードなら「開いた時点」の情報が必ず添えられていること、 逆に通常モードでそれが添えられていたら不正(どちらも 400)。 (4) 題名500文字以内、コメント12,000文字以内。 (3) の「余計なものが付いていたら断る」という検査は珍しく、 画面の状態とサーバーの理解がずれていないかを、両方向から確かめている。

8-3 形が通ったら、そのノート専用の順番待ちの列に並ぶ。 同じノートに対する保存や削除が既に走っていれば、終わるまで待つ。

技術的には ノートのIDを鍵にした約束の連鎖で作った待ち行列。 新しく来た処理は「前の処理が終わったら自分が始まる」という形でつながれ、 自分が終わったら次を解放する。前の処理が失敗しても、 その失敗は握りつぶして次を必ず進める(1つの失敗で列が止まらないように)。 これはサーバーのメモリ上の仕組みなので、実行環境が2つ動いていれば効かない。

8-4 画像の番号を1つずつNotionに問い合わせ直して、本当に預かられているかを確かめる。 画面から送られてきた番号を鵜呑みにしない。

技術的には GET /v1/file_uploads/{番号}1枚ずつ順番に。状態が uploaded で、 形式が image/ で始まり、大きさが10MB以下であることを確認。 1つでも外れたら 400 +「添付画像を確認できませんでした。」。 7番で確認済みのことを、なぜもう一度確認するのか―― 画面を通さず直接このAPIを叩かれた場合、番号は偽れるから。 ここで取り直したファイル名が、実際に本文へ書かれるキャプションになる。

8-5 対象のノートをNotionから取り直し、いま何のTagと何のABC Noteに 結び付いているかを完全に把握する。

技術的には ページを取得して 本当にLiterature DBの下にあるかを確認(違えば 400)。 続いて関連づけをタグ側とABC側で同時に取り切る。 ページ取得の応答には関連が最大25件しか入らないので、 「続きがある」印が立っていれば専用の問い合わせで100件ずつ全部たどる。 ここで「いまの真実」を掴むのが、次の判定の土台になる。

8-6 いまのNotionの状態が、画面の前提と噛み合うかを判定する。 噛み合わなければ、書かずに断る。

技術的には モードで分岐する。 通常モード:タグ欄かABC欄が1つでも埋まっていたら 409 +「このノートはNotion側ですでに処理されています。」。 受信箱に出る条件が「両方空」なので、埋まっている=別経路で処理済み、という判断。 修正モード:2段階で見る。 (1) 開いた時点のTag・ABCの集合と、現在の集合が完全一致するか。 違えば 409 +「Notion側で更新されています。全体マップから開き直してください。」 ――これが楽観的排他制御(先に鍵を掛けず、書く直前に「変わっていないか」を確かめる方式)。 (2) 現在のTag・ABCが、送られてきた選択にすべて含まれるか。 1つでも欠けていたら 409 +「現在のTagとABC Noteを維持してください。候補の追加はできます。」 ――修正モードでは「増やす」ことはできても「減らす」ことはできないという制約。 知識の削除という取り返しのつかない操作を、この画面からはさせない設計。

8-7 選んだTagとABC Noteが、本当にそのDBのもので、 親子関係が正しいかを確かめる。

技術的には TagのIDを1件ずつ順番に取得し、 親がTag DBかを確認。1つでも違えば 400。 ABC Noteも1件ずつ取得し、親がABC DBであること親Tagがちょうど1つで、それが選択中のTagに含まれることを確認。 違えば 409 +「選んだTag配下ではないABC Noteが含まれています。」。 これは6番の絞り込みと同じ条件を、書く直前にもう一度確かめている。 画面の一覧が古い可能性があるため。 なお取得は直列なので、Tag3件+ABC2件を選べばここだけで5往復かかる。

8-8 「新しいABC Noteを作る」を選んでいた場合、ここでページを1つ作る。 中身は空ではなく、最初から目次と「その他」の見出しと、いま書いたコメントが入っている。

技術的には POST /v1/pages に、 親としてABC DBを指定し、🧠の絵文字、題名、親Tagの関連、 そして本文(children)を一緒に送る。本文の中身は3つ。 (1) 目次ブロック(今後見出しが増えたときのため)、 (2) 大見出し「その他」(3) 最初の記入=中見出しに新しい題名、段落に 元ノートへの「メンション」(Notion上でページを指す埋め込みリンク)+改行+コメント、 そして画像。 ページ作成と本文の書き込みを1回の要求にまとめているので、 「ページはできたが中身が空」という中途半端な状態が生まれない。

8-9 既存のABC Noteへ転記する場合、1件ずつ、そのページ専用の鍵を取ってから処理する。

技術的には ABC NoteのIDを鍵にした、8-3 とは別の待ち行列。 違うLiterature Noteから同じABC Noteへ同時に転記しようとしても、 本文の読み取りと追記が交錯しない。 複数のABC Noteを選んでいる場合は、1件ずつ順番に処理する(同時にはしない)。 なお 8-8 で作ったばかりのABC Noteは、すでに中身が入っているのでここは飛ばす。

8-10 転記先のページの本文を、先頭から最後まで全部読む。 そして「その他」という見出しがどこにあるかを探す。

技術的には 100件ずつ、続きが無くなるまで取り切る。 「その他」の判定は、見出しブロックの文字を 全角半角をそろえ、空白を全部消し、小文字にした形で比較する。 見出しなら大中小どのレベルでもよい。 2つ以上見つかったら 409 で止まり、 「Notion側で1つに整理してください。」と人に投げる―― どちらに書くべきか機械には決められないため。 見つかったら、次に同じレベル以上の見出しが現れるところまでが「その他」の範囲。

8-11 「その他」の中に、このノートからの記入がすでにあるかを調べる。 あれば書き換え、無ければ足す。

技術的には ここがこのブロックでいちばん凝っている。 (1) 節の中の探索:各ブロックのJSONを丸ごと文字列にして、 対象ノートのIDが現れるかを見る(メンションのリンクにIDが入っているため)。 見つかって、その1つ前が中見出しで自身が段落なら、 その2つを書き換える(新しい題名とコメントで上書き)。 これで同じノートを何度保存しても、記入が増殖しない(2) 画像の差分追加:7番で作った指紋から zi_attachment=◯◯◯◯◯◯◯◯-(64桁) という目印を組み立て、 それが本文のどこかに現れるかを探す。前半8桁はノートIDから作った短い値で、 同じ画像を別のノートから貼ったときに別物として扱うためのもの。 この目印は、画像のキャプションのリンク先URLの中に埋め込まれている―― Notionのブロックに「印」を持たせる場所が無いための工夫。 まだ無い画像だけを、その記入の末尾に追加する。 (3) ページ全体の探索:「その他」の中に無かった場合、 ページ全体を入れ子の奥まで再帰的にたどって、 そのノートのIDが本文のどこかに出てこないかを調べる(最大5,000ブロック、見つかったら即打ち切り)。 見つかれば「すでにある」として何もしない。 「その他」以外の場所へ手で移動された記入を、二重に書かないための保険。 (4) どこにも無ければ、「その他」の末尾に追記する。「その他」自体が無ければ、 見出しごとページの末尾に作る。 結果は updatedalready_presentappendedcreated_section のいずれかで返る。

8-12 元のLiterature Noteのほうにも、同じ画像を貼る。 こちらは「マイコメント添付」という見出しの下。

技術的には 8-10・8-11 とほぼ同じ手順を、 見出し名だけ変えて元ノートに対して行う。中見出し「マイコメント添付」が 2つあれば 409、無ければ作る。指紋の目印で、すでにある画像は飛ばす。 つまり同じ画像が、元ノートと選んだABC Noteすべてに複製される。 Notionは同じ預かり番号から複数のブロックを作れるので、 実体が何倍にもなるわけではないが、表示上はそれぞれの場所に現れる。

8-13 最後に、元のLiterature Noteの4つの項目を一度に書き換える。 これで受信箱から消える。

技術的には PATCH /v1/pages/{id} 1回で、 題名・コメント・タグの関連・ABCの関連を同時に更新する。 4回に分けず1回にまとめているので、 「タグだけ付いてABCが付いていない」という中途半端な状態が生まれにくい。 題名とコメントは1,900文字ごとに分割して送る―― Notionが1つの文字列部品に入れられる上限が2,000文字なので、 12,000文字のコメントは7つの部品に分かれて1つの段落になる。 この更新が終わった瞬間に、このノートは「未処理」の条件(両方空)から外れる。

8-14 8-9 から 8-13 のどこかで失敗したら、 このとき作ったばかりのABC Noteだけをゴミ箱へ移す。

技術的には PATCHin_trash: true。 ゴミ箱への移動自体が失敗しても、それは黙って無視して元の失敗を優先して報告する (後始末の失敗で、本当の原因が隠れないように)。 取り消されるのはこの1ページだけで、 既存のABC Noteへ書いた転記や、貼った画像は元に戻らない。 「新しく作ったものは無かったことにできるが、既存のものへの書き足しは戻せない」という線引き。

8-15 書き終わったあと、もう一度そのページを読み直して、 狙いどおりになっているかを1つずつ照合する。

技術的には 照合するのは6つ。 題名が一致するか、コメントが一致するか、タグの件数が一致するか、 ABCの件数が一致するか、送ったIDが全部含まれているか、 そして新規作成した場合は親Tagがちょうど1つで指定どおりか、 そのABC Noteから元ノートへの引用関係ができているか。 1つでも外れたら 502 +「Notionへの保存結果を確認できませんでした。」。 ここで 502 が返っても、書き込みは取り消されない。 「保存できたつもりで実は違った」を利用者に知らせるための照合であって、 元に戻す仕組みではない。

8-16 成功したら、受信箱と全体マップの控えを捨て、結果を返す。 画面は次のノートへ自動で進む。

技術的には 200 + 作成したABC Noteの情報、最終的なABCのID一覧、 ABC1件ごとの転記の結果(新規節を作った/追記した/書き換えた/すでにあった)。 画面側は再読み込みをせず、手元のデータを自分で更新する―― 処理したノートを一覧から外し、Tagの使用回数を1増やし、 新規ABCがあれば一覧の先頭に足す。そして次のノートを選ぶ。 修正モードのときだけは、全体マップの画面へ戻る。 これがこのアプリの体感速度を決めている―― 1件終わるたびに 2番の重い読み込みをやり直していたら、連続処理は成立しない。

ワークフロー図

← 図は横にスクロールできます

ブラウザ
保存API
転記処理
Notion API
8-1 POST /api/process(画像は番号だけ)
8-2 16項目の形の検査(外れたら400)
8-3 このノート専用の待ち行列に並ぶ
8-4 預かり画像の状態を1枚ずつ確認
8-5 対象ノートと現在の関連を取得
8-6 処理済み/変更済みの判定(409)
8-7 選んだTagとABCの素性を確認
8-8 (新規のとき)ABC Noteを本文ごと作成
8-9 転記の依頼(ABC1件ずつ・鍵つき)
8-10 本文を全部読み、その他の位置を探す
8-11 既存なら書き換え、無ければ追記
8-12 元ノートへ画像を貼る
8-13 題名・コメント・タグ・ABCを更新
8-14 (失敗時)作ったABC Noteをゴミ箱へ
8-15 書いた結果を読み直して照合
8-16 200 + 作成したABCと転記の結果

6. この分解から見えること

  • 16工程のうち、書き込みは4つだけ(8-8・8-11・8-12・8-13)。 残りは検査と読み取りと後始末。 このブロックの本体は「書くこと」ではなく「書いてよいかを確かめること」。
  • 二重書き込み対策が3段構え。 (1) ノート単位の待ち行列、(2) 記入の書き換え(増殖させない)、 (3) ページ全体の再帰探索(移動された記入も見つける)。 同じ内容が2つ並ぶという壊れ方を、いちばん強く警戒している。
  • 画像の目印を「キャプションのリンク先URL」に隠しているのが、この設計の白眉であり弱点でもある。 Notionに印を置く場所が無いための工夫だが、 利用者がNotion側でキャプションを消すと、目印も消えて二重に貼られる。 しかもそのURLはアプリ自身のドメインを指しているので、 公開URLが変わると過去の目印と合わなくなる。
  • 照合はするが、元に戻さない。8-15 で 502 が返ったとき、 Notionには書きかけの状態が残る。自動で直す処理はどこにも無い。 Notionを正本と決めた以上、直すのはNotion側で人が、という割り切りだが、 利用者には「何がどこまで書かれたか」が伝わらない。
  • 取り消しの範囲が非対称。新規作成したABC Noteは取り消されるのに、 既存ABC Noteへの転記と画像の貼り付けは残る。 「新しく作ったもの=誰も知らないから消してよい」「既存に足したもの=消すほうが危険」 という判断で、これは妥当だが、結果として中途半端な状態は必ず残りうる。
  • 修正モードは「増やせるが減らせない」。全体マップから開いたときは、 既存のTagとABCを外すことができない。 知識のつながりを切る操作は、この画面からは絶対にできないようになっている。
  • Notionへの往復が多い。Tag3件・ABC2件・画像2枚を選んだ場合、 8-4 で2回、8-5 で1〜3回、8-7 で5回、8-9〜8-11 で各ABC 2〜3回、 8-12 で2回、8-13 で1回、8-15 で1〜2回――20往復前後になる。 1件の保存に数秒かかるのは、この構造による。

7. 失敗時の挙動

  • 形の検査で落ちた(8-2):400 + 何が足りないかの日本語。 Notionへは1度も行かない。何も残らない。
  • すでに処理済み(8-6・通常モード):409 + 「画面を更新してください。」。何も書かない。
  • 開いてから変わっていた(8-6・修正モード):409 + 「全体マップから開き直してください。」。何も書かない。
  • 「その他」が2つある(8-10):409 + 「Notion側で1つに整理してください。」。 ただし、複数のABC Noteを選んでいて2件目でこれが起きた場合、 1件目への転記はすでに済んでいる。
  • 転記の途中で通信が失敗(8-9〜8-13): 新規作成したABC Noteはゴミ箱へ移るが、 既存ABC Noteへの転記・元ノートへの画像・(間に合っていれば)プロパティ更新は残る。 利用者には元の失敗のメッセージだけが出る。
  • 照合に失敗(8-15):502 +「Notion側を確認してください。」。 書き込みはすべて残ったまま。受信箱の控えも捨てられないので、 画面を再読み込みすると処理済みのはずのノートがまだ残って見えることがある
  • どこまで進んでから失敗すると何が残るかの整理: 8-7 まで=何も残らない。8-8 直後=ABC Noteが1つできるが取り消される。 8-11 の途中=ABC Noteの本文に記入が残る。8-13 の直前= ABC Note側には転記済みだが、元ノートは未処理のまま (=受信箱に残り続け、もう一度保存すると 8-11 の重複検査が働いて二重にはならない)。

8. 未確認事項

  • 照合に失敗して 502 になった書きかけの状態を、誰がいつ直すのか(自動で直す仕掛けは無い)
  • アプリの公開URLが変わったとき、過去に埋め込んだ画像の目印がどうなるか(目印にドメインが含まれる)
  • 複数の実行環境が同時に動いた場合、2種類の鍵が跨いで効くか(Lv.5相当の確認が必要)
  • 8-11 の再帰探索の上限5,000ブロックに、実際に届いたことがあるか
  • 元ノートとABC Noteに同じ画像を複製することで、Notion側の保存量がどう増えるか
  • 複数ABC Noteの転記を直列にしているのが、Notionの回数制限を避けるためか、本文の整合のためか

※ 2026年8月14〜15日時点の zettelkasten-inbox のプログラムを読んで作成しました。過去の設計資料は参照していません。

※ 番号は全体図・この解説・シーケンス図で共通です。工程番号は「ブロック番号-連番」で書いています。

全体図へ戻る / ブロック目次へ

akuramochi1.com — personal tools for learning and thinking.