※この記事は、Claude Codeで1人開発しているSNS運用SaaS「ThreadPost」の開発日記です。
SNS運用を自動化しませんか?
ThreadPostなら、投稿作成・画像生成・スケジュール管理まで全てAIにお任せ。
突然のAPI死。ユーザーを守るための即断即決
Threads APIが突然死んだ。ユーザーに何も伝えないのはまずいから、緊急バナーを出すことにした。直したはずが、まだ被っている。パディングを足した。今度はコンテンツが隠れた。レイアウト順を変えた。スティッキーヘッダーがズレた。バナー1枚でUIが完全に崩壊した。

今週の全体像
今週の総コミットは28件だ。新機能は1件、バグ修正は4件にとどまった。Threadsの障害対応のため緊急バナーを実装した。ただバナーを1枚出すだけのはずが、ヘッダーとの重なり問題で修正の無限ループに陥った。機能実装よりもUIの微調整という泥仕合に時間を吸い取られた。外部APIの死が、フロントエンドのCSS設計の甘さを容赦なく暴き出した。

障害発生。UI防衛戦の幕開け
「00:36 - Threads連携ボタンに障害対応ダイアログを追加」
最初はダイアログで防ごうとした。ユーザーが連携ボタンを押した時にだけ、障害を知らせる仕組みだ。Reactのコンポーネントツリーの末端に、小さな警告を追加した。これで十分だと思っていた。しかし、これじゃ足りない。
ユーザーは予約投稿が動かない理由がわからず、混乱する。SNS連携アプリにおいて、外部APIの死はアプリ全体の死と同義だ。「00:43 - Threads障害ダイアログのメッセージを改善」
予約投稿が利用できないことを明記した。手動で投稿を続けるための臨時ボタンも用意した。本文をクリップボードにコピーさせ、画像は手動で添付するよう案内した。「00:56 - Threads障害時の緊急バナーを追加」
よし、画面の最上部に赤いバナーを出してやる。DashboardLayoutの最上部に固定表示される強烈なバナーだ。PC表示時はサイドバーと被らないよう配置を計算した。閉じるボタンで消せるようにし、状態はlocalStorageに保存した。これなら誰でも気づく。
すぐに対応できる自分に少し酔っていた。画面のトップに固定配置する、ごく単純な実装だ。直後、画面が崩壊した。僕が最初に作ったバナーは、ヘッダーに思いっきり被っていた。「10:52 - 緊急バナーがヘッダーに被る問題を修正」
z-indexを70から30に下げて、ヘッダーの下に配置した。これで解決だと思った。甘かった。「10:55 - 緊急バナーのz-indexとパディングを調整」
今度はサイドバーの下に潜り込んだ。パディングを足したら、メインコンテンツが隠れた。Webのレイアウトは積み木だ。Sticky Headerと固定バナーが混在すると、ブラウザのレンダリング順序が狂う。Stacking Contextという重なり順の概念が牙を剥く。親要素のz-indexが子要素の上限を決める。
ヘッダーがz-40で、サイドバーがz-70。その間でバナーをz-50にねじ込むというパズルが始まった。一般的な企業開発なら、専任のフロントエンドエンジニアが設計規約に則って解決する。Tailwind CSSのユーティリティクラスを、チーム全体で厳密に管理する。1人開発では、勘と総当たりで数値をいじるしかない。「11:06 - 緊急バナー表示時のisVisibleを常にtrueに設定」
アニメーションの状態管理も邪魔をした。バナーの初期値を常に表示状態に固定した。「11:07 - レイアウト順序を修正 - ヘッダー→オレンジバナー→コンテンツ」
ヘッダーを最上部にし、バナーをその下に置いた。ハンバーガーメニューが押せなくなった。バナーが透明なレイヤーとしてメニューの上に覆いかぶさっていた。「11:09 - レイアウト順序をシンプルに - オレンジバナー→ヘッダー→コンテンツ」
もう一度順序を入れ替えた。緊急通知として目立たせるため、バナーを最上部に配置した。今度はスクロール時の挙動がおかしくなった。「11:09 - エマージェンシーバナー表示時のスティッキーヘッダー位置を修正」
バナーが出ている時だけ、ヘッダーの固定位置を40px下にずらすフックを書いた。useEmergencyBannerという専用の状態管理フックまで作る羽目になった。「11:39 - エマージェンシーバナーの高さを明示的に設定」
バナーの高さを2.5remに固定し、iPhoneのノッチ領域であるsafe-area-inset-topも計算に入れた。ヘッダーのtop位置とピクセル単位で一致させた。これでようやく隙間が消えた。緊急バナー1枚の表示に、10回以上のレイアウト調整が必要だった。
文言の調整も泥沼だった。「Threads障害中」とだけ書いたら、Xは使えるのかという問い合わせが来る。「11:08 - 緊急バナーにX正常利用可能の旨を追加」
「Xへの投稿は正常に使えます」を足した。「11:10 - バナーメッセージ「X(Twitter)への投稿は」に修正」
Twitterという旧称を入れないと伝わらないユーザーもいる。「11:16 - Threads障害メッセージから予約投稿の案内を削除」
Web Intent経由では予約投稿ボタンが表示されない。誤解を招く案内を削った。「14:22 - Threads API障害対応の臨時UI実装」
XとThreadsを同時選択しているユーザーには、さらに警告が必要だった。「Xのみに投稿されます」という赤い文字を出した。Threads起動ボタンは、Web Intentで直接アプリを開くようにした。絵文字を含めるとURLエンコードが壊れるため、正規表現で絵文字を除去する処理も書いた。「14:24 - 予約一覧画面にもThreads API障害対応の臨時UI追加」
予約一覧画面の「今すぐ投稿」ボタンも無効化した。文字が多すぎてスマホで2行になり、レイアウトがまた崩れた。「19:50 - お知らせバナーをmarquee表示に変更」
文字を横に流すしかなかった。HTMLの古き良きmarqueeタグの挙動を、CSSのflexboxとアニメーションで再現した。
しんたろー:
12件連続でUI微調整のコミット。そのうち8件がz-indexとパディングの変更。CSSの闇を見た。
復旧後の呪縛。消えないキャッシュとの戦い
「18:10 - Threads API障害対応の臨時コードを削除」
Threadsが復旧した。臨時コードを全部消して、スッキリ終わるはずだった。不要になったEmergencyBannerコンポーネントを非表示にした。連携ブロック処理も消した。disabled属性も全て外した。
僕の画面には、まだ真っ赤な「障害中」のバナーが出ている。嘘だろ。コードは完全に消した。サーバーも再起動した。ブラウザの画像キャッシュが強烈に残っていた。「18:46 - Threads復旧通知バナーと連携情報の論理削除対応」
AnnouncementBannerという汎用のバナーコンポーネントを新設した。緊急用の赤から、情報通知用の青に変更した。スクロール時も固定表示されるようにした。「23:23 - Threads連携復旧通知用の画像を追加」
復旧を知らせるための画像を用意した。しかし、ユーザーの画面には古い障害画像が出続ける。静的アセットのキャッシュ戦略はWeb開発の鬼門だ。ブラウザは一度読み込んだ画像をディスクに保存し、通信を省こうとする。CDNもエッジサーバーに画像を保持し続ける。
企業の大規模サービスなら、ビルド時にファイル名へハッシュ値を自動付与する。WebpackやViteが、一意の名前を自動生成する。CDNのキャッシュパージもCI/CDパイプラインに組み込まれている。僕の環境にはそんな高度な仕組みはない。「23:55 - recovery.pngを再生成」「23:58 - recovery2.pngを追加(キャッシュ対策)」
ファイル名を直接変えるという原始的な手法に頼るしかなかった。recovery.pngからrecovery2.pngへ。さらにthreads-recovery-v1.pngへと名前を変え続けた。コードの削除作業は5分で終わった。CDNやブラウザキャッシュの無効化という見えない壁の突破に、数時間を取られた。HTTPヘッダーのCache-Control設定の甘さが、ここで最悪の形で跳ね返ってきた。
しんたろー:
画像の名前を3回変えた。キャッシュの有効期限を1年に設定していた過去の自分を呪う。
ここまで読んだあなたに
今なら無料で全機能をお試しいただけます。設定後は完全放置でプロ品質の投稿を毎日生成。
落とし穴
バナーのz-indexを調整してヘッダーとの重なりを解消しようとした。z-indexを下げたら今度はサイドバーの下に潜り込み、上げたらヘッダーを突き破り、パディングを変えたらスマホでレイアウトが崩壊した。「バナーを出す」という簡単なはずのタスクが、まるでCSSという名の迷宮で鬼ごっこをしている気分だった。
今日の数字
| 項目 | データ |
|---|---|
| 総コミット数 | 28件 |
| 新機能追加 | 1件 |
| バグ・UI修正 | 4件 |
| z-index調整回数 | 8回 |
| 画像名変更回数 | 3回 |
| 開発時間 | 約1日 |
28回のコミットを約1日で完結させた。企業なら法務の文言チェック、広報の承認、UIレビューを挟み2週間はかかる。僕は1人で即日対応した。本来の機能開発を止めてまで投入した緊急対応コストは重い。しかし、これはユーザーの信頼を守るための必要経費だ。APIの死はコントロールできないが、UIの死はコントロールできる。
しんたろー:
1日の作業時間の9割が緊急対応。本来進めるはずだった新機能の進捗はゼロ。
開発の裏側FAQ
Q: 1人開発で緊急対応の優先順位をどう判断した?
A: 開発が1日遅れるコストよりも、ユーザーが障害に気づかず離脱するコストの方が遥かに大きい。1人で28回のコミットを回し、即日でバナーを出し切った。企業なら数週間かかる対応を数時間で終わらせるのが、1人SaaSの生存戦略だ。
Q: 画像キャッシュが消えない問題は技術的にどう防ぐ?
A: 本来はビルドツールを使ってファイル名に一意のハッシュ値を自動付与するのがベストプラクティスだ。今回は手動でファイル名をv1、v2と変更する泥臭い対応になった。HTTPヘッダーのCache-Controlを適切に設定し、CDNのキャッシュパージを自動化する仕組みが必要になる。
Q: 特定のユーザーだけスキップさせる特例対応は安全?
A: 本番環境に特例コードを直書きするのは技術的負債の最たるものだ。本来はFeature Flagと呼ばれる機能切り替えシステムで安全に制御する。復旧時に消し忘れると深刻なセキュリティホールになるため、即座の削除が鉄則だ。
泥仕合の果てに
外部APIが死ぬと、UI側でこれだけの泥仕合が発生する。

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