サービスは動いている。記事も入っている。Stripeの設定も終わった。あとは公開するだけだ——と思っていたが、公開直後からトラブルが続いた。
この記事は「公開当日に起きたこと」の記録だ。
テスト購入で最初のエラー
ユーザー登録をしてVol.1を購入しようとした。Stripeの決済ページで「4242 4242 4242 4242」(Stripeのテストカード番号)を入力して購入完了。リダイレクトで戻ってきたが、記事が読めなかった。
DBを確認すると purchases テーブルが空だった。Webhookが処理されていなかった。
Stripeのダッシュボードを見ると「422 Unprocessable Entity」エラーが記録されていた。この原因を突き止めるのに2時間かかった(この詳細は前の記事に書いた)。
修正して再送したら正しく処理され、記事が読めるようになった。
購入ボタンを押したら404が返った
次の問題はフロントエンドだった。「この巻を購入」ボタンを押すと /checkout/volume/1 というURLに遷移する。しかしこのURLは「Stripeの決済ページへリダイレクトするAPIエンドポイント」の前にFlastAPIの404エラーが返っていた。
原因はURLのプレフィックスだった。APIエンドポイントは /api/checkout/volume/1 として定義していたが、フロントエンドのリンクは /checkout/volume/1(/api/ なし)だった。
修正は2つの選択肢があった。フロントの全リンクを /api/... に変えるか、サーバー側にリダイレクト用のルートを追加するか。後者の方が変更箇所が少なかったので採用した。
@app.get("/checkout/volume/{volume_no}")
def checkout_volume_page(volume_no: int):
return RedirectResponse(f"/api/checkout/volume/{volume_no}")
こういう「URLの設計ミス」は実際に動かすまで気づかないことが多い。ドキュメントを書いている段階では見えない問題だ。
ポート競合でサービスが再起動を繰り返した
設定変更のたびにサービスを再起動していたら、途中から「Address already in use」というエラーが出続けた。ポート9000がすでに使われているため、新しいプロセスが起動できないというエラーだ。
古いプロセスが終了する前に新しいプロセスが起動しようとして、ループ状態になっていた。
解決策は sudo fuser -k 9000/tcp でポートを使っているプロセスを強制終了してから再起動することだ。これはDX経営ゲームの本番障害対応でも使ったコマンドだ。同じトラブルを別のプロジェクトで踏んだ。
最初の読者が来た瞬間
テスト購入・デバッグを終えて、実際に外部の人に読んでもらえる状態になった。
DX経営ゲームの研修が終わった後、参加者の診断レポート画面に「このゲームの制作過程を公開中——1cto.jp」というバナーを表示した。26名の研修参加者のうち、ゲーム直後の状態でこのバナーを見る人がいる。
「なぜこのゲームが動いているのか」を一番知りたいのは、今日このゲームを体験した人だ。自分でDXに取り組む立場でこのゲームを体験した後、「作った側の記録」を読む動機が最も高い。
研修参加者から1cto.jpへの動線を作ることが、最初の読者を獲得する最短経路だった。
公開当日に学んだこと
システムは「動く」と「使える」が違う。自分でテストして動いていても、実際の購入フローで想定外のエラーが出た。404・422・500・ポート競合——全て公開後数時間以内に踏んだエラーだ。
DX経営ゲームの本番研修でも同じことが起きた。「開始失敗:No companies registered」というエラーが参加者登録前にゲームを開始しようとして発生した。
「本番で何かが起きる」という前提で動き続けることが、システムを運用し続けるための心構えだ。完璧な状態を待って公開するより、動く状態で出して問題を潰していく方が早い。
ただし、金銭に関わる決済の部分は十分にテストしてから出す。ここは例外だ。
*次回は「SEOとAI検索最適化——robots.txt・sitemap・llms.txtをどう設計したか」*
*シンプルシステム株式会社 代表 伊藤勝彦*