ファイル管理を練習で作る — CDK・Docker PostgreSQL・Cognito・S3

はじめに
店舗・支店向けに、Excel や PDF などのファイルをアップロードして共有する Web アプリを、練習プロジェクトとして作ってみました。本番相当のフル構成というより、「認証・ストレージ・DB・インフラ定義を一度つなげてみる」ことが目的です。
この記事では、バックエンド周りの IaC を AWS CDK で書き、データベースは Docker 上の PostgreSQL(RDS は使わない)、認証は Amazon Cognito、ファイル保存は Amazon S3 にした構成を整理します。

全体像
ざっくりした流れは次のとおりです。
- ユーザーは Cognito でサインインする
- ブラウザから Excel / PDF をアップロードする
- API がメタデータを PostgreSQL に保存し、実ファイルは S3 に置く
- インフラ(Cognito、S3、API まわりなど)は CDK で定義する
- PostgreSQL は開発・検証用に Docker Compose で立ち上げる
フロントエンドから見ると「ログイン → ファイル選択 → アップロード → 一覧・ダウンロード」という、店舗業務でよくあるパターンに近い形です。支店ごとに「誰が・いつ・どのファイルを上げたか」を残すイメージで設計しました。
インフラを CDK で書く
バックエンドまわりの AWS リソースは AWS CDK(TypeScript) で管理しています。コンソールで都度クリックするより、スタックとしてコードに残した方が、後から差分レビューしやすいと判断しました。
CDK 側では、例えば次のような単位でスタックやコンストラクトを分けると整理しやすかったです。
- 認証: Cognito User Pool、App Client、(必要なら)Hosted UI やドメイン
- ストレージ: S3 バケット、バケットポリシー、CORS、ライフサイクル(練習段階では最小限)
- API / コンピュート: Lambda + API Gateway、またはコンテナ系(プロジェクトの選び方次第)
- IAM: 各サービス間の権限を明示的に付与
「全部 1 ファイル」にすると変更の影響範囲が読みにくくなるので、認証・ストレージ・API くらいの粒度で分けるのがよさそうです。本番前には cdk diff を習慣にして、意図しない削除や公開設定の変更がないか確認します。
データベース — Docker + PostgreSQL(RDS は使わない)
今回は Amazon RDS は使っていません。理由はシンプルで、まずは ローカルと同等の環境でスキーマと API を固めたい からです。
- Docker Compose で PostgreSQL を起動
- マイグレーションやシードでテーブル定義を試す
- API の CRUD と認可の動きを確認してから、本番用 DB を検討する
練習段階では RDS のコストや VPC・サブネット設計を同時に抱え込まなくてよい、というメリットもあります。代わりに、本番移行時には接続先・バックアップ・マルチ AZ などを別途設計する必要がある ことは頭に入れておきます。
DB には、例えば次のような情報を持たせる想定です(名称はプロジェクト次第)。
- ファイル ID、S3 オブジェクトキー、元ファイル名、MIME タイプ
- アップロードしたユーザー(Cognito の sub など)
- 支店・店舗を表す識別子(ブランチ ID)
- アップロード日時
認証 — Amazon Cognito
店舗向けアプリなので、誰がログインしているか をはっきりさせたいです。認証基盤には Amazon Cognito を使いました。
- User Pool でユーザー管理
- アプリ側は ID トークン / アクセストークンを検証して API を保護
- 未ログイン状態ではアップロード API を受け付けない
Hosted UI を使うか、自前 UI から SRP / OAuth フローで繋ぐかは実装次第ですが、いずれにせよ API Gateway や Lambda の前段で JWT を検証する 形が分かりやすいです。練習では「ログインできる → トークン付きで API が通る」までを最初のマイルストーンにしました。
ファイルアップロード — S3(Excel / PDF)
Excel(.xlsx など)と PDF を対象に、オブジェクトストレージは S3 に置いています。
典型的なパターンは次のどちらかです。
- Presigned URL: クライアントが S3 に直接 PUT し、API はメタデータだけ DB に書く
- API 経由: 一旦 API / Lambda に送り、サーバー側で S3 に保存する
練習では、ファイルサイズや CORS、進捗表示のしやすさを見て 1 か 2 を選ぶとよいです。どちらにしても、バケットはパブリック公開にせず、IAM または Presigned URL でアクセスを絞る前提にしています。
アップロード後は、DB に S3 キーとファイル名を保存し、一覧画面では DB から引いて、ダウンロード時だけ Presigned GET を発行する、という流れが扱いやすかったです。
店舗アプリとしてのユースケース
「支店(ブランチ)」単位で次のような使い方を想定しています。
- 各店舗の担当者が、日次の Excel 集計や PDF 資料をアップロードする
- 本部側は同じプラットフォームから、支店ごとのファイルを確認する
- ファイルの正本は S3、検索・一覧の入口は PostgreSQL
本番では部門・権限ロール(店舗のみ / 本部のみ)を Cognito グループやアプリ側 RBAC で分ける必要が出てきます。今回の練習では、認証済みユーザーがアップロードできる ところまでを優先しました。
つまずきやすい点・次のステップ
練習中にハマりやすかったのは次のあたりです。
- Cognito のリダイレクト URL と CORS の組み合わせ
- S3 CORS と Presigned URL の有効期限・Content-Type
- ローカル PostgreSQL と本番接続文字列の切り替え
今後、本番に近づけるなら次を検討する予定です。
- DB を RDS またはマネージド系に移行し、バックアップ方針を決める
- S3 イベント + ウイルススキャン(ClamAV 等)やファイル種別の制限強化
- CloudWatch Logs / 監査ログで「誰がいつダウンロードしたか」を残す
- CDK で 環境(dev / stg / prod) を分ける
おわりに
CDK でインフラの輪郭をコードにし、Cognito で入口を固め、S3 にファイル、PostgreSQL にメタデータ — という、店舗向けファイル管理アプリの骨格を一通り試せました。RDS をあえて使わず Docker PostgreSQL にしたのは、学習コストを下げてアプリの縦串を先に通す ためです。
同じような構成を検討している方の参考になれば幸いです。詳細なリポジトリ構成やスタック名は、必要になったタイミングで別記事に分けてもよさそうです。



Discussion
No comments yet