「Twins Blog」をゼロから作り、AWS Amplify Hostingで本番公開するまでの記録です。開発はClaude Codeとの対話形式で進めました。

技術スタック

  • Next.js 14(App Router)+ TypeScript
  • データストア: AWS DynamoDB(on-demand課金)
  • 画像: AWS S3
  • 認証: next-auth(Google OAuth)
  • ホスティング: AWS Amplify Hosting(WEB_COMPUTE/SSR)
  • リッチテキストエディタ: Tiptap

権限体系とデータベース機能

最初に固めたのは「閲覧ユーザー/編集ユーザー/管理者」の3階層の権限モデルです。管理者は環境変数ADMIN_EMAILSでのみ付与し、Webフォームからの自己昇格を防止。編集ユーザーは管理者が/admin/usersから追加する方式にしました。

あわせて、記事に「カラムを自由に定義できる表」を1つ添付できるデータベース機能を実装。テキスト・数値・選択肢・評価(★)の4種類の列を組み合わせられるようにし、この仕組みは後にレビューサイト機能の土台にもなりました。

公開状態の3段階化

記事は常に「非公開(下書き)」で作成され、管理者だけが「会員限定公開」「全体公開」に切り替えられる仕組みからスタート。後に、編集ユーザーも自分で「会員限定公開」までは切り替えられるように拡張し、「全体公開」だけは管理者の承認制として残しました。

Twins Home(会員限定エリア)

編集ユーザー以上(会員)だけがアクセスできる/friendsを新設し、イベント機能(作成・参加表明・「今遊びたい」アラーム)と、映画・書籍・イベント・ボードゲームの4カテゴリーを扱うレビューサイトを追加しました。URL構成も/blog(ブログ本体)と/friends(会員限定)の2領域に整理しています。

開発環境と本番環境の分離

ログイン不要でロールを切り替えられる「DEV ROLE」という開発用の仕組みがありますが、これはNODE_ENV=productionのときは常に無効化されるよう二重の安全策を組み込みました。あわせて、.env.local/.env.development.local/.env.production.localの3ファイルに設定を分割し、開発用DynamoDBテーブル(末尾にDevが付いた別テーブル)を用意することで、ローカルでの動作確認が本番の実データに影響しないようにしました。

本番デプロイでハマった話

AWS Amplify Hostingへの初回デプロイでは、環境変数を正しく設定したはずなのに本番の実行環境(SSR)ではprocess.envから一切読めず、NextAuthが「server configuration」エラーを返し続けるという問題に長時間ハマりました。

調査の結果、これはAmplify Hostingの仕様で、コンソール/APIで設定した環境変数はビルド時のみ有効で、Next.jsのサーバーコンポーネント実行時には既定でアクセスできない、という意図的な挙動でした(ビルド時にしか使わない機密情報を保護するための設計とのこと)。

対処法は、amplify.ymlのビルドコマンドで、必要な環境変数を明示的に.env.productionファイルへ書き出しておくこと。これによりNext.jsのビルド成果物に変数が組み込まれ、SSR実行時にも参照できるようになります。

env | grep -E '^(NEXTAUTH_SECRET|...)=' >> .env.production

あわせて、DynamoDB/S3へのアクセスはアクセスキーではなくAmplify Hostingの「SSR Compute role」(IAMロール)経由にすることで、認証情報を環境変数に直接置かずに済むようにしています。

アクセス解析

Google Analytics 4の計測タグは、本番ビルドかつ測定IDが設定されているときだけ読み込むようにして、開発中のアクセスで実データを汚さないようにしました。

今後やってみたいこと

  • 閲覧数の記録(将来的なアフィリエイト化を見据えて)
  • 独自ドメインの設定

この記事自体、Claude Codeとの対話ログをもとに振り返りとして書いたものです。