LINE・Notion・Cloud Run で作る小規模文書検索システムの設計

娘が4月から幼稚園に通い始めました。🌸
園からは予定表、給食献立、同意書、感染症対応などのプリントが紙で届くのですが、後から知りたくなるのは文書そのものではなく、「明日の持ち物は何か」「この病気にかかったらどう対応すべきか」といった断片的な情報です。

紙のまま管理すると、必要な情報にたどり着くのが手間になると感じ、自然言語で検索する形にできないかを考えていました。

そこで、LINE を入口にして、Notion に整理した情報を Cloud Run 上のアプリケーション経由で検索できる、小規模な文書検索システムを試作しました。

こういった類の課題解決をするための商用サービスはいくつかありますが、普段の私の業務ではあまり触れない領域でもあり、個人的な興味から実際に手を動かして構成を考えてみました。

今回は、LINE・Notion・Cloud Run を使って小規模な文書検索システムを組むにあたって考えたことと、最終的に採用した構成についてまとめます。

構成としては、LINE から質問を受け付け、バックエンドで文書を検索し、必要に応じて LLM で回答を生成する仕組みです。

  • ユーザーインターフェース: LINE 公式アカウント
  • アプリケーション: FastAPI(Python)
  • 実行環境: Cloud Run
  • インフラ管理: Terraform
  • データ管理: Notion を編集 UI にし、同期済み JSON を検索
  • 回答方式: ルールベース応答 + 軽量な文書検索 + 必要時のみ LLM

挨拶や定型案内、資料に存在しない質問の打ち切りはアプリケーション側で処理し、LLM 呼び出しを必要な場面に限定しています。

LINEグループチャットでBotが応答しているデモ

前提と制約

最初に思いつくのは、紙を OCR(光学文字認識) で文字を抽出して、どこかにためておいて検索する、という構成です。

ただ、少し考えるとすぐにいくつか問題がありました。

  • 文書は紙で届くため、最初の入力が非構造
  • 新しい文書が継続的に追加される
  • 利用者は専用アプリをインストールしたくない
  • 小規模運用なので、できるだけ無料または低コストにしたい
  • OCR の品質は文書レイアウトや撮影品質にかなり左右される

この時点で、「完全自動で OCR で文字を抽出して構造化し、常に正確に答える」構成は現実的ではなさそうだと感じました。特に表組みや複数カラムのプリントは、OCR 単体だと順序が崩れやすく、重要な情報が欠落しやすいためです。

また、入力元が紙である以上、モデルや検索基盤を豪華にしても、元データが崩れていれば精度は上がりません。今回の規模だと、検索基盤を重くするより、文書をどう整えて保持するかの方が重要そうでした。

全体構成

最終的には、次のような役割分担にしました。

  1. 紙文書を画像として取り込む
  2. 必要に応じて OCR テキストを補助情報として用意する
  3. 元画像を確認しながら Markdown に整形する
  4. 整形結果を Notion に蓄積する
  5. Notion から同期した保存済み JSON を対象に検索する
  6. 検索結果が十分にある場合のみ LLM に要約させる

検索精度を左右するのは、モデルの性能よりも「どの文書をどういう形で持っているか」の方が支配的です。きれいなテキストが蓄積されていれば、小規模な検索でもかなり実用になります。

全体構成図

※チャット上で /sync というコマンドを入力すると Notion の内容が同期されるようにしています。

インターフェースとしての LINE

利用頻度は高くなくても、使いたい瞬間にすぐ開けることが重要でした。そのため、専用フロントエンドを作るより、既存のメッセージングチャネルを UI として使う方が合理的だと考えました。

LINE を使うことで、以下の利点がありました。

  • 利用者に新しいアプリのインストールを求めない
  • 通知・履歴・入力 UI をそのまま利用できる
  • 少人数運用では専用フロントエンドの保守コストを避けられる

その代わり、バックエンド側では LINE の webhook を公開で受ける必要があります。今回は、Cloud Run 自体は公開しつつ、LINE の署名検証と許可ユーザー ID の制限で利用者を絞る形にしました。

データ管理の置き方

入力元が紙文書であり、文書ごとにフォーマットが違う状況では、最初から厳密なスキーマを決めるより、まず柔らかく保持できる形の方が扱いやすいと考えました。

当初は Markdown ファイルをそのままアプリ側で読む構成も考えていました。人間にも読みやすく、差分も追いやすいので、最初に試す形としては自然です。

ただ、この形だと Cloud Run 上ではファイル更新のたびに再デプロイが必要になります。

そこで、最終的には編集 UI は Notion、検索対象は同期済み JSON という分担にしました。これにより次の利点がありました。

  • 利用者が Notion 上で直接更新できる
  • Cloud Run への再デプロイなしでデータ更新できる
  • 検索時は保存済みデータだけを見るのでレイテンシが安定する
  • Notion 障害時でも最後の同期結果で回答できる

この判断により、「まず取り込む」「あとで少しずつ整える」という運用のしやすさを保ったまま、更新フローも軽くできました。

取り込みフロー

OCR 単体では、次のような問題が出ます。

  • 行や列の順序が崩れる
  • 見出しと本文の対応が壊れる
  • 一部の文字が落ちる
  • レイアウト情報が失われる

この部分は検索システム本体とは少し性質が違うので、取り込み用のワークフローとして切り分けて考えることにしました。

そのため、最終的には「半自動ワークフロー」に寄せました。

ここでは自動化の度合いを上げることよりも、誤変換に気づけることと、あとから運用者が見返したときに状態を追えることを優先しています。

  • 未処理の画像を作業用の置き場に集める
  • 画像内容を確認する
  • 人間に分かる名前へ整理する
  • 元資料を保管用の置き場に退避する
  • 転記用の Markdown を生成する
  • Notion へ転記する

完全自動化は見栄えがよい一方で、誤変換に気づきにくく、運用者以外が状況を追いにくいことがあります。今回は、「未処理」「処理済み原本」「Notion 上の正本」「検索用データ」の状態を分けて扱うことで、運用の見通しがかなり良くなりました。

取り込みワークフロー図

LLM の役割

すべての質問を LLM に投げる構成は、コスト・レイテンシ・失敗時挙動の面で扱いづらいことが分かりました。特に無料枠ではレート制限にすぐ達し、雑談や資料外質問で API を消費するのは効率が悪いです。

そのため、回答経路をいくつかに分けています。

  • 挨拶: 固定応答
  • お礼: 固定応答
  • 「何ができるの?」: データからローカル生成
  • 資料にない質問: ローカルで打ち切り
  • 資料に根拠がある質問: 検索結果をもとに回答生成

この分岐を入れたことで、LLM は「なんでも答えるエンジン」ではなく、「検索で根拠が取れたときに自然な日本語へ整える役割」に近づきました。

応答分岐図

今後の改善

  • 検索前処理の改善
  • 日付やイベント名の正規化
  • 文書追加時の Markdown 整形支援の強化
  • 機能案内のカテゴリ要約改善
  • デプロイフローの自動化

特に今後精度を上げるなら、まずモデルを変える前に検索前処理を改善するのが筋だと考えています。たとえば「4/21」「4月21日」「来週月曜」が同じ候補へ寄るような前処理が入るだけでも、体感品質はかなり変わるはずです。

まとめ

この取り組みを通して一番大きかったのは、文書検索システムの品質は LLM の性能だけでは決まらない、という点です。小規模運用では、

  • どの文書をどう保持するか
  • OCR と人手確認をどう分担するか
  • どの質問を LLM に渡さないか
  • 運用状態をどう見える化するか

といった周辺設計の方が、使い勝手を大きく左右します。

低コスト・少人数・既存 UI 活用という制約の中では、理想的な完全自動化よりも、壊れにくく、変更しやすく、利用者に説明しやすい構成の方が長く使えます。
今回の構成はその一例として、同じように小規模な文書検索やナレッジ整理を考えている場面でも応用できるのではないでしょうか。

生成AIは「スパイス」でいい。やる気ゼロから鬼編集者に変わる秘策

「あ〜資料作らなきゃ・・・」テンション低めのときに「生成AI」をスパイスに。

忙しい。疲れている。時間がない。

それでもドキュメントの品質は落としたくない。

そんなときに効いたのが、生成AIを「書くための代役」ではなく、自分のテンションを上げるためのスパイスとして使う方法だった。

自分で直してこそ、文章は血肉になる

以前の記事で、私はこんなことを書いた。

AIが書いた文章をそのまま流すのは危険だ。自分で書いた(あるいは直した)言葉でなければ、本当の意味で理解できない。

そして、こうも。

「あなたの手」を効かせて欲しい。自動生成された文章には、改行位置や強調具合など気になるところがあるはずだ。

言っていることは本心だし、いまも正しいと思っている。

ただ、正しいからといって、いつもできるとは限らない。

忙しいと、チェックが浅くなる。

疲れていると、直す気力が削られる。

そんな状況で、次の「実践編」を書かなければならなかった。

しかもさらに、もう一つ前のブログで、

次回は 「実践編」として、実際にGoogleドキュメントとGeminiを使って、ゼロからSlidocsを爆速で作成する具体的な手順を公開します。

と書いてしまっている。

あまり時間を空けるわけにはいかない。

私は生成AIに「村上春樹風にして」と投げた

そこで私は、文章の校正段階で生成AIにこう頼んだ。きっと逃げ出したい気持ちがあったのだと思う。

「村上春樹風にして」

すると、あれよあれよと「村上春樹風」になった。いや、「村上春樹を意識して書いてみた」だ。「ものまね芸をものまねした」ようだった。

とはいえ、比喩が増え、リズムが出て、テンポが変わって、文章の印象が別物になった。

……そして、過剰だった。くどかった。

「いい塩梅」ではなかったのだ。

でも、この中途半端感というか、違和感というか、その感覚が、私を動かした。

人は「中途半端さ」や「気持ち悪さ」を見つけると、それを放置しづらい。

いったん「この文章、なんか気持ち悪いな」と脳が検知すると、無意識にその“気持ち悪さ”を正そうとして、手が勝手に直しに向かう。

なんだかんだ言っても、書き手の中に「自分はちゃんと伝わる文章を書きたい」という基準があるからだ。

そこにズレが生まれると、認知的不協和(矛盾やズレがある状態が落ち着かない)として居心地が悪くなる。

この居心地の悪さが、編集のエネルギーになる。

生成AIに一度わざと“やりすぎ”の文章を作らせると、この違和感が手に入る。

そして違和感があるからこそ、直したくなる。

この流れが、私の「やる気スイッチ」を入れてくれた。

ここからが本番だった。

AIが“やらかした”から、私は”鬼編集者”になった

出来上がった過剰な文章に対して、私は鬼編集者のようにツッコミを入れ始めた。

  • 「ここはいらん」
  • 「この表現はぽくない」
  • 「そこまで回りくどくしなくていい」
  • 「もう少し具体例が欲しい」

面白いのは、作業の目的がいつの間にか「直さなきゃ」から「削って整えてスッキリする」に変わっていくことだ。

直しているうちに、テンションが上がっていった。

結果として、

  • 自分で内容を理解したまま
  • 自分の言葉で整えつつ
  • 〆切に間に合わせる

という、ついさっきまで腑抜けていた私には想像もつかないところに到達していた。

生成AIがワークフローのスパイスにもなった

その日は少し夕食が遅くなった。でも、自分で設定した〆切には間に合った。

よかった。

生成AIが、私の作業の流れ(ワークフロー)をこれまでとは違った形で前に進めてくれた。

テンションが上がらなかったときに、ちょっとした刺激を入れてくれた。

まさにスパイスだった。

だから、「実践編」の語調が以前の記事と少し違うのは、この背景がある。

やる気が空っぽのときほど、スパイスを入れる

今後も、

  • テンションが上がらないとき
  • 行き詰まったとき
  • 「あかん、空っぽやー」と感じるとき

そんなときは、生成AIをスパイスとして使っていこうと思う。

ポイントは、生成AIに任せきることではなく、遊ばせて、直して、最後に自分の手で締めることだ。

Slidocs作成:AIをパートナーにあなたの思考を「伝わる」資料にする

はじめに

前回の記事で、私は 「Slidocs(スライドックス)」という、少しばかり耳慣れない名前のフォーマットについて書いた。スライドのわかりやすさと、ドキュメントの正確さ。その二つを混ぜ合わせて、さっと理解したい人、さらに深掘りしたい人、その両方のニーズに対応出来る形式のドキュメントだ。

おそらく、あなたは記事を読みながらこう感じたはずだ。「よいかもしれない。でも、それを作る手間を考えると、気が滅入ってしまう」と。
その感覚は正しい。要約と詳細の両方を用意するなんて、そんな物理的な時間も精神的な余裕もありはしない。普通に考えれば、誰もやりたがらない。
しかし、時代は変わった。今は生成AIという名の、驚くほど有能なパートナーが入っている。

Slidocsを作るのに、気が滅入ることはない。面倒な構造化も、要約も、すべてAIに任せてしまえばいい。あなたはただ、言いたいことだけをAIに投げ掛ければいいのだ。 今回は、私が実際にSlidocsを書き上げるまでのプロセスを紹介しようと思う。
私が使ったのはGoogleドキュメントとGemini、シームレスで相性がいいからだ。もちろん、あなたが使い慣れた他のAIツールでも構わない。

2. 準備するもの

必要なのは最低限の道具と、どこへ行きたいかという意思だけだ。準備するものが増えるとそれだけも気が滅入るから、最小限に留めたい。

  • Google ドキュメントおよびGoogleスライド
    • Geminiで生成した文章を書き出し、このドキュメントをブラッシュアップする
    • Geminiから直接アクセス出来るのも都合がいい(Google workspaceに接続が必要だが、Essentials Starterという無料版あり)
    • スライドはドキュメントをビジュアル化するために利用する
  • Gemini
    • 無料版でも構いませんが、Google Workspace等の有償版でドキュメント内に統合されていると、よりスムーズに事が運ぶ
  • 【重要】あなたの「言いたいこと」
    • 完璧な文章である必要はない。箇条書きの、断片的な思考の欠片で十分だ。

道具が揃ったのなら、はじめよう。

⚠︎GeminiからGoogleドキュメントへアクセスさせるためには、ファイル添付をGoogle Driveからとするか、プロンプトから @Googleドキュメント とアプリケーションへの接続を明示的に指定する必要がある。

@Googleドキュメント

※注意 現在Geminiは日々進化し、仕様が不安定である。そのため、ここの説明ではGeminiからアクセス出来ない可能性もある。なお、現時点では @Googleドキュメントとの接続ではツールの選択ができない。

ステップ1:とにかく「思考の種」を書き出す

いきなりGoogleドキュメントを開いてはいけない。 真っ白なページは、緊張する。そこで立ち尽くして時間を浪費しないように、まずはAIとの「おしゃべり」から始めよう。

書きたいことや、モヤモヤしている疑問を、チャット欄に投げかける。「会議、わからん。論点は? 資料には書いてないじゃん。いや書いてあるけど、ぼやけてる。短時間で理解は無理。後で見返してもわからん。行間での意図が多過ぎ。なんとかならないか?」文法なんて気にする必要はない。ただ、思考を言葉にすればいい。

その後、AIから生成されるレスポンスに対して「論点を明確にしましょうなどのToBeの羅列ではなく、構造やフォーマットとして定義したいんだ」「そうそう、概要理解と詳細理解を同時に、しかも2つの資料を作らずにしたい」「社内もドキュメントのSaaS利用進んでいるから、それらを活用して・・・」

そうやって壁打ちを続けていると、次第に霧が晴れてくるはず。思考の断片が繋がり、輪郭を 見せ始めてくる。そうなれば、こちらのもの。AIにこう頼んでみるといい「今までの話を、言語化してまとめて」と。

そして、ここからが最も重要なフローだ。 AIが出力したそのテキストをGoogleドキュメントに出力して、必ず「あなた自身の手」で加筆修正すること。

これは次のステップで作る「骨子(目次)」ではまだない。あなた自身が、何を書きたいのかを認識するためのプロセスである。 AIの要約は優秀だが、あなたの意図の全てを汲んではくれていない。「ここは少し違う」「もっと強い言葉で言いたい」。そうやって赤を入れることで、曖昧だった思考が確固たる「認知」へと変わる。

生成AIに最初から最後まで書かせると、綺麗だけれどどこか他人行儀な文章になってしまう。 最後の一筆をあなたが加えることで、そのドキュメントは初めて「あなたの思考」となる。

【実践例】前回の記事の「種」

実際に、私が前回の記事(Slidocsの解説記事)を書いたときのモヤモヤ思考と、輪郭がはっきりした思考をお見せすることにする。まず、最初にAIに投げかけたプロンプトは、たったこれだけだった。

ミーティングで見せられる資料がまいど分かりにくいし、翌週には内容を忘れている。
資料を見返してもイマイチ思い出しきれない。もっとよい資料のあり方を考えたい。

その後のやりとりで、認知できた私のモヤモヤの正体は以下となる。

■記事のテーマ
生成AI時代の新しい資料フォーマット「Slidocs」の提案
■ターゲット

  • 仕事で資料作成が多い人
  • 「言った言わない」のトラブルに疲れている人
  • スライド作りが苦手な人

■現状の課題(Why Now?)

  • パワポ(スライド):行間が伝わらない。あとで見返しても意味不明。
  • ワード(ドキュメント):文字ばかりで読む気が失せる。会議で読み上げると眠くなる。
  • 両方作るのはコストが高すぎて無理だった。

■解決策(Slidocsとは)

  • スライド(ビジュアル)とドキュメント(詳細)のハイブリッド。
  • 構成:上部に「要約・図解」、下部に「詳細テキスト」。
  • メリット:パッと見てわかるし、じっくり読めば誤解がない。AmazonのReading cultureを根付かせるのはすぐには無理。まずはもっと視覚的に理解しやすく脱落させない。
  • このフォーマットと目的はSlidedocs®とは別物

■一番言いたいこと

  • 「作るのが大変そう」と思うだろうが、今は生成AIがある。
  • 構造化と要約はAIが得意な作業。だからコストは問題にならない。
  • これからは「AIに素材を渡してSlidocsを作る」のが当たり前になる。

種は小さくても、そこには確かにあなたの思考が含まれてる。それを掘り起こし、明確化することからはじめよう。

ステップ2:AIに「骨子(目次)」を作らせる

骨組みがおかしなドキュメントは、あなたの思考を誤解させ、また無駄な質疑応答に疲弊してしまう。

Slidocsにおいて最も重要なのは「構造」である。
しかし、白紙の状態から「第1章、第2章……」と構成を考えるのは骨が折れる作業だ。そこで、AIという有能な構成作家に頑張ってもらおう。

ステップ1で思考を整理したGoogleドキュメントを添付し、Geminiに以下のプロンプト(指示文)を入力するといい。(もちろん、本文をチャット欄にコピペしても構わない。)

【プロンプト例:構成案の作成】

[ここにステップ1で作ったGoogleドキュメントを添付]
※Geminiがアクセスできるように、@Google Drive などでファイルを指定
指示:
あなたは優秀な編集者です。添付したGoogleドキュメントの内容をもとに、会議資料の構成案(目次)を作成してください。

条件:
* 会議参加者が論点を理解しやすい論理構成にすること。
* 最終的には意思決定するための流れにすること。

Geminiは数秒で、あなたの思考の塊を整理された目次へと変換するだろう。
出力された構成を見て、「少し違うな」と思えば、修正を指示する。ここでも納得のいく骨組みができるまで、AIと対話をする。それが思考の塊をあなたが伝えたいストーリーとしての目次として出来上がっていく大切な過程である。

修正内容によっては、Geminiが出力した構成案をGoogleドキュメントの「思考の種」の下に書き出し、自分の手で修正を加えるとよい。

チャット上でAIに何度も修正指示を出すよりも、自分で書き換えてしまったほうが早く、何よりあなたが手を動かした時にはじめて思考を深めることになることもあるだろうから。 納得のいく骨組みができるまで、対話して、手を動かす。それが肝である。

ステップ3:「詳細レイヤー(ドキュメント要素)」を執筆させる

しっかりとした骨格ができあがったら、次は肉付け。
ここでの「肉」とは、Slidocsにおける「詳細レイヤー(ドキュメント要素)」、つまり読み手がじっくりと読み込むための本文のテキストである。
ここでも、初手からあなたがキーボードを叩いて長文を書く必要はない。ステップ2で修正・確定させた目次(構成案)をもとに、AIに執筆を依頼するといい。このときGeminiならツールとして Canvas を選択しておくとよい。長い文章でも整形されたフォーマットは読みやすく、その後のGoogleドキュメントへのエクスポートも楽になるから。

【プロンプト例:本文の執筆】

[ここにステップ2で作ったGoogleドキュメントを添付]
※Geminiがアクセスできるように、@Google Drive などでファイルを指定

指示:
添付したGoogleドキュメント内にある「構成案」の各セクションについて、本文を執筆してください。

条件:
* トーン&マナー:ビジネスパーソン向けの、論理的かつ熱量のある文体で。
* 各セクション、詳細な説明を記述すること(箇条書きではなく、文章で)。
* 「言った言わない」をなくすため、論理の飛躍がないように丁寧に説明してください。
* 参照した資料や文献があれば、参照元を示してください。

Geminiが生成を開始すると、画面上に文字が溢れ出してくる。あなたはそれをコーヒーでも飲みながら眺めていればいい。

しかし、ここで作業を終わらせてはいけない。

Geminiが出力したドキュメントをGoogleドキュメントに書き出すべきだ。 先ほどまでの「思考の種」や「構成案」が入ったドキュメントではなく、新しいドキュメントへ書きだそう。それらのエッセンスはすべて、今出力された本文の中に溶け込んでいる。これからは、この新しいドキュメントを、誰かの目に触れる「作品」に仕立て上げていくベースになる。

そして、必ず自分自身の手で加筆修正を行ってもらいたい。

最近、AIが書いた文章をそのまま右から左へ流す人を見かけるが、それは危険だ。自分で書いた(あるいは直した)言葉でなければ、本当の意味で内容を理解することはできない。 「ここはもっと具体的な事例を入れたい」「この表現は少し堅苦しい」。そうやって手を入れることで、初めてそのドキュメントはあなたの血肉となり、会議で質問されても自信を持って答えられるようになる。会議中に冷や汗をかきたくはないだろう?

ステップ4:「ビジュアル・レイヤー(スライド要素)」を抽出させる

今のままでは、あなたのドキュメントはただの「文字の壁」だ。正確だが、愛想がない。まるで電話帳のように、必要なことはすべて書いてあるけれど、誰も読みたがらない。

SlidocsをSlidocsたらしめているもの。それは、詳細なテキストの上に掲げられる「ビジュアル・レイヤー(要約と図解)」。ここは「読ませる」のではなく「見せる」場所。一目瞭然のインパクトが必要だ。

ここでは、Geminiとのチャット内のツールCanvasと、カスタマイズ機能である「Gems」を活用して、ドキュメントを一瞬でスライド化する術を説明しよう。

1. Gemsで「専属スライドデザイナー」を呼び出す

もしあなたがGeminiを使えるなら「Gems」でスライド作成専用のプロンプトを保存しておくと便利だ。 「箇条書きにして」だけでなく、以下のような「ビジュアル指示」を含めるのがコツ。また、統一感を見せるために色彩設計は重要なので、憶えておくといい。

  • 強調表現: キーメッセージを「太字」や「括弧」で囲む。
  • 色彩設計: 背景色、メインカラー(例えば、自社のコーポレートカラー(例: #1e3a8a))、アクセントカラーなどを指定する。
  • 管理タグ: 「社外秘(CONFIDENTIAL)」や「決定事項」などのスタンプを入れる。

2. Canvasでスライド要素を生成する

ビジュアル指示を入れたGemsを呼び出したら、ビジュアル指示と以下のようなプロンプトを投げるとよい。その際、スライド形式であることを明示した方がよい結果が得られるだろう。

【プロンプト例:ハイインパクトなスライド化】

[ここにステップ3で作ったGoogleドキュメントを添付]
※Geminiがアクセスできるように、@Google Drive などでファイルを指定
指示:
添付ファイルに記載されたドキュメントの各セクションを要約して、スライドにしてください。
条件:
* 構造: 1行程度の「キーメッセージ(要約)」と、要約の中のワードや論理の説明や根拠が基本構成。
        複雑な論理構造は図解、論理の対比や数字の比較は表などを用いるなど、情報が整理しやすい表現を用いる。
        説明や根拠はリストやブロック構造など視覚的にわかりやすく配置する。
* 強調: 重要な単語は括弧で囲んだり、フォントを大きくしたり、太文字、アクセントカラーなどで強調する。
* 属性: 右上に「社外秘」のテキストボックスを入れること。
* デザイン意図: 忙しい役員が、この枠を見るだけで「Go/No-Go」を判断できる情報量に絞る。
* 表現: ドキュメントと同じ文体や言い回しにする。
* 出力: Googleスライドにエクスポートしやすい形式

Geminiが構成を出力したら、画面上の「スライドにエクスポート」ボタンを押してGoogleスライドに書き出す。 できたら、次に進もう。

3. スライドを手直しし、画像としてドキュメントに戻す

ここでもやはり、「あなたの手」を効かせて欲しい。これまでの自らの意思を込めたドキュメントに対して、 自動生成されたスライドは改行位置や強調具合など気になるところがあるはずだ。それこそあなたの魂を込める余地。Googleスライドを開き、デザイナーになったつもりで仕上げを行おう。

納得のいくスライドができたら、各ページを選択し、「ファイル > ダウンロード > PNG画像(.png 現在のスライド)」を実行、そして、その画像をGoogleドキュメントの対応するセクションの冒頭に貼り付けていく。

文字だけの愛想のない壁面が、鮮やかになる瞬間。 この「画像(要約)」と「テキスト(詳細)」の二層構造こそが、読み手の脳に最も優しいSlidocsの完成形となる。しかし、最後まで手は抜かない。次で最後のステップだ。

ステップ5:仕上げは「AIと人間によるチェック」

最後の仕上げ。それはこれまでのステップであなたやAIがやってきたことだが、これまではチェックは思考を明確にすること、ストーリーを納得させること、ドキュメントをあなたの言葉にすることなどが目的だった。最後に全体を通して、文章校正を目的にしたチェックを行う。目的外のことは、あなたもAIも見ていない。当然だ。だから最後までやりきろう。

さて、AIに校正のアシスタントを依頼しよう。目的通りの以下のプロンプトを使って、客観的な視点でドキュメント全体をチェックさせる。

【プロンプト例:最終校正とチェック】

[ここにステップ4でSlidocs化したGoogleドキュメントを添付]
※Geminiがアクセスできるように、@Google Drive などでファイルを指定

指示:
添付したドキュメント全体の校正を行い、修正案または指摘事項をリストアップしてください。リストアップは修正済みが表現できるようにチェックボックスにしてください。


チェック項目:
1. 誤字脱字: 明らかな入力ミスや変換ミスがないか。
2. 表記ゆれ: 「私/僕」「弊社/当社」などの人称や、固有名詞(製品名など)の表記が統一されているか。
3. トーンの調整: 全体を通して「ビジネスパーソン向けの信頼感ある文体」になっているか。砕けすぎたり、堅苦しすぎる箇所があれば指摘すること。
4. ハルシネーションの懸念: 数値データや具体的な事実関係について、文脈的に不自然な箇所や、事実確認(ファクトチェック)が必要と思われる箇所を指摘すること。

AIからのフィードバックを受け取ったら、それを参考にしながら、最後は必ずあなた自身の目で確認・修正を行う。

特に「ハルシネーション(もっともらしい嘘)」や「熱量」に関しては、AI任せにできはしないだろう。 そこに魂を吹き込めるのは、世界であなただけなのだから。

まとめ:AIをパートナーによりよいものを早く

こうして、一つのSlidocsが完成したはずだ。
かかった時間は、おそらく以前の半分以下だろう。しかし、そのクオリティはきっと向上しているはずだ。
私たちはこれまで、資料を作るためにあまりにも多くの時間を「構成の組み立てで行ったり来たり」「推敲し、キーボードを叩き」「レイアウト調整に四苦八苦」に費やしてきた。
しかし、Slidocsと生成AIの組み合わせは、その苦役から私たちを解放すると同時に、さっと分かる、じっくり読んで分かる資料に昇華させることができる。

  • 人間は「思考の種(言いたいこと)」を生み出す。
  • AIがそれを「構造化」し、「ビジュアル化」する。

この分業こそが、新しい時代のスタンダードになりつつある。

明日の会議資料、さっそくこの方法で作ってみてはどうだろうか?

完璧な資料を作ろうとして一人で夜更かしをする必要はない。AIをパートナーにあなたの思考を見て分かる資料、深く理解できる資料をサクッと作り、さっさと寝床につくといい。

「伝わらない」をなくす。生成AI時代に見直したい資料作成術 - 「Slidocs(スライドックス)」という解法

はじめに

あなたが会議で受ける質問・回答の多くが単に「伝わっていない」ための確認やそれを埋めるためのやりとりだったりすると思います。
あるいは、聞き手の立場で、後から資料を見返したとき、箇条書きの短いテキストとグラフだけが並んでいて、「結局、なぜこの結論になったんだっけ?」と頭を抱えたことはないでしょうか。
私たちは日々、資料作成において「伝わらない」を生む多くのジレンマを抱えています。

この長年の課題を解決する手法として、「Slidocs(スライドックス)」という資料フォーマットを定義します。(このブログ記事のようなフォーマットです。) スライド要素とドキュメント要素を併せ持つこのフォーマットは、作成コストの高さがネックと思われるかもしれませんが、生成AIが登場した「今」こそ、最も合理的で強力な武器になります。

今回は、伝わる資料フォーマットとして「Slidocs」と、それを現実的な工数で実現する方法について解説します。

「伝わらない」を生み出す理由

  • プレゼン資料の「行間」消滅問題

    • スライド(PowerPoint等): 視認性が高い一方で、説明の背後にある文脈・論理(行間)を省略してしまいがち
  • 追い切れない情報量

    • 情報過多スライド: 行間を埋めようとして文字を詰め込むと、字が小さくなったり、読む順序も不明瞭になったりする
    • ドキュメント(Word等): 詳細は網羅できるが、文字ばかりで全体像が掴みづらく、読み上げると集中力が続かない

これらの課題に対して、発表用の「薄いスライド」と、詳細を記した「重いドキュメント」の2つを作成・管理するコストが発生したり、あるいはスライドに文字を詰め込みすぎて「読むのも聞くのも辛い」資料が生まれたりします。

この「同期(会議中)の分かりやすさ」と「非同期(会議後)の再現性」を両立させる解決策として、今回は「Slidocs(スライドックス)」 というアプローチを紹介します。

「パッと見てわかる」と「じっくり読んでわかる」を両立

似たような語感でSlidedocs®という手法を聞いたことがある人もいるかもしれません。
Slidedocs®は、プレゼンテーションデザインの権威であるNancy Duarte(ナンシー・デュアルテ)氏が提唱した概念です。

"Slidedocs are visual documents, developed in presentation software, that are intended to be read and referenced instead of projected."
(Slidedocsとは、プレゼンテーションソフトで作成された、投影用ではなく「読んで参照する」ためのビジュアルドキュメントである)
*1

従来の「投影して話すこと」を前提としたスライドではなく、「読まれること」を前提にデザインされた資料のことです。

「読む」会議としてAmazonでは、PowerPointの使用を禁止し、会議冒頭に「沈黙の読書時間(Silent meeting)」を設けています。

しかし、Amazonのように『会議時間を読書に充てる』という文化変革をいきなり起こすのはハードルが高いかもしれません。そこで、『今の会議スタイルのまま、自然と中身も読める』ように再設計したのが、今回のSlidocsです。

私はこれを現代のビジネスツール(Google DocsやNotionなど)に合わせて 「縦スクロール型のスライドとドキュメントのハイブリッド資料」 と定義しました。

具体的な構造:情報の「レイヤー化」

Slidocsの最大の特徴は、情報の構造化にあります。1つのトピックを以下の2つのレイヤーで構成します。

  • ビジュアル・レイヤー(スライド要素)
    • 役割: 全体の概要を瞬時に伝える。
    • 要素: タイトル、要約メッセージ、グラフ、図解。
    • 効果: 忙しい決裁者でも、ここを見るだけで大枠を理解できる。
  • 詳細レイヤー(ドキュメント要素)
    • 役割: 論理的な詳細、背景、データを網羅する。
    • 要素: テキストによる詳細な説明、補足データ、注釈。
    • 効果: 実務担当者や後で読み返す人が、迷いなく正確に理解できる。

この2層構造により、「パッと見てわかる」と「じっくり読んでわかる」を両立させるのです。

構成イメージ

【見出し】 プロジェクトAの採用技術について

【要約(スライド要素)】
* Reactを採用し、開発効率を優先する
* 初期コストは高いが、中長期の保守性で回収可能

【本文(ドキュメント要素)】
今回Reactを選定した主な理由は、既存チームのスキルセットとの適合性です。
Vue.jsと比較検討しましたが、エコシステムの広さと採用市場の活況を考慮し……
(以下、詳細な比較データとロジック続く)

Slidocs導入の3つのメリット

  • 「言った言わない」がなくなる
    • 詳細がテキストとして明記されるため、解釈のズレがなくなります。
  • 属人性の排除
    • 作成者がその場にいなくても、資料単体で説明責任を果たせます(これがよい意味での「独り歩きする資料」です)。
  • 非同期コミュニケーションの加速
    • 事前にSlidocsを共有しておけば、会議の時間を「情報共有」ではなく「意思決定」や「議論」だけに集中させることができます。Amazonなどが実践する「Reading Document」の文化もこれに近いものです。

なぜ「今」なのか? コストの壁を壊す生成AI

ここまで読んで、「理屈はわかるけど、作るのが大変そう」と思いませんでしたか?

おっしゃる通りです。Slidocsの最大のデメリットは 「作成コスト」です。スライドのビジュアルを作り込み、さらにドキュメントのような文章も書く。普通にやれば2倍の手間がかかります。

しかし、生成AIの登場で状況は一変しました。

今こそSlidocsを導入すべき理由は、AIを使えばコストをかけずに「いいとこ取り」ができるからです。

従来の作成フロー(コスト大)

  • 自分で構成を考える。
  • 自分で文章を推敲して書く。
  • 自分で図解や要約を作る。
  • 結果: 時間がかかりすぎて挫折する。

生成AI時代の作成フロー(コスト小)

  • 人間:
    • 箇条書きやメモ書き(ラフなアイデア)を用意する。
  • AI:
    • 「これを論理的な文章に直して」→ 詳細レイヤーの完成
    • 「この内容を3行で要約して」→ ビジュアル・レイヤーのメッセージ完成
    • 「この内容を表形式に整理して」→ 図解の元ネタ完成

私たちは、AIに「素材」を渡すだけで良くなったのです。むしろ、Slidocsのような「構造化されたドキュメント」は、生成AIが最も得意とする形式です。

「だらだら書き」から始めても、AIが整えてくれる。
この安心感があるからこそ、私たちは本質的な「中身」の検討だけに集中し、高品質なSlidocsを短時間で作成できるのです。

まとめ

Slidocsは、単なる資料のフォーマットではありません。「相手の時間を奪わず、正確に情報を伝える」 という、ビジネスコミュニケーションへの姿勢そのものです。

これまでは作成コストの壁がありましたが、生成AIという強力なパートナーがいる今、挑戦しない手はありません。

次回は 「実践編」として、実際にGoogleドキュメントとGeminiを使って、ゼロからSlidocsを爆速で作成する具体的な手順を公開します。お楽しみに!

*1:出典: Slidedocs

技術負債の返済を「売上に効く投資」に変える ―― 実践から学んだ進め方

はじめに

新しい機能や顧客要望の取り込みは、売上に直結する“見えやすい投資”です。一方で、ライブラリ更新やアーキテクチャ整備、セキュリティアップデートといった技術負債の返済は“売上に直結しない投資”と見なされ、開発投資の意思決定の場で優先度が下がりやすいのも事実です。しかし、実際の技術負債の返済がもたらす成果・価値は売上アップを阻害している要因を排除するもので、「売上に効く投資」になるはずです。

経営陣は技術負債の悪影響(開発効率の低下、セキュリティリスクの増大)を頭では理解しています。それでも投資判断に迷いが生じるのは、「投資額に見合う成果が、いつ・どう売上や事業に効くのか」が十分に可視化されていないからです。さらに、一度きりの大規模返済プロジェクトでは、時間が経てばまた同じ構図に戻るのではという不安が生じているのです。

本記事では、技術負債の返済を“売上に効く投資”につなげるための価値定義について、実際に開発組織の長として私が行った取り組みをベースに説明していきます。


技術負債返済 × 価値づけの原則

ポイントは「技術負債返済そのもの」を目的化しないこと。技術負債返済が売上に効く投資としての“価値”を見出し、合意形成の材料に落とすことが重要です。価値づけを次の4つに整理します。

  1. 開発スピード:開発の容易さと意思決定のリードタイム短縮、デプロイ難易度低下と頻度の増加
  2. 信頼性・セキュリティ脆弱性対応・障害調査・復旧の迅速化、監査適合の容易さ
  3. 営業・採用の武器化:顧客要望の受け入れハードルの低下、差別化要素(監査対応、自動化、稼働率等)
  4. 原価・機会損失の削減:運用コスト/人件費の抑制、アップデート停滞による機会損失の回避

“返済→価値”のマッピングを投資前に明示し、成果の測定指標までセットで合意しておくことが、経営判断を前に進めます。

価値づけのポイント

価値づけする場合に何が優先されるかは会社の成長戦略と一致させる必要があります。特に成長スピードが優先される場合と、安定が優先される場合では、技術負債返済で得られる価値も合わせることが求められるでしょう。

「信頼性・セキュリティ」に関しては成長戦略とは一致しない場合はあります。この場合は、開発という責務の多くを担う部署として率先して、「信頼性・セキュリティ」に関する現状と課題については成長戦略と絡めて、言語化する必要があります。

また、例えば、開発スピードを上げるための技術負債の返済を行うとき、EOLを迎えているライブラリの置き換えも行い、セキュリティも上げようとすることはあると思います。このように開発スピードとセキュリティの複数の価値のためのソリューションを進めるときに、採用するソリューションによっては、新たな技術負債を生み出す可能性があることを理解し、複数の価値については優先順位を付けておくことをおすすめします。


期待価値とステークホルダーへの共有

技術負債返済により価値づけを行いました。

新しい機能追加など開発投資は、期待する価値が売上貢献などに対して直接的で分かりやすい一方、期待通りの価値を得られるかどうかの蓋然性(確度)は予測しにくいことがほとんどです。対して技術負債返済による価値は、既に顕在化している具体的な課題を取り除いた後に得られる価値であり、改善の起点も効果測定の指標も明確です。そのため、同じ限られた予算・人員を配分する局面では、期待価値(=価値×確度)を高く見積もりやすいため、他の開発投資との比較を行う場合、期待価値についても言及するとよいでしょう。

技術負債の返済により期待できる価値と確度を明確にしたところで、次にステークホルダー(経営陣だけにとどまらず、開発エンジニアやその価値を享受する人々すべて)に対して、共有することが重要です。特に、開発エンジニア以外に、セールスやカスタマーサービスへはデプロイ・リリース時の影響について、何かしらフィードバックを得られます。それに対応することを念頭に置き対策を講じておくことで、理解だけでなく、協力も得られます。

技術負債返済のコスト

技術負債返済は、当初見積を超えて延々と置き換え続ける沼になりがちです。これを避けるには、返済計画をフェーズに分解し、各フェーズで得られる価値を事前に言語化しておくことが有効です。フェーズごとに意思決定(Go/No-Go)と振り返りを行い、投下コストと獲得価値を都度検証することで、ズルズル続けずに途中成果を事業へ還元できます。環境や市場が変わっても、次フェーズの設計をすぐに変更できます。

次に、ズルズルと続けることがないようにフェーズを区切るためのポイントを整理します。

  • フェーズ期間の目安: 各開発フェーズは 3–5ヶ月以内 に収める。
    • 大きくなりそうな場合は、2–4週間の検討フェーズを前置きし、分割コストを払ってでも小さく刻む
  • 各開発フェーズ価値の言語化:各フェーズの開始前に開発投資の意思決定のために、価値を言語化する(「完了時に何ができるか/何が楽になるか」を具体的に定義)。価値が定量的に測れるものであるとよりよい。(例:開発リードタイム30%削減、ライブラリのEOLをなくす、平均復旧時間30%短縮)。
  • 次開発フェーズ前のチェック:完了した開発フェーズの価値を振り返る。効果が出るのに時間がかかるものであれば、判断時期をセットする。期待値からの乖離、状況の変化などがあれば、縮退や方向転換を行う。

さらに、フェーズ終了後のチェックポイントで次のフェーズに進むかどうかの撤退ポイント(キルクライテリア)を明確にすると、開発投資の意思決定はスムーズになります。

投資判断を通すための項目

これまでの内容を踏まえて、技術負債により毀損している価値を取り戻すための意思決定を行う上で重要なことを説明しました。実際に経営会議などで説明するための項目を整理します。

  • 背景/問題:どの負債が何を妨げているか(例:システムの複雑化により開発スケジュールが長くなり、顧客要望のバックログの滞留が長くなっている)
  • 期待価値:この返済により、どの価値がどれだけ改善するか。売上や信頼など経営層の意思決定しやすい内容にする
  • 施策:返済のためのソリューション案(検討フェーズの場合はその検討内容)
  • 指標・目標
    • デプロイ頻度、変更あたりの失敗率、平均復旧時間
    • EOLライブラリの対応数、脆弱性指摘の改善数
    • 機能追加、顧客要望の受け入れにかかる工数の削減率(または、削減時間)
  • 開発フェーズイメージ:全体をフェーズに分割した全体的なスケジュール(終盤の確度が落ちることを明確に)
  • 今回のフェーズ:
    • 期間:3-5ヶ月以内が望ましい
    • 期待価値:今回のフェーズのみの価値とその確度について説明
    • コスト:稼働工数、開発環境のランニングコストなど
  • リスク:今回の開発投資に限定されるリスクを明確にする
  • キルクライテリア:次のフェーズに進まない場合の条件を明確にできると、さらに意思決定が楽になる

まとめ:合意は「仕組み」に宿る

技術負債の返済は、売上に効く価値の回路を設計し、測定と運用に落とすことで、はじめて経営の意思決定を前に進めることができます。

「大規模プロジェクトで一掃」ではなく、小さく始めて仕組みで続ける。そのうえで、成長戦略と価値を一致させつつ、継続的に“返済→価値”の実感を積み上げていく――これが、同じ問題を繰り返さないための現実解だと考えています。

そのため、技術負債の返済のための合意は“金額の承認”ではなく“期待価値とチェックの仕組み”に対して取りに行く、がコツです。

AWS EKSクラスタでArmコンテナを動かす方法

この記事では、AWS EKSクラスタArmアーキテクチャのコンテナを動かす方法について説明します。Armコンテナは、特にコスト効率が求められるワークロードに適しています。ここでは、Terraformを使用してEKSクラスタをセットアップし、Javaアプリケーション(Spring Boot)をArmコンテナでデプロイする手順を紹介します。

続きを読む

Amazon Cognito リフレッシュトークンローテーション検証

2025年4月にサポートが発表されたCognitoリフレッシュトークンローテーション機能を検証し、その動作とセキュリティ効果を解説します。

対象読者

  • 認証機能を扱うフロントエンド・バックエンド開発者
  • Cognitoを利用中または導入検討中の技術者
  • セキュリティ向上に関心のあるエンジニア

背景

2025年4月、Amazon Cognitoでリフレッシュトークンローテーション機能のサポートが発表されました。

Amazon Cognito が更新トークンのローテーションに対応

この機能により、リフレッシュトークンの使い回しによるセキュリティリスクを軽減できるようになりました。
本記事では実際の検証結果を紹介します。

Cognitoが発行するトーク

トーク 用途 有効期限 リスク
Access Token API認可 5分〜1日
ID Token ID情報 5分〜1日
Refresh Token トークン更新 60分〜10年

リフレッシュトークンは長寿命のため、漏洩時のセキュリティリスクが高くなります。

ローテーション機能の概要

従来の動作

ローテーション有効時

効果: 使用済みトークンの無効化により、リプレイ攻撃等のリスクを軽減

検証① - 機能確認

環境設定

検証を容易にするため、以下の設定でCognitoクライアントを作成しました:

  • クライアントシークレット: なし(検証の簡素化)
  • トークン有効期限: 設定可能な最短値
  • リフレッシュトークンローテーション: 有効
  • 猶予期間: 0秒
  • ALLOW_REFRESH_TOKEN_AUTH: 無効(ローテーション有効時の必須設定)

注意: 本検証では猶予期間を0秒に設定していますが、実際のプロダクション環境では、ネットワーク遅延や並列リクエストを考慮して適切な猶予期間を設定する必要がありそうです。

Cognitoクライアント編集画面

検証コード

import boto3
import requests
import time
 
# 以下の定数はご自身の環境に合わせて編集してください
REGION = "<YOUR_AWS_REGION>"
USER_POOL_ID = "<YOUR_USER_POOL_ID>"
COGNITO_DOMAIN = "<YOUR_COGNITO_DOMAIN>"
CLIENT_ID = "<YOUR_CLIENT_ID>"
USERNAME = "<YOUR_USERNAME>"
PASSWORD = "<YOUR_PASSWORD>"
 
def login():
    print("Logging in via AdminInitiateAuth...")
    client = boto3.client("cognito-idp", region_name=REGION)
    resp = client.admin_initiate_auth(
        UserPoolId=USER_POOL_ID,
        ClientId=CLIENT_ID,
        AuthFlow="ADMIN_NO_SRP_AUTH",
        AuthParameters={
            "USERNAME": USERNAME,
            "PASSWORD": PASSWORD
        }
    )
    return resp["AuthenticationResult"]
 
def refresh_token(refresh_token):
    print("Refreshing token via /oauth2/token...")
    url = f"https://{COGNITO_DOMAIN}/oauth2/token"
    data = {
        "grant_type": "refresh_token",
        "client_id": CLIENT_ID,
        "refresh_token": refresh_token,
    }
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    res = requests.post(url, data=data, headers=headers)
    res.raise_for_status()
    return res.json()
 
if __name__ == "__main__":
    first = login()
    print("\nInitial login:")
    print("Access Token:", first['AccessToken'][:40], "...")
    print("Refresh Token:", first['RefreshToken'][:40], "...")
     
    time.sleep(5)  # Wait a bit before refreshing
 
    second = refresh_token(first["RefreshToken"])
    print("\nAfter refresh:")
    print("New Access Token:", second["access_token"][:40], "...")
    print("New Refresh Token:", second["refresh_token"][:40], "...")
 
    # Test reusing old token
    try:
        print("\nTesting old refresh token...")
        refresh_token(first["RefreshToken"])
        print("WARNING: Old token reuse succeeded - rotation may not be enabled")
    except requests.exceptions.HTTPError as e:
        print("SUCCESS: Old token is invalidated - rotation is enabled!")
        print("Error:", e.response.status_code, e.response.text)

実行結果

Logging in via AdminInitiateAuth...

Initial login:
Access Token: eyJraWQiOiJBcGl1T1p2QXczeVNuNmNcL3RmTUlS ...
Refresh Token: eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwi ...
Refreshing token via /oauth2/token...

After refresh:
New Access Token: eyJraWQiOiJBcGl1T1p2QXczeVNuNmNcL3RmTUlS ...
New Refresh Token: eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwi ...

Testing old refresh token...
Refreshing token via /oauth2/token...
SUCCESS: Old token is invalidated - rotation is enabled!
Error: 400 {"error":"invalid_grant"}

結果: 古いリフレッシュトークンが正常に無効化されることを確認。

検証② - 有効期限への影響

疑問点

AWSの発表では「中断なくアクセス維持」とありますが、これは有効期限延長を意味するのでしょうか?

デベロッパーガイドには「新しい更新トークンは、元の更新トークンの残りの期間有効」と記載されています。

検証方法

1分間隔でトークンを更新し続け、元の有効期限で停止するかを確認します。

import boto3
import requests
import time
from datetime import datetime # 追加
 
# 定数定義(REGION、USER_POOL_ID等)とlogin()、refresh_token()関数は
# test00.pyと同じ内容のため省略
 
if __name__ == "__main__":
    result = login()
    refresh = result["RefreshToken"]
    access = result["AccessToken"]
 
    print("\nStart time:", datetime.now())
    print("Initial refresh token (first 30 chars):", refresh[:30], "...")
 
    while True:
        try:
            print(f"[{datetime.now().strftime('%H:%M:%S')}] Updating token...")
            result = refresh_token(refresh)
            access = result.get("access_token")
            new_refresh = result.get("refresh_token")
            if new_refresh:
                refresh = new_refresh  # Update if rotated
                print("Refresh token rotated.")
            else:
                print("Refresh token not rotated (same).")
        except requests.exceptions.HTTPError as e:
            print(f"Update failed at {datetime.now()}")
            print("Error:", e.response.status_code, e.response.text)
            break
 
        time.sleep(60)  # Wait 1 minute

結果

※長いので途中のログは省略しています。

Logging in via AdminInitiateAuth...

Start time: 2025-07-12 14:15:15.749232
Initial refresh token (first 30 chars): eyJjdHkiOiJKV1QiLCJlbmMiOiJBMj ...
[14:15:15] Updating token...
Refresh token rotated.
[14:16:16] Updating token...
Refresh token rotated.
[14:17:17] Updating token...
Refresh token rotated.

... (1分おきの継続的なローテーション) ...

[15:14:11] Updating token...
Refresh token rotated.
[15:15:12] Updating token...
Refresh token rotated.
[15:16:13] Updating token...
Update failed at 2025-07-12 15:16:14.626224
Error: 400 {"error":"invalid_grant"}

結果: 初回発行から約61分後に停止しています。有効期限は延長されないことがわかりました

結論

ローテーション機能は...

  • 古いトークンを無効化
  • 有効期限は元のトークンの残り期間を継承
  • セキュリティ向上のための機能であり、トークンの有効期限を延長する機能ではない

まとめ

検証結果

2つの検証により、以下のことが確認できました:

  1. ローテーション機能は正常に動作

    • 古いリフレッシュトークンは無効化される
    • {"error":"invalid_grant"}でエラーが返される
  2. 有効期限は延長されない

    • 初回発行から設定した期限(今回は60分)で無効化
    • ローテーションしても元のトークンの残り期間を継承
  3. AWSの発表の「中断なくアクセス維持」の意味

    • 有効期限延長ではなく、セキュアなローテーションによる安全性向上
    • 期限内であれば、毎回新しいトークンで安全に更新可能

実装時の注意点

今回の検証から分かった実装時の注意点:

  • エラーハンドリングが必須: 古いトークンの再利用は400エラーとなる
  • 設定の確認: ALLOW_REFRESH_TOKEN_AUTHを無効にする必要がある
  • 猶予期間の設定: 0秒の場合は即座に無効化、最大60秒まで設定可能
    • 実際のプロダクション環境では、ネットワーク遅延や並列リクエストを考慮して、適切な猶予期間を設定する必要があると考えられます。

リフレッシュトークンローテーションは、認証セキュリティを向上させる有効な機能であることがわかりました。