主にスキル向上を目的に、ポートフォリオとしてタスク管理アプリ (Miwataru) を作成しました。
これはシングルページアプリケーション (SPA) として作成しており、フロントエンドには、TypeScript / React、バックエンドには、PHP / Laravel、インフラには、Vercel (静的サイト) / AWS Lambda (API) を使用しています。詳細は後述の開発環境 (フロントエンド)、開発環境 (バックエンド)、本番環境をご覧ください。
アプリケーションや実装過程の説明については、以下のリンクからアクセスできます。
- アプリケーション:
https://www.miwataru.com/ - フロントエンド実装過程: https://github.com/zuka-e/laravel-react-task-spa/blob/development/frontend/README.md
- バックエンド実装過程: https://github.com/zuka-e/laravel-react-task-spa/blob/development/backend/README.md
※ 注釈
SPA開発におけるGitHubのリポジトリについて、フロントエンドとバックエンドを同一のリポジトリにする方法と別に作成する方法が考えられますが、今回は同じリポジトリ内で開発を行っています。
ただこの場合GitログやBranchが混同するため、例えばフロントエンド側での記録のみを確認する場合に邪魔になることがあり、その観点ではリポジトリを分割した方が良さそうです。
分割する場合、フロントエンドとバックエンド間に依存関係があると困りますが、今回の場合これは特に問題ありません。バックエンドのサーバーが動作していれば、APIリクエストの確認も行うことが可能です。また、適切なテスト環境が整っていればそれぞれ独自に開発を進めることもできるので、コード自体に相互依存関係はありません。機会があればリポジトリを分割する方法も試行しようと思います。
- 認証
- ログイン / ログアウト
- Cookie / セッション
- ユーザー登録 / 表示 (マイページ) / 更新 / 削除
- メールアドレス認証
- 未認証ユーザー削除 (定期処理)
- ユーザーパスワード更新
- パスワードリセット
- ゲストユーザーログイン (認証済み)
- ゲストユーザー登録 (未認証、ランダムメールアドレス)
- ログイン / ログアウト
- タスク (カード) 管理
- 作成 / 表示 / 更新 / 削除
- リスト (カードグループ) 作成 / 表示 / 更新 / 削除
- ボード (リストグループ) 作成 / 表示 / 更新 / 削除
- 絞り込み
- 並び替え
- 選択型 (日付、昇順 / 降順)
- ドラッグ&ドロップ型
- 状態保持
- 検索
- ページネーション
フロントエンドの開発言語としてTypeScriptを使用し、ライブラリとして使用したのはReactです。またこれらを基本とした開発環境の構築にはCreate React App (CRA)を用いており、これによって、Reactを実行し結果を確認できるサーバーなどのReactの利用に必要な環境が簡単に用意できます。その他実行環境は以下のようになっています。(括弧内の数字はバージョン)
- Create React App (4.0.3)
- Yarn (1.22.10)
- Node.js (16.6.1)
- TypeScript (4.2.4)
- React (17.0.2)
尚、動作確認のブラウザには、Chrome (Mac、Android) を使用しています。
バックエンドの開発言語にはPHP、WebアプリケーションフレームワークにはLaravelを利用しました。開発環境の構築には、Laravelから公式に提供されているLaravel Sailを用いており、これを実行することで開発用のサーバーが起動し、データベースやセッションストアの他、メール送信まで行うことができる環境が整います。
Laravel Sailにデフォルトで用意されている環境はカスタマイズすることも可能ですが、今回は特に変更を行っておらず、構築した環境は以下のようなものです。
- Docker for Mac (3.6.0)
- Laravel Sail (1.4.7)
フロントエンド側で生成された静的ファイルのホスティングサービスとして、Vercelを選択しました。一方、バックエンドで作成したAPIは、AWS Lambdaで実行しています。そこで使用したサービスと用途については以下に列挙した通りです。
- Vercel - 静的ファイルホスティング
- CloudFormation - AWSリソース構成
- Certificate Manager - SSL/TLS 証明書発行 (API用カスタムドメイン)
- API Gateway - API (Lamdba) アクセス
- Lamdba - サーバレスコンピューティング (Laravelアプリ実行)
- VPC - 仮想ネットワーク構成
- VPC Endpoint - VPC内外プライベート接続
- RDS (MariaDB 10.4.13) - RDB
- DynamoDB - キャッシュ、セッションストア
- S3 - アセットストア
- Amazon SES (SMTPインターフェイス) - カスタムドメインメール送信
- IAM (ユーザー、ロール、ポリシー) - アクセス管理
- Systems Manager (パラメータストア) - 機密情報保管
- CloudWatch (ログ, イベント) - ログ管理、Lamdba関数トリガー (Cron)
アプリケーションの基本的な処理の流れとしては以下の通りです。
- ユーザーは、VercelにデプロイされたURLからアプリケーションにアクセス
- APIの機能が必要な場合は、API Gatewayに向かってリクエストを送信
- API Gatewayによって呼ばれたLambdaが以下のような処理を実行
- Cookieの付与、DynamoDBによるセッション管理
- データベースからデータの取得や更新
- 必要に応じてユーザーにメールを送信
- ログをCloudWatchに保存
これを表しているのが以下の図です。
上記で触れていないポイントについて簡潔に説明していきます。
まず図の上部のCloudFormationについて、これは設定ファイルに基づいてAWSリソースの構成が役割です。このとき例えばパスワードなどの秘匿情報が必要となるので、Systems Managerのパラメータストアという機能を用いてその値を安全に扱っています。
次に、Certificate Managerについて、これはカスタムドメインに対するSSL/TLS 証明書の発行を行っています。ここで設定するドメインはブラウザのURL欄に表示されるものではなくそのサブドメインです。ユーザーが直接アクセスするメインのドメインはVercelによって設定を行います。
次に、Lamdbaについて、まず前提として通常LambdaをVPC内に設置しませんが、ここではVPCと共に構成しています。これはRDSとの接続を行うためです。RDSはVPC内に設置されているので、アクセスするためにはパブリックアクセスを有効にするかまたはVPCから行う必要があります。後者の方がセキュリティの観点で優れているため、VPC内でLamdbaを利用しています。
一方、LambdaはDynamoDB及びSESにも接続していますが、これらはRDSとは異なりVPC外のリソースです。通常アクセスするためには、Lambdaのロールに適切なポリシーをアタッチするのですが、VPC Lambdaはインターネットに接続不可能という問題があり、これだけではまだVPCの外に存在するリソースにアクセスできません。そこで、間にEndpointを挟むことでその問題を解決することが可能です。
最後に図の下部に位置しているLambdaについて、これは先述のものとは異なり、APIリクエストによって実行されるのではなくイベントをトリガーとして起動します。ここではスケジュールをイベントとし、指定した時間になると事前に設定した関数を実行する仕組みになっています。
以上が今回構成したインフラの概要です。
参考:
Environment variables - Bref # Secrets
Custom domain names - Bref
Using a database - Bref # Accessing the internet
Cron functions on AWS Lambda - Bref
Laravelでは初めから様々なマイグレーションファイルが用意されています。それらを含めて自動的に生成されたER図は以下のようになりました。
上記の図の内、今回のAPIのために作成したのはusers
と繋がっている部分です。タスクをtask_cards
(カード) という最小単位で扱い、それらの集合がtask_lists
(リスト) となり、task_board
(ボード) は複数のリストを持つという関係になっており、またそれぞれがusers
に所属しています。
尚、ER図の作成には、MySQL Workbenchというツールを用いています。
MySQL Workbenchとは、GUIでデータベースの作成や操作などを行うことができるツールです。機能の一つとして、既存のデータベースの情報を用いてER図を出力することができます。
ER図を作成するにあたって問題に思ったのは、データベースとの不整合が発生する恐れがあることです。先述の通りLaravelにはデフォルトで用意されているデータベースが存在しており、自身で作成していないことから、それらは特に見落としが発生してしまうと考えました。
そこでデータベースの情報からER図を作成する手段を探していた所で、MySQL Workbenchを利用する方法に辿り着き、これによって作成の手間を省きER図とデータベースの整合性を保つことが可能となりました。
- TypeScript (4.2.4) - 開発言語、静的型付け
- React (17.0.2) - SPA構築ライブラリ
- React Router Dom (5.2.0) - ルーティング
- React Helmet Async (1.0.9) - HTMLタグ更新
- Redux (4.1.0) - 状態管理
- React Redux (7.2.4) - 状態管理 (Reactバインディング)
- Redux Toolkit (1.5.1) - 状態管理 (Redux簡便化ツール)
- Marerial-UI (4.11.4) - UIデザインツール
- Axios (0.21.1) - HTTPクライアント
- React Hook Form (7.6.5) - フォーム
- Yup (0.32.9) - スキーマ構築 (バリデーション)
- React DnD (14.0.2) - ドラッグ&ドロップ
- Jest (27.0.4) - テスト
- React Testing Library (27.0.4) - UIテスト
- Mock Service Worker (0.28.2) - APIモック
- markdown-to-jsx (7.1.3) - Markdown
- PHP (8.0.5) - 開発言語
- Laravel (8.32.1) - Webアプリケーションフレームワーク
- MySQL (8.0.23) - RDB (開発環境)
- Redis (6.0.10) - キャッシュ、セッションストア (開発環境)
- MailHog - メール送受信 (開発環境)
- PHPUnit (9.5.2) - テスト
- Telescope (4.4.6) - デバッガー
- Sanctum (2.9.3) - SPA認証 (セッション、CSRF & XSS 防衛)
- Fortify (1.7.8) - 認証用バックエンド (ルーティング、コントローラー etc)
- Bref (1.2.10) - PHP用Lambdaデプロイツール
- Serverless (2.53.1) - サーバレスアプリケーション構成管理
- AWS SDK for PHP (3.188.0) - AWS連携
- Docker - コンテナ管理
- GitHub Actions - CI/CD
入力時バリデーション | 送信時バリデーション |
---|---|
入力時バリデーション | 送信時バリデーション |
---|---|
入力時バリデーション | 送信時バリデーション |
---|---|