※この記事は、Claude Codeで1人開発しているSNS運用SaaS「ThreadPost」の開発日記です。
SNS運用を自動化しませんか?
ThreadPostなら、投稿作成・画像生成・スケジュール管理まで全てAIにお任せ。
核心回答:バグの原因はAIではなくReactの同期ズレだった
同期に戻した。また非同期に戻した。
嘘だろ、これ3回目だぞ。
4コマ漫画の生成機能を実装していて、僕は完全に迷子になっていた。
AIが言うことを聞かない。
指示したはずのキャラクター名が反映されない。
「最近のAIはポンコツになった」と本気で呪っていた。
でも、違った。
全部、僕が書いたコードのせいだった。
今週は4コマ漫画生成機能の安定化に全振りした。
結果から言うと、1週間で49回のコミットを積んだ。
新機能は1件だけ。バグ修正が2件。
あとはひたすら見えない敵との戦いだった。
やろうとしたのは、重たい画像生成処理の非同期化だ。
でも、Reactの状態管理とデータベースの同期という泥沼にハマった。
最終的に動くようにはなった。
代償として、僕の精神力と無駄なAPIトークンがごっそり削られた。

タイムアウトの壁を越えた非同期化
事の発端は、4コマ漫画の生成処理がVercelでタイムアウトして落ちたことだ。
画像生成AIは1枚の生成に平気で十数秒かかる。
4コマ分を直列で作れば、当然サーバーレス関数の制限時間をぶっちぎる。
一般的なHobbyプランなら10秒だ。
Proプランでも設定次第でタイムアウトの壁が立ちはだかる。
企業開発ならここで素直に非同期アーキテクチャを組む。
僕もInngestを使って、処理をバックエンドのジョブキューに逃がした。
ここまでは教科書通りの判断だ。
「fix: 漫画画像生成をInngestのバックグラウンドジョブに移行」
実装は驚くほどスムーズに進んだ。
InngestのSDKを入れ、イベントを発火させるだけで重い処理が裏に回る。
フロントエンドのレスポンスは劇的に速くなった。
ユーザーがボタンを押した瞬間、画面はすぐに次の状態へ遷移する。
裏側ではワーカーが黙々と画像を生成し続けている。
完璧なアーキテクチャを手に入れたと確信した。
ただし、UIのローディング表示は完全に壊れていた。

ジョブを投げた後、フロントエンドは完了を待つ必要がある。
僕はポーリング処理を書いた。
数秒おきにサーバーに「終わった?」と聞きに行く原始的な方法だ。
最初は完璧に動いているように見えた。
しんたろー:
Inngestの導入、マジで一瞬だった。俺天才じゃんって思った。
その後ポーリング処理で地獄を見るとは知らずに。
バックエンドが優秀でも、フロントがポンコツなら意味ないんだよな。
クロージャが引き起こした無限ループ
UIを操作した途端に様子がおかしくなった。
ポーリングが完了フラグを見失う。
何度修正しても、ポーリングが永遠に回り続ける。
AIの生成は終わっているのに、画面はずっとローディングのままだ。
「fix: 漫画画像生成のポーリングタイムアウトバグを修正」
原因はReactのクロージャ問題だった。
非同期関数のスコープ内で、古い状態を握りしめたままループが回っていた。
Reactのレンダリングサイクルは残酷だ。
関数が実行された瞬間の変数の値を、スナップショットのように保存してしまう。
だから、裏でデータベースのフラグが更新されても、ループの中の変数は永遠に古いままになる。
業界標準なら、ここでReact QueryやSWRのようなライブラリに頼る。
キャッシュと同期の複雑な状態管理を、ライブラリ側に丸投げするためだ。
でも僕は自前実装にこだわって、見事に自爆した。
1週間で同じ処理を3回書き直した。
最初は同期、次は非同期、また同期。
最終的な解決策は、すべての状態をuseRefに逃がすという一番ダサい方法だった。
「お前、同じ変数を何回取り違えるんだ」
深夜のモニターに向かって毒づいた。
修正した。また別の場所で同じことが起きた。
セリフを編集したのに、再生成すると古いセリフで上書きされるバグが3箇所から出てきた。
「fix: 4コマ漫画のセリフ編集が反映されない問題を修正」
Reactの状態更新は非同期で行われる。
ユーザーがセリフを書き換えた直後に「再生成」ボタンを押すと、最新のテキストが関数に渡らない。
これもクロージャの罠だ。
結局、すべての重要な状態をuseRefに逃がすことで、やっと無限ループが止まった。
スマートなコードとは程遠い。
でも、画面上のローディングスピナーがピタッと止まり、新しい4コマ漫画が表示された。
これで非同期処理の呪縛から解放されたと思った。
ここからさらに、UIの細部調整という別の沼が待っていた。
「fix: 4コマ漫画の再生成機能改善とUI色分け」
ストーリー編集画面のセクションを色分けした。
場面は紫、背景は緑、構図は橙、キャラは青。
視認性は上がったが、コードの複雑さはさらに増した。
「fix: セリフ再描画のローディング表示と構図の日本語表示を修正」
セリフ再描画中に画像上にローディングオーバーレイを表示した。
ユーザー体験は向上したが、これもまた非同期処理のタイミング問題を引き起こす火種になった。
僕は自分の首を絞め続けていた。
以下のリストは、この期間に直面したエラーの一部だ。
- タイムアウトエラーの誤検知
- 無限ループによるAPIコールの枯渇
- 古いセリフデータによる上書き
- 画面のフリーズとクラッシュ
- 存在しない画像の参照エラー
- コンポーネントの強制アンマウント
これらを一つ一つ潰していく作業は、まさに賽の河原だった。
僕はコードを書いているというより、コードに振り回されていた。
しんたろー:
まじかよ…1週間で3回書き直して行き着いたのがuseRefって。
ダサすぎる。企業ならPRで即リジェクトされるやつ。
でも1人開発なら動けば正義。とりあえず画面は動いてる。
ここまで読んだあなたに
今なら無料で全機能をお試しいただけます。設定後は完全放置でプロ品質の投稿を毎日生成。
落とし穴:存在しないキャラクターの怪談
非同期処理が落ち着いた直後、別の怪奇現象が起きた。
キャラクターの名前を「りょう」から「ごう」に変更した。
当然、AIに渡すプロンプトの指示も「ごう」に書き換えた。
「fix: Stage1プロンプトのキャラ名を修正(りょう→ごう、じいちゃん→おじじ)」
ところが、生成された漫画の画像には、明らかに「りょう」の特徴を持ったキャラが描かれていた。
あるいは、指定したはずのプロンプトが完全に無視された謎の人物が出てくる。
僕はAIを疑った。
「Claude、お前さぁ…プロンプト読んでる?」
プロンプトエンジニアリングの沼に足を踏み入れた。
指示を強くし、英語にし、禁止事項を箇条書きで追加した。
「fix: 漫画Stage2プロンプト改善 - 悩んでるキャラが自分で解決策を言う問題を防止」
「fix: 漫画の「画面外から」表現を禁止」
ルールをガチガチに固めた。
1コマ目で悩みを言ったキャラが、2〜3コマ目で自分で解決策を言うのは不自然だ。
だからそれを禁止するルールを追加した。
それでも「りょう」の亡霊は消えなかった。
数日後、ふとデータベースのログを見て血の気が引いた。
AIに渡っていたデータは、最初から「りょう」だったのだ。
原因は、フロントエンドの状態とデータベースの同期ズレだった。
ユーザーが画面でキャラを変更しても、それがデータベースに保存される前にInngestのジョブが走っていた。
Inngestはデータベースの古い情報を正として読み込み、画像生成AIに渡す。
フロントエンド、データベース、非同期ワーカー。
分散システムにおけるデータ整合性の問題を、僕は甘く見ていた。
企業の大規模システムなら、トランザクション管理や分散ロックで厳密に制御する領域だ。
僕はそれを、Reactの片手間でやろうとしていた。
「fix: 4コマ漫画の手動編集したキャラ・セリフが反映されない問題を修正」
画像生成の直前に、データベースへの同期処理を挟んだ。
同期関数を追加し、書き込み完了を待ってからジョブを投げる。
たった数行のコードだ。
これを追加した途端、「ごう」が正しく描画されるようになった。
AIは最初から完璧に指示に従っていた。
ポンコツだったのは、古いデータを渡し続けていた僕のコードだった。
しんたろー:
Claude、ごめん。お前は完璧だった。
3日間プロンプトこねくり回してた俺がバカみたいじゃん。
ログ見たら一発で分かるのに、なんでAIのせいにしてたんだろ。
「fix: 4コマ漫画のセリフ連続性を改善」
「fix: AIが画像にパネル番号を描かないよう指示を追加」
プロンプトの調整も続けたが、それはあくまで補助的なものだ。
根本的な原因は常にデータの流れにある。
新キャラ4名を追加した時も同じだ。
「fix: 新キャラ4名を追加(まなみ・ゆうき・きよ・こうた)」
キャラクターが増えれば増えるほど、状態管理の複雑さは指数関数的に跳ね上がる。
僕はその現実から目を背けていた。
非同期処理のポーリング完了フラグを、ローカル変数で管理しようとした。
関数の中で変数を定義し、完了したらフラグを立てる。
シンプルで完璧なロジックだと思っていた。
コンポーネントが再レンダリングされるたびに、フラグが初期化された。
Reactは画面を描画し直すたびに、関数の中身を最初から実行する。
当然フラグは毎回リセットされる。
結果、ポーリングが永遠に終わらなくなった。
「fix: ポーリング完了フラグをコンポーネントレベルのRefに移動」
「お前、同じ変数を何回取り違えるんだ」と自分にツッコミを入れながら、またしてもRefに逃げ込んだ。
ローカル変数は信用できない。クロージャも信用できない。
Reactのレンダリングサイクルに翻弄され続ける姿は、まさに敗北の味だった。
企業ならテストコードで一発で弾かれるレベルのミスだ。
でも1人開発では、誰も止めてくれない。
無限ループの代償は、ただ静かにAPIの課金メーターを回し続けるだけだった。
ペルソナ情報と画像生成の微妙なズレがまだ残っている。
「fix: 4コマ漫画生成にペルソナ情報を追加」でジャンル情報を渡すようにした。
でも、AIがそのジャンルをどう解釈するかは完全にブラックボックスだ。
指定した世界観と、出てくる画像のトーンがたまに噛み合わない。
この変数の調整は、また来週以降の課題として放置している。
今日の数字
| 項目 | 今回の数字 | 比較対象 |
|---|---|---|
| コミット数 | 49件 | 普段の週の約2倍 |
| 開発期間 | 1週間 | 企業チームなら2〜3週間の規模 |
| バグ修正 | 2件 | 新機能1件に対して多すぎる |
| APIコール | 150回以上 | 無限ループによる無駄打ち |
個人開発の1週間で49コミットは、標準的な開発速度の約2倍の密度だ。
ずっとコードを書き続けていたわけではない。
同じ場所を壊しては直し、壊しては直しを繰り返した結果の数字だ。
特に痛かったのはAPIコストだ。
AIのAPIトークン消費と、試行錯誤によるポーリング回数の増加。
無限ループで無駄にAIを叩き続けた結果、通常の生成コストより余計にAPI代が溶けた。
具体的な金額は見たくない。
FAQ
なぜAI生成の漫画に「透かし」を入れることにしたの?
生成AIコンテンツの著作権や帰属表示は、今の業界で最もシビアな問題だからだ。
「fix: add watermark to manga panel images」でInngestワークフローに透かし処理を自動で組み込んだ。
後から手動で加工する手間を省きつつ、コンテンツの出所を明確にするための自衛策だ。
画像生成のフォント選定で「明朝体禁止」にした理由は?
画像生成AIは、日本語フォントのレンダリングが絶望的に苦手だからだ。
「fix: 漫画フキダシのフォント指定を改善」で、Arial BlackやImpactなどの太いサンセリフ体を強制した。
明朝体だと文字の細い部分が潰れて読めなくなり、OCR耐性も著しく落ちる。
APIコストが跳ね上がった具体的な原因は?
非同期処理のバグで、生成途中の画像を何度も再リクエストしてしまったからだ。
ポーリングがタイムアウトを誤検知し、裏でAIが動いているのに新しい生成ジョブを投げていた。
1回の生成で済むはずの処理が、バックグラウンドで3〜4回重複して走るという最悪のコストドレインだった。
バグと格闘しながら、少しずつ前に進んでいる。

この記事が参考になったら、ThreadPostを試してみませんか?
投稿作成・画像生成・スケジュール管理まで、全てAIにお任せできます。
ThreadPostをもっと知る