{"componentChunkName":"component---src-templates-blog-template-js","path":"/2026-07-05-weekly-knowledge","result":{"data":{"site":{"siteMetadata":{"title":"KenRp Blog"}},"markdownRemark":{"html":"<p>2026年06月29日から2026年07月05日にかけては、<code class=\"language-text\">shared-shopping-app</code> という共有買い物リストアプリのリポジトリで、<code class=\"language-text\">ShareShopi</code> の UX 改修と Cloudflare 移行を進めつつ、その変更を Gatsby ベースの個人技術ブログへ再利用可能な形で残す運用を整えた。ここでいう <code class=\"language-text\">worklog-blogger</code> は、Codex セッションログと Git 履歴から日次 worklog と週次記事の下書きを生成する自作スキルである。</p>\n<p>この事例の主題は二つある。ひとつは <code class=\"language-text\">ShareShopi</code> を Supabase 依存から Firebase Auth と Cloudflare D1 中心の構成へ移すこと。もうひとつは、その移行作業を「後から読んで再現できる技術記録」に変換するために、日次 worklog の品質ゲートを ブログ側で整えたことだ。</p>\n<h2>この記事で解決すること</h2>\n<p>Cloudflare 移行は、認証、データ、API、運用文書が同時に動くため、単なる作業ログでは再現しづらい。この記事では、次の悩みを解く。</p>\n<ul>\n<li>Supabase 依存から Firebase Auth と Cloudflare D1 へ寄せる判断を整理したい。</li>\n<li>UI、API、DB、運用ドキュメントを混ぜずに移行記録へ落としたい。</li>\n<li>後から検証できるよう、テスト済みの範囲と残課題を明確にしたい。</li>\n</ul>\n<h2>実施した改善</h2>\n<p>週の前半は、ブログ側で日次 worklog を保存する運用を毎日見直し、自動生成直後の草稿に残る抽象表現を減らした。週の後半は、<code class=\"language-text\">ShareShopi</code> 側でローディング UI の共通化、Firebase Auth への認証移行、Cloudflare D1 へのデータ移行、Cloudflare 前提の build・deploy・運用ドキュメント更新を進めた。</p>\n<p>単なる日報にしなかったポイントは、実装と記録を分けて扱ったことにある。草稿生成スキルは下書きを集める役割に留め、本文では <code class=\"language-text\">shared-shopping-app</code> とブログ側の変更内容、テスト、運用判断を主語に置いた。</p>\n<h2>確認できた成果</h2>\n<table>\n<thead>\n<tr>\n<th>対象</th>\n<th>変更内容</th>\n<th>検証・運用の到達点</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code class=\"language-text\">ShareShopi</code></td>\n<td>共通ローダー導入、Firebase Auth 追加、Cloudflare D1 移行、運用ドキュメント更新</td>\n<td>トークン検証テスト追加、E2E 観点整理、Cloudflare build/deploy 手順を文書化</td>\n</tr>\n<tr>\n<td>ブログ側</td>\n<td>日次 worklog を既存 frontmatter 契約に沿って保存</td>\n<td><code class=\"language-text\">validate-content.js</code> で Markdown 記事の静的検証を継続</td>\n</tr>\n<tr>\n<td>草稿生成スキル</td>\n<td>dry-run 後に人手で具体化する運用を確立</td>\n<td>抽象的な初稿をそのまま公開候補にしない判断基準ができた</td>\n</tr>\n</tbody>\n</table>\n<p>成果として大きかったのは、アプリ移行の実装知見と、その記録方法が同時に整理されたことだ。<code class=\"language-text\">ShareShopi</code> 側では Cloudflare へ寄せる構成が具体化し、ブログ側ではそれを draft 記事として壊さず残す最小の品質ゲートが固まった。</p>\n<h2>判断と進め方</h2>\n<p>最初に見えた問題は、自動生成された daily worklog に <code class=\"language-text\">対象アプリ</code> のような未具体化表現が残ることだった。これでは、後から見返しても「どのリポジトリの、どの層を、なぜ変えたのか」が伝わらない。そこで 2026-06-29、2026-07-01、2026-07-02、2026-07-04 の worklog では、ブログ側の記事データ契約、<code class=\"language-text\">gatsby-source-filesystem</code> による取り込み、<code class=\"language-text\">validate-content.js</code> による静的検証を確認しながら、人手で内容を具体化する流れを繰り返した。</p>\n<p>そのうえで 2026-07-03 の <code class=\"language-text\">ShareShopi</code> では、実装の中心が明確だった。まず App Router のローディング表現を共通ローダーへ寄せて UX の揺れを減らし、その後に認証とデータ保存を Cloudflare 向け構成へ移した。最後に <code class=\"language-text\">README.md</code>、<code class=\"language-text\">CLOUDFLARE_MIGRATION.md</code>、無料運用の制約文書を更新し、build・preview・deploy の入口をコードと同じ日に揃えた。</p>\n<p>この順番が有効だった理由は、UI、認証、データ、運用文書を一度に変えても、各層の責務を切り分けて説明できるからだ。後から週次記事へする時も、変更のまとまりごとに知識を再構成しやすかった。</p>\n<h2>使った技術</h2>\n<p>この事例の技術選定は、ログ生成ツールではなく、実際に変更したアプリとリポジトリを中心に整理した方が分かりやすい。</p>\n<table>\n<thead>\n<tr>\n<th>技術 / 仕組み</th>\n<th>使った対象</th>\n<th>役割</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Next.js App Router / React</td>\n<td><code class=\"language-text\">ShareShopi</code></td>\n<td>画面遷移、ローディング UI、共有買い物リストのフロントエンド</td>\n</tr>\n<tr>\n<td>Playwright</td>\n<td><code class=\"language-text\">ShareShopi</code></td>\n<td>ローダー表示や初回導線の E2E 観点</td>\n</tr>\n<tr>\n<td>Firebase Auth</td>\n<td><code class=\"language-text\">ShareShopi</code></td>\n<td>Google ログインとメールログイン、ID Token 発行</td>\n</tr>\n<tr>\n<td><code class=\"language-text\">jose</code> による JWT 検証</td>\n<td><code class=\"language-text\">ShareShopi</code></td>\n<td>API 側での Firebase ID Token 検証</td>\n</tr>\n<tr>\n<td>Cloudflare D1</td>\n<td><code class=\"language-text\">ShareShopi</code></td>\n<td>共有リスト、プロフィール、招待、リマインドの永続化</td>\n</tr>\n<tr>\n<td>OpenNext + Cloudflare Workers</td>\n<td><code class=\"language-text\">ShareShopi</code></td>\n<td>Cloudflare 前提の build / preview / deploy 先</td>\n</tr>\n<tr>\n<td>Gatsby 2 / <code class=\"language-text\">validate-content.js</code></td>\n<td>ブログ側</td>\n<td>weekly/daily 記事の取り込みと frontmatter 検証</td>\n</tr>\n</tbody>\n</table>\n<p>重要なのは、草稿生成スキルを「アプリの実装技術」としては扱わなかったことだ。あれは source material を集める補助であり、この事例の実装上の知見は <code class=\"language-text\">ShareShopi</code> の Cloudflare 移行と、ブログ側でその変更記録を安全に保持する運用にある。</p>\n<h2>構成</h2>\n<p><code class=\"language-text\">ShareShopi</code> の移行後イメージは、認証、API、データ、運用ドキュメントの責務を分ける形に寄っている。</p>\n<div class=\"gatsby-highlight\" data-language=\"mermaid\"><pre class=\"language-mermaid\"><code class=\"language-mermaid\">flowchart LR\n  U[&quot;ブラウザ / Next.js UI&quot;] --&gt; A[&quot;Firebase Auth&quot;]\n  U --&gt; B[&quot;Next.js API Routes&quot;]\n  A --&gt; B\n  B --&gt; C[&quot;Cloudflare D1&quot;]\n  B --&gt; D[&quot;公開リンク / リマインド処理&quot;]\n  E[&quot;README / Migration Docs&quot;] --&gt; B\n  E --&gt; C</code></pre></div>\n<p>フロントエンドでは <code class=\"language-text\">components/app-loader.tsx</code> を中心にローディング UI を共通化し、App Router の <code class=\"language-text\">loading.tsx</code> とナビゲーション中の待機表示をそろえた。API 層では <code class=\"language-text\">lib/api-auth.ts</code> が bearer token を受け、<code class=\"language-text\">lib/firebase-token.ts</code> で検証した結果を <code class=\"language-text\">lib/d1.ts</code> の viewer 解決へつなぐ。データ層では D1 の migration で <code class=\"language-text\">profiles</code>、共有リスト、メンバー、商品、招待、リマインド履歴を管理し、Supabase 側に散っていた責務を Cloudflare 前提へ集約した。</p>\n<p>一方で記録側のブログ側はシンプルで、<code class=\"language-text\">_data/blog/*.md</code> がデータ層、Gatsby のファイル収集と Markdown 変換が表示層、<code class=\"language-text\">validate-content.js</code> が受け入れ検証層になる。この事例ではこの「実装アーキテクチャ」と「記録アーキテクチャ」を混ぜないことが重要だった。</p>\n<h2>採用理由と代替案</h2>\n<p>Firebase Auth を選んだ理由は、Google ログインとメールログインを Workers 本体へ抱え込まず、認証だけを独立サービスとして安定させたかったためだ。D1 を選んだ理由は、Cloudflare Workers と同じ基盤で API・DB・Cron を寄せられ、無料運用の条件を考えると構成が単純になるからである。</p>\n<p>Supabase を段階的に残す選択肢もあったが、認証とデータアクセスの二重経路が残ると、権限境界と移行後の検証が難しくなる。そこで <code class=\"language-text\">firebase_uid</code> を追加しつつ D1 側へ viewer 解決を寄せ、旧 callback route や heartbeat 実装を削除する方向が採られた。</p>\n<p>ブログ側で <code class=\"language-text\">validate-content.js</code> を品質ゲートに据えたのも同じ発想だ。weekly/daily 記事の変更はアプリコード改修よりコンテンツ追加が中心なので、まず壊れやすいのは frontmatter 契約と <code class=\"language-text\">path</code> の整合性である。毎回フル build を回すより、最短の静的検証でドラフト品質を守る方が作業密度に合っていた。</p>\n<h2>検証結果</h2>\n<p>確認した観点は、ShareShopi の認証、データ、API、運用文書を Cloudflare 移行の構成要素として分けて確認した点にある。確認した主な観点は次の通り。</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> <span class=\"token builtin class-name\">test</span>\n<span class=\"token function\">npm</span> run build\n<span class=\"token function\">npm</span> run test:e2e\n<span class=\"token comment\"># Firebase ID Token 検証テスト</span>\n<span class=\"token comment\"># OpenNext / Wrangler の build・preview・deploy 手順確認</span></code></pre></div>\n<p>Supabase 依存を段階的に残す案と、Firebase Auth + D1 へ寄せる案を比較し、権限境界を単純にする方針を採った。</p>\n<h2>導入手順</h2>\n<p>この事例の流れを再利用可能な手順へ落とすと、次の順で進めるのが現実的だった。</p>\n<ol>\n<li><code class=\"language-text\">ShareShopi</code> の既存依存を棚卸しし、Supabase が担っていた認証、共有 API、公開リンク、リマインド、保存処理を分解する。</li>\n<li>UI では共通ローダーを追加し、<code class=\"language-text\">loading.tsx</code> とナビゲーションの待機表示をそろえて、移行中でも利用者の体験を安定させる。</li>\n<li>認証では <code class=\"language-text\">firebase-client.ts</code> と <code class=\"language-text\">firebase-token.ts</code> を追加し、クライアントログインとサーバー側トークン検証を分離する。</li>\n<li>データでは D1 migration を追加し、<code class=\"language-text\">lib/d1.ts</code> と API routes を介して共有リスト関連の読み書きを Cloudflare 側へ寄せる。</li>\n<li>build / deploy では <code class=\"language-text\">README.md</code> と <code class=\"language-text\">CLOUDFLARE_MIGRATION.md</code> に、<code class=\"language-text\">npm run cf:build</code>、preview、<code class=\"language-text\">wrangler d1 migrations apply</code>、deploy の順を明示しておく。</li>\n<li>記録では草稿生成スキルの dry-run を確認したうえで、ブログ側の Markdown に対象リポジトリ名、変更箇所、テスト、未実施の release 項目を書き戻す。</li>\n<li>最後に <code class=\"language-text\">validate-content.js</code> で記事契約を確認し、公開に進まない場合でも draft として再利用できる状態にする。</li>\n</ol>\n<p>build と deploy については、この事例の source material では「手順を更新した」ことまでは確認できたが、Cloudflare preview 実行結果や remote migration 完了までは確認できていない。したがって、手順の整備と反映準備は進んだが、最終 release 完了ではない。</p>\n<h2>制約と残課題</h2>\n<p>一番大きい課題は、Supabase が暗黙に持っていた認証・権限・データ責務を、Firebase token 検証と D1 側の API 実装へ明示的に書き戻す必要があったことだ。RLS に寄っていた部分をアプリコード側へ引き取るため、viewer 解決や閲覧権限の境界をコードで説明できる状態にしなければならなかった。</p>\n<p>次の課題は、移行作業そのものよりも記録の精度だった。dry-run 直後の worklog は抽象表現やローカル文脈を含みやすく、そのままでは週次記事に使えない。結果として、ブログ側の記事契約に合わせて毎回人手で具体化し、どこまでテストし、どこから先は未実施かを明記する必要があった。</p>\n<p>もうひとつは、build・deploy・無料運用の境界をドキュメントで揃える難しさである。実装だけ Cloudflare 前提に変わっても、README や migration 手順書が古いままだと、次に触る人が誤った順序で作業しやすい。この事例ではそこまで含めて同日に更新した点が重要だった。</p>\n<h2>次の改善候補</h2>\n<ul>\n<li><code class=\"language-text\">ShareShopi</code> では <code class=\"language-text\">npm test</code>、<code class=\"language-text\">npm run test:e2e</code>、<code class=\"language-text\">npm run cf:build</code> を継続的に通し、D1 移行後の回帰を早めに固定したい。</li>\n<li>Firebase token 検証だけでなく、公開リンク閲覧、共有メンバー権限、リマインド処理まで含む API テストを増やす余地がある。</li>\n<li>Cloudflare preview と remote D1 migration の実行結果を別 worklog として残し、release 手順書を実測ベースで固めたい。</li>\n<li>草稿生成スキル には未解決プレースホルダや抽象語を検出する警告を足し、weekly 記事化の手補正量を下げたい。</li>\n<li>ブログ側では frontmatter 検証に加えて、必要なら draft 記事の build 確認を自動化し、レンダリング崩れも早めに拾えるようにしたい。</li>\n</ul>","excerpt":"2026年06月29日から2026年07月05日にかけては、 という共有買い物リストアプリのリポジトリで、 の UX 改修と Cloudflare 移行を進めつつ、その変更を Gatsby ベースの個人技術ブログへ再利用可能な形で残す運用を整えた。ここでいう  は、Codex セッションログと Git…","frontmatter":{"date":"2026年07月05日","path":"/2026-07-05-weekly-knowledge","title":"ShareShopiのCloudflare移行を再現できる技術記録にする","thumbnail":"/kenRp-blog/assets/image-4.jpg","metaDescription":"ShareShopi の Firebase Auth と Cloudflare D1 移行を題材に、移行手順、検証、記録運用を再現できる形で整理する。","category":"Knowledge","tags":["nextjs","cloudflare","weekly-knowledge"]}}},"pageContext":{"slug":"/2026-07-05-weekly-knowledge"}}}