推しアイデア
スマホの写真フォルダがそのまま武器になる!AIが出す予測不能なお題に合わせて手持ちの画像を提出 埋もれた「奇跡の一枚」や「黒歴史」で笑い合える新感覚パーティーゲーム!
スマホの写真フォルダがそのまま武器になる!AIが出す予測不能なお題に合わせて手持ちの画像を提出 埋もれた「奇跡の一枚」や「黒歴史」で笑い合える新感覚パーティーゲーム!
ハッカソンのテーマ「Spark」から「火花散るバトル」を連想し、そこに「昔のアルバムを見返す楽しさ」を掛け合わせました
・ Context APIで快適なUX ・ 保守性の高い設計 ・ TerraformとGitHub ActionsでCI/CD











リアルタイムでの通信に使用する 1 つの WebSocket 接続を、アプリ全体で共有できるようにしました。Context API を用いて WebSocket コンテキストとプロバイダーを設計し、ページ遷移における接続の維持を実現しています。
// WebSocketContext - 接続状態と操作を提供 type WebSocketContextType = { status: "idle" | "connecting" | "connected" | "disconnected" | "error"; sendMessage: (data: string) => void; connect: () => void; disconnect: () => void; isReconnecting: boolean; // ... };
WebSocketProvider がルートレイアウトでラップするので、ルーム画面からバトル画面へ遷移しても接続が維持されます。
1 つの WebSocket 接続を複数の用途で容易に使えるよう、専用のフックを用意しました。
バトルの進行状態を「フェーズ」として管理し、各フェーズの開始・終了・タイムアップ時にコールバックを発火させる設計にしました。
type BattlePhase = | "waiting" | "selecting" | "clap_time_1" | "clap_time_2" | "clap_time_3" | "clap_time_4" | "clap_time_5" | "result" | "finished"; // フェーズごとのイベントハンドラ onPhaseStart?: (phase) => void; // フェーズ開始時(演出開始など) onPhaseEnd?: (phase) => void; // フェーズ終了時 onTimeUp?: (phase) => void; // 制限時間終了時
これにより、フェーズ遷移に伴う演出(タイマーリセット、画像切り替えなど)のトリガーが容易になりました。
開発効率を上げるため、WebSocket イベントと REST API を個別にテストできるページを用意しました。ルーム作成からゲーム開始,拍手送信まで一通りの操作をテストでき、WebSocket メッセージや API レスポンスをリアルタイムで確認できます。
これにより、バトル途中の状態からのデバッグや、特定のイベントの動作確認が容易になりました。

通信は用途に応じて WebSocket と REST API を使い分けました。 イベント通知などリアルタイム性が必要なデータ送受信は WebSocket を使用し、 その通知を受けてクライアントは REST API を呼び出してデータを取得することで、リアルタイム性とシンプルさの両立を目指しました。 もう少し具体的に言うと、WebSocket はイベントタイプのみの「何かあったよ」という通知のみを送信し、実際のデータはこのイベントを受けてクライアントが REST によってデータの取得を行うといった感じです。
また、イベント通知などで少し複雑になりそうだったため、シーケンス図やクラス図を作成・設計によって認識の共有を行ってから実装にとりかかりました。



クリーンアーキテクチャに沿って、ドメイン層を中心に据えた設計にしました。 ビジネスルールをドメインに閉じ込めることで、他の層に振り回されない構造を目指しました。
WebSocket のイベント通知周りはイベント駆動で設計しました。 EventDispatcher であるイベントタイプに関連したハンドラーを登録しておき、イベントの発火を検知してハンドラーを呼び出すようにしています。

0 ベースで書くのは初めてでしたが、Terraform にチャレンジしてみました。 AWS のリソースを定義して、コンテナのビルドとデプロイのみは Github Actions での自動化を行いました。
プルリクエストを出すと AI が自動でレビューしてくれるシステムを構築しました。
見落としがちなエラーにも気づけてとても助かりました。(↓寝ぼけてた中助かりました

main ブランチに変更がマージされると、AWS へ自動でビルド・デプロイされます。
