AmplifyでNext.jsをデプロイしたときの備忘録

2025年8月17日

Amplify基本知識

Amplifyとは

サーバーレスなアプリケーションの効率的な開発が可能なフレームワーク

サーバーレスということで、基盤となるサーバー、ミドルウェアをAWSが行う、「バックエンドをAPI化」するイメージ

Gen1とGen2

Gen1

Amplify CLIで対話的に実行

現在はGen2で新規作成が推奨ですが、作成自体はまだ可能です

Gen2(Gen2は2024年5月~)

対話形式からCDK方式になりました

TypeScriptでAmazon DynamoDBやAWS AppSyncなど記述が可能に

// amplify/auth/resource.ts
import { defineAuth } from '@aws-amplify/backend';

export const auth = defineAuth({
  loginWith: {
    email: true,
  },
});

Amplify Docs - AWS Amplify Gen 2 Documentation

AWS Amplify Docs - Develop and deploy cl…
docs.amplify.aws

チュートリアル

今回のプロジェクト概要

要件定義

依頼主との要望のすり合わせ

  • 要望
    • 依頼主が実現したい事
  • 要件
    • 要望をリスト化
  • 仕様
    • 要件をみたすためのプログラム

  • 前提
    • 社内ネットワーク
    • Transcribe
    • 音声形式はmp3、wav
  • ユーザーストーリー
US-01音声データ(長さは10分前後)複数ファイル(20~30)を一括で文字おこし
US-02「Aという問いかけをしているか」というようないくつかの項目をそれぞれの音声ファイルごとに確認する
US-03US-02のAのようなキーワードはユーザー側で動的に変更できる仕様

  • 受け入れ基準

テストケース

AC-01
AC-02
AC-03
著名URLでS3へPUT

基本設計

全体アーキテクチャ

  • フロントエンド(Next.js):ファイル選択→アップロード→起動→進捗→結果表示
  • API(Next.js Route or Lambda)
    • /api/presigned-url:S3 PUTの署名URL発行
    • /api/transcribe/start:Transcribeジョブ起動
    • /api/transcribe/status:ジョブ状態取得&結果整形
  • S3uploads/(入力)、transcribe/(出力)
  • IAM:署名発行・Transcribe実行を最小権限に分離

データフロー(概念)

  1. FE → /api/presigned-url → 署名URL取得
  2. FE → S3(署名URL) PUT
  3. FE → /api/transcribe/start → ジョブ起動
  4. FE → /api/transcribe/status(5秒間隔)→ 完了/失敗判定
  5. FE ← 整形テキスト表示

バケット/CORS/ポリシー方針

  • バケット:public/uploads/YYYY/MM/dd/{uuid}-{safeName}、出力:transcribe/{jobName}/result.json
  • CORS(最小):PUT, GET/必要ヘッダ(Content-Typex-amz-*
  • バケットポリシー:署名前提、公開許可なし

画面設計

  • A. ファイル選択/一覧(重複検知、サイズ表示)
  • B. アップロード/進捗(Uploading/Processing/Completed/Failedバッジ)
  • C. 結果ビュー(コピー/ダウンロード、注意書き)

詳細設計

API仕様

POST /api/presigned-url

Req

{ "fileName": "sample.m4a", "contentType": "audio/m4a" }

Res

{ "url": "https://...X-Amz-Signature=...", "bucket": "<BUCKET>", "key": "public/uploads/2025/08/22/<uuid>-sample.m4a" }

制約:有効期限60秒、1回使用想定


POST /api/transcribe/start

Req

{ "bucket": "<BUCKET>", "key": "public/uploads/...", "languageCode": "ja-JP", "mediaFormat": "mp3|mp4|wav", "jobName": "tr-<epoch>-<shortid>" }

Res

{ "job": { "TranscriptionJobName": "tr-169..." } }

備考mediaFormatは拡張子から推定(m4a→mp4


GET /api/transcribe/status?jobName=...&showTimestamp=true&showSpeaker=true

Res

{
"status": "QUEUED|IN_PROGRESS|COMPLETED|FAILED",
"formattedTranscript": "...",
"segmentsCount": 12,
"speakersCount": 2,
"error": null
}

ポーリング:5秒

エラーモデル

{ “code”: “SIGN_URL_EXPIRED|PUT_FAILED|TRANSCRIBE_START_FAILED|STATUS_FETCH_FAILED”, “message”: “…”, “requestId”: “…” }

フロント実装要点

  • 重複排除キー:name-size-lastModified
  • 非同期キューでアップロード→起動→監視を連結
  • UI状態:idle|uploading|processing|completed|failed
  • アップロード前に input.value = '' で同名ファイル再選択可

S3命名規約/ライフサイクル

  • 入力:public/uploads/{YYYY}/{MM}/{dd}/{uuid}-{safeFileName}
  • 出力:transcribe/{jobName}/result.json
  • ライフサイクル例:uploads=30日、transcribe=90日 で Expiration

IAM最小権限(例・要調整)

  • 署名発行ロール:s3:PutObject(対象バケット/public/uploads/* に限定)
  • Transcribe実行ロール:transcribe:*(必要最小)、s3:GetObject(入力)、s3:PutObject(出力)

テスト観点(抜粋)

正常系
  • 1件/10件でアップロード→起動→完了
  • mp3/m4a/wav 各形式で成功
  • 署名期限内にPUT成功
例外系
  • 署名期限切れでPUT→403
  • Transcribe起動失敗(不正形式/権限不足)
  • ステータス取得失敗時のUIエラー表示

運用・監視

  • ログ項目:requestId, userId(optional), fileKey, jobName, latencyMs, status, errorCode
  • ダッシュボード:成功率/平均処理時間/失敗率、長尺上位
  • アラート:連続失敗、署名発行失敗率、Transcribe失敗率

ブートストラップが原因でビルド失敗

ビルド失敗
Bootstrap stack version parameter failed to load.

原因
Amplify Gen2がCDKを使用
CDKの事前準備(ブートストラップ)が未実行または不完全

対応方法
bashcdk bootstrap aws://アカウントID/リージョン

CloudShellエラーが発生
エラー内容

「環境を作成できません」
VPCまたはパブリック環境を作成するための権限が不十分
環境が既に存在しない可能性

対処法

ポリシー名必要な理由
AdministratorAccess-AmplifyAmplifyアプリの作成・管理・デプロイに必要
AmazonBedrockFullAccessAI機能(文章生成・要約等)でBedrockを使用
AmazonS3FullAccess音声ファイルのアップロード・保存に必要
AmazonTextractFullAccess文書のOCR・テキスト抽出機能で使用
AmazonTranscribeFullAccess音声の文字起こし機能で使用
CloudWatchLogsReadOnlyAccessCloudWatch → ログ → ロググループ にアクセスできるようになります
IAMFullAccessCDK Bootstrapでロール・ポリシー作成に必要

CDKがLambda実行ロール作成時に、S3・Transcribe・Bedrock等へのアクセス権限を付与するため
※Next.jsのAPIルート(/api/transcribe/upload)はLambda関数として実行
CloudFormationFullAccessCDKCDK Bootstrap時
CDKスタック作成
npx ampx pipeline-deployがAmplifyサービス経由で実行(ユーザーは直接CloudFormation等を呼ばない)
AmazonEC2ContainerRegistryFullAccessCDK Bootstrap時ECR
リポジトリ作成
npx ampx pipeline-deployがAmplifyサービス経由で実行(ユーザーは直接CloudFormation等を呼ばない)
AmazonSSMFullAccessCDKBootstrap時SSM
パラメータ作成
npx ampx pipeline-deployがAmplifyサービス経由で実行(ユーザーは直接CloudFormation等を呼ばない)

Amplify アプリケーションのビルド設定の構成 - AWS Amplify ホスティング

Amplify ホスティングでデプロイされたアプリのビルド設定を構成し、編集する…
docs.aws.amazon.com

Amplify の一般的な問題のトラブルシューティング - AWS Amplify ホスティング

Amplify ホスティングにデプロイされたアプリケーションで発生する一般的な問…
docs.aws.amazon.com

アップロードサイズ制限

AWS Lambdaは6MB制限 はNext.js: デフォルト1MB

大きなサイズのファイルアップロードは通常のAPI経由では処理不可能です。

対処法

A) Presigned URL(PUT)

AWS S3に直接アップロードする最も一般的な方法です。

S3 は通常 IAM ユーザーのみ利用可能ですが、サーバー側で一時的に有効な署名付きURLを発行し、認証情報(AWSのアクセスキーやシークレットキー)を直接公開せずに、クライアントがそのURLにファイルを送信します。

APIやLambdaのサイズ制限を回避でき、セキュアかつ大容量ファイルに対応可能です。Next.jsや他フレームワークでも広く採用される標準的な構成です。

Use signed URLs - Amazon CloudFront

Describes the basics for using signed UR…
docs.aws.amazon.com

▼ 視覚的に分かりやすい

The illustrated guide to S3 pre-signed URLs - fourTheorem

S3 pre-signed URLs can be used to easily…
fourtheorem.com
ブラウザ → API (Presigned URL取得) → 直接S3アップロード → Transcribe
  • YouTube: 直接Google Cloud Storage
  • Zoom: 直接S3アップロード
  • Spotify: 直接S3アップロード
npm install @aws-sdk/s3-request-presigner

B) Amplify Storage(uploadData)

Amplifyを利用する場合に最短で導入できる方法です。uploadData を呼ぶだけでブラウザから直接S3にアップロードでき、進捗イベントや中断・再開などの機能も標準で利用可能です。複雑な署名URL処理やCORS設定を意識せずに済み、Amplify中心の開発環境では実装効率が高いのが特長です。

Presigned URLを内部的にAmplifyが処理してくれる

npm i aws-amplify @aws-amplify/storage
npx ampx sandbox