{"componentChunkName":"component---src-templates-blog-template-js","path":"/2026-05-24-weekly-knowledge","result":{"data":{"site":{"siteMetadata":{"title":"KenRp Blog"}},"markdownRemark":{"html":"<p>2026年05月18日から2026年05月24日までのワークログを見返すと、この事例の実装テーマは「共有アプリの体験を、画面・API・テスト・デプロイ準備まで一気通貫で整える」ことだった。中心になったのは <code class=\"language-text\">shared-shopping-app</code> という共有買い物リストアプリで、モバイル UI の刷新、招待リンク API の運用耐性向上、E2E テストの追従、Cloudflare 移行準備が同時に進んでいる。</p>\n<p>あわせて、<code class=\"language-text\">kakei-balance-app</code> という共有家計アプリでは、ゲスト利用中心の MVP を Supabase 連携の共有家計構成へ広げる改修が進み、<code class=\"language-text\">product-service</code> という Spring Boot API では OpenAPI / Swagger UI の導入が進んだ。この事例では別々のリポジトリを触っているようでいて、実際には「状態管理を分離しながら、利用者向け導線と運用者向け確認手段を厚くする」という共通の流れが見えていた。</p>\n<h2>この記事で解決すること</h2>\n<p>共有アプリは UI だけを変えると、招待 API、並び順、テスト、デプロイ準備のどこかに歪みが出やすい。この記事では、次の悩みを解く。</p>\n<ul>\n<li>共有アプリの画面改善を、API とテストの変更から切り離さず進めたい。</li>\n<li>Cloudflare 移行前に、どの層の責務を整理すべきか見たい。</li>\n<li>複数リポジトリの作業を、ひとつの設計判断として読み解きたい。</li>\n</ul>\n<h2>実施した改善</h2>\n<p>週の前半では、<code class=\"language-text\">kakei-balance-app</code> に認証・世帯共有・クラウド保存を足し、IndexedDB に閉じた家計管理から、Supabase を使った共有家計アプリへ拡張する流れが見えた。<code class=\"language-text\">product-service</code> では、Spring Boot アプリに Springdoc を導入し、Swagger UI と API Docs の公開経路を追加して、利用者が仕様確認しやすい状態を作っている。</p>\n<p>週の後半で比重が大きかったのは <code class=\"language-text\">shared-shopping-app</code> だった。モバイル向けのリスト切り替え UI をカルーセル風に作り直し、設定画面やテーマ切り替えも含めて見た目と操作モデルを更新したうえで、招待リンク API のエラーハンドリング、リスト並び順ロジックの共通化、E2E テストの追従、Cloudflare へのデプロイ移行準備までをまとめて進めている。</p>\n<h2>確認できた成果</h2>\n<p>この事例の成果は、単なる UI 改修ではなく、共有アプリを長く運用するための土台を複数層で固めたことにある。</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><code class=\"language-text\">shared-shopping-app</code></td>\n<td>モバイル UI 刷新、招待 API 改善、E2E 更新、Cloudflare 移行整理</td>\n<td>体験改善と運用移行の論点が一つの流れで見える状態になった</td>\n</tr>\n<tr>\n<td><code class=\"language-text\">kakei-balance-app</code></td>\n<td>Supabase 認証、世帯共有、クラウド保存、ダッシュボード拡張</td>\n<td>ゲスト MVP から共有家計アプリへ広げる構造が見えた</td>\n</tr>\n<tr>\n<td><code class=\"language-text\">product-service</code></td>\n<td>Springdoc 導入、Swagger UI / API Docs 設定</td>\n<td>API 利用者が仕様確認しやすい入口を追加できた</td>\n</tr>\n</tbody>\n</table>\n<p>特に <code class=\"language-text\">shared-shopping-app</code> では、UI だけを先に派手に変えるのではなく、並び順ロジックを純関数へ切り出し、招待テーブル未反映時のエラーを API で吸収し、Playwright テストまで追従させている点が良かった。これにより、「見た目が変わった」よりも「変更が継続運用に耐える形になった」と言いやすい。</p>\n<h2>判断と進め方</h2>\n<p>この事例の流れは、ドキュメント整理から始めて API と UI の責務をそろえ、最後にテストとデプロイ準備を合わせる順番だった。<code class=\"language-text\">shared-shopping-app</code> では、まず Cloudflare 移行メモと公開準備を整理し、その後にリスト並び順と招待リンク API を固め、さらにモバイル UI を刷新し、その変化に合わせて E2E を更新している。</p>\n<p>この順番が効いているのは、見た目と運用を別物として扱っていないからだ。招待リンク API のエラー整形や Cloudflare 移行手順の明文化が先にあることで、フロントエンドの見た目改善が「運用時に壊れやすい派手な変更」で終わらず、実際に公開まで持っていきやすい状態になっている。</p>\n<div class=\"gatsby-highlight\" data-language=\"mermaid\"><pre class=\"language-mermaid\"><code class=\"language-mermaid\">flowchart LR\n  A[&quot;shared-shopping-app UI刷新&quot;] --&gt; B[&quot;並び順ロジック共通化&quot;]\n  B --&gt; C[&quot;招待リンクAPIの運用耐性向上&quot;]\n  C --&gt; D[&quot;Playwright E2E追従&quot;]\n  D --&gt; E[&quot;Cloudflare移行準備&quot;]\n  E --&gt; F[&quot;公開前の受け入れ確認&quot;]</code></pre></div>\n<h2>使った技術</h2>\n<p>主役だった <code class=\"language-text\">shared-shopping-app</code> の技術スタックは、<code class=\"language-text\">Next.js 15</code> と <code class=\"language-text\">React 19</code> を土台に、<code class=\"language-text\">TypeScript</code>、<code class=\"language-text\">Supabase</code>、<code class=\"language-text\">Playwright</code>、<code class=\"language-text\">Vitest</code>、<code class=\"language-text\">OpenNext for Cloudflare</code>、<code class=\"language-text\">Wrangler</code> を組み合わせる構成だった。画面側では Client Component を中心にリスト詳細、設定画面、テーマ切り替えを実装し、API 側では Supabase を前提に招待リンクやリスト取得を扱っている。</p>\n<p><code class=\"language-text\">kakei-balance-app</code> では <code class=\"language-text\">Next.js App Router</code> と React Context によるセッション管理、Supabase Auth / Database、IndexedDB ベースのゲスト保存を組み合わせ、ログイン前後で保存先を切り替える二層構成を採っていた。<code class=\"language-text\">product-service</code> は Java の <code class=\"language-text\">Spring Boot 3</code> と <code class=\"language-text\">Maven</code>、そして <code class=\"language-text\">springdoc-openapi</code> による API ドキュメント生成が中心で、こちらは UI ではなく API 自己記述性の改善がテーマだった。</p>\n<p>技術の使い方を見ると、この事例では新技術を増やす週というより、「既存スタックの責務を整理して、ユーザー導線と運用導線を足す週」だったと言える。特にテストとデプロイ関連は、実装そのものと同じくらい重要な層として扱われていた。</p>\n<h2>構成</h2>\n<p><code class=\"language-text\">shared-shopping-app</code> の変更は、UI、API、テスト、デプロイ準備の 4 層がきれいに分かれていた。</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>UI</td>\n<td>リスト閲覧・設定・テーマ切り替え</td>\n<td>カルーセル型のリスト切り替え、プレビュー表示、設定画面整理</td>\n</tr>\n<tr>\n<td>API</td>\n<td>共有リンク発行・一覧取得</td>\n<td>招待テーブル未反映時のエラー整形、並び順ロジックの共通化</td>\n</tr>\n<tr>\n<td>Test</td>\n<td>変更の回帰検知</td>\n<td>Vitest で並び順を固定化、Playwright でゲスト導線と公開ページを検証</td>\n</tr>\n<tr>\n<td>Deploy</td>\n<td>ビルド・プレビュー・本番移行準備</td>\n<td>OpenNext / Wrangler 前提の Cloudflare 移行メモと受け入れ条件整理</td>\n</tr>\n</tbody>\n</table>\n<div class=\"gatsby-highlight\" data-language=\"mermaid\"><pre class=\"language-mermaid\"><code class=\"language-mermaid\">flowchart TD\n  UI[&quot;Next.js UI&lt;br/&gt;list-detail / settings / nav&quot;] --&gt; API[&quot;API Routes&lt;br/&gt;invite / lists&quot;]\n  API --&gt; DB[&quot;Supabase&lt;br/&gt;lists / invites / auth&quot;]\n  UI --&gt; TEST[&quot;Playwright / Vitest&quot;]\n  API --&gt; TEST\n  UI --&gt; DEPLOY[&quot;OpenNext + Cloudflare Workers&quot;]\n  API --&gt; DEPLOY</code></pre></div>\n<p>この構成の良い点は、変更の責務が明確なことだ。並び順のような判断は <code class=\"language-text\">lib/list-order.ts</code> に切り出し、UI の見た目変更と API の取得順序が同じルールを共有する。招待テーブル未反映のような運用差分は API 境界で吸収し、Playwright はユーザー操作の全体像を、Vitest は小さなロジックの正しさをそれぞれ受け持つ。</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>リスト順を <code class=\"language-text\">created_at</code> 基準に統一</td>\n<td><code class=\"language-text\">updated_at</code> 順にする</td>\n<td>モバイルの横スクロール UI で位置が跳ねにくく、認知負荷を下げられる</td>\n</tr>\n<tr>\n<td>招待エラーを API で専用メッセージ化</td>\n<td>Supabase の生エラーをそのまま返す</td>\n<td>スキーマ未反映時の切り分けがしやすく、利用者に不要な内部情報を見せずに済む</td>\n</tr>\n<tr>\n<td>並び順ロジックを純関数化してテスト</td>\n<td>UI 内に埋め込む</td>\n<td>UI と API で同じ規則を再利用しやすく、回帰を小さく検知できる</td>\n</tr>\n<tr>\n<td>Cloudflare 移行を OpenNext 前提で整理</td>\n<td>ホスティングを現状維持する</td>\n<td>App Router 構成を大きく壊さず、Cron や Preview の整理まで視野に入れやすい</td>\n</tr>\n<tr>\n<td><code class=\"language-text\">kakei-balance-app</code> でゲスト保存とクラウド保存を併存</td>\n<td>すぐ全面クラウド移行する</td>\n<td>MVP 利用者を壊さずに共有機能を足せる</td>\n</tr>\n<tr>\n<td><code class=\"language-text\">product-service</code> に Springdoc を導入</td>\n<td>README 手書き運用を続ける</td>\n<td>API 実装とのズレを減らし、利用者の確認コストを下げられる</td>\n</tr>\n</tbody>\n</table>\n<p>この週の判断はどれも保守性寄りだ。新しい基盤へ飛び移る前に、既存コードの責務分離と確認方法を先に作っているので、変更の速度と安全性の両立を狙いやすい。</p>\n<h2>検証結果</h2>\n<p>確認した観点は、UI、API、テスト、移行準備を同じ共有アプリの変更として扱い、各層の確認方法を分けた点にある。確認した主な観点は次の通り。</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\"># Vitest: 並び順ロジック</span>\n<span class=\"token comment\"># Playwright: ゲスト導線と公開ページ</span></code></pre></div>\n<p>API のエラー整形、並び順ロジック、モバイル UI、Cloudflare 移行メモを別々の成果ではなく、公開前の受け入れ条件としてまとめて確認した。</p>\n<h2>導入手順</h2>\n<p>この事例の作業から再利用しやすい導入手順を抜くと、共有アプリ改修は次の順序が扱いやすい。</p>\n<ol>\n<li>対象リポジトリの既存構成を確認し、UI、API、データ、デプロイのどこを変えるかを切り分ける。</li>\n<li>UI を先に触る場合でも、共有リンクや並び順のような基礎ルールは API または純関数へ寄せて、複数画面で共有できる形にする。</li>\n<li>共有機能では、未反映スキーマや権限不足のような運用エラーを API で説明可能なレスポンスへ変換する。</li>\n<li>UI の刷新後は、Vitest のような小さなテストでロジックを固定し、Playwright のようなブラウザテストでゲスト導線、設定画面、公開ページの振る舞いを確認する。</li>\n<li>デプロイ先を変える場合は、コード変更と同時に build、preview、deploy の順序、Secrets、OAuth 設定、Cron の移し替え先まで文書化する。</li>\n<li>本番公開前には、<code class=\"language-text\">build</code>、<code class=\"language-text\">test</code>、<code class=\"language-text\">test:e2e</code>、プレビュー環境確認、共有機能の実機確認を最低ラインとして並べる。</li>\n</ol>\n<p>この事例のワークログでは、テストとビルドのコード追加や運用メモは確認できた一方で、実際の <code class=\"language-text\">npm run build</code> や <code class=\"language-text\">playwright test</code> の実行完了までは確定していない箇所もあった。つまり、導入手順はかなり明確になったが、最終の受け入れ確認は次週の実行タスクとして残っている。</p>\n<h2>制約と残課題</h2>\n<p>一番大きい課題は、UI 改修と運用差分が連動していることだった。<code class=\"language-text\">shared-shopping-app</code> では、見た目の刷新だけならフロントエンドで閉じられるが、招待リンクは Supabase のテーブル反映状況に依存し、Cloudflare 移行は Cron、OAuth、Secret の設定まで巻き込む。そのため、コードができても運用が揃わないと完成しない。</p>\n<p>もう一つの課題は、モバイル最適化された UI の保守だ。カルーセルやテーマ切り替えは体験としては強いが、アクセシビリティ、キーボード操作、E2E の安定性まで考えると、実装直後より運用フェーズの方が難しくなる。<code class=\"language-text\">kakei-balance-app</code> のゲスト保存とクラウド保存の併存も同じで、段階移行は安全だが、分岐が増えるぶんテスト観点は広がる。</p>\n<p><code class=\"language-text\">product-service</code> も小さな変更に見えて、実際には「OpenAPI を出せる」だけでは十分ではない。コントローラ単位の説明やエラーモデルが薄いままだと、Swagger UI があっても利用者体験は半端になる。導入の初期コストより、その後の情報更新をどう続けるかが重要になる。</p>\n<h2>次の改善候補</h2>\n<p><code class=\"language-text\">shared-shopping-app</code> では、まず Cloudflare での <code class=\"language-text\">cf:build</code> と <code class=\"language-text\">cf:preview</code> を実際に通し、Supabase / OAuth / Secret / Cron の設定差分を実環境でつぶすべきだと思う。あわせて、招待リンク生成、2 アカウントでの共有参加、公開ページ閲覧、設定画面操作を E2E シナリオとして固定すると、移行後の回帰監視がしやすい。</p>\n<p><code class=\"language-text\">kakei-balance-app</code> では、ゲストデータからクラウド世帯への移行導線をどう作るかが次の論点になる。保存先を二層にしている設計は現実的だが、利用者が切り替えを意識しなくて済む導線がないと、共有家計アプリとしての完成度が上がりにくい。</p>\n<p><code class=\"language-text\">product-service</code> では、Swagger UI を入口にとどめず、エンドポイント説明、レスポンス例、エラー仕様まで育てると、外部利用者にとっての価値が一段上がる。この事例では「見える化」の入口ができた段階なので、次は「使える仕様書」に寄せるのが自然だ。</p>","excerpt":"2026年05月18日から2026年05月24日までのワークログを見返すと、この事例の実装テーマは「共有アプリの体験を、画面・API・テスト・デプロイ準備まで一気通貫で整える」ことだった。中心になったのは  という共有買い物リストアプリで、モバイル UI の刷新、招待リンク API の運用耐性向上、E2E…","frontmatter":{"date":"2026年05月24日","path":"/2026-05-24-weekly-knowledge","title":"共有アプリのUI・API・テスト・デプロイ準備を崩さず進める","thumbnail":"/kenRp-blog/assets/image-4.jpg","metaDescription":"共有買い物リストと共有家計アプリを題材に、UI改善、API境界、テスト、Cloudflare移行準備を同時に進める判断を整理する。","category":"Knowledge","tags":["nextjs","cloudflare","weekly-knowledge"]}}},"pageContext":{"slug":"/2026-05-24-weekly-knowledge"}}}