Role C: フロントエンド&3Dモジュール

実装詳細とアーキテクチャ要件

トップページへ戻る

Role Cが担当する「フロントエンド&3Dモジュール」は、保護者が直感的に状況を把握できるUIを提供する役割を担います。「巨大な3Dモデルによるブラウザクラッシュ」や「バックグラウンド時のWebSocket切断」を回避し、モバイル端末でもサクサク動く堅牢なWebアプリケーションを構築する必要があります。
また、Role Bが先行して構築する「モックAPI」と「テストユーザー」を活用し、インフラ層との結合テスト(CORSや認可)を開発初期段階で完了させることが重要です。

1. 開発に必要な環境・情報(準備物)

  • 環境: React, Three.js (@react-three/fiber, @react-three/drei)
  • アセット: Polycam等でスキャンした部屋の3Dモデル(.gltf / .glb形式)
  • 連携情報: Role AからのMQTTトピック名とカメラキャリブレーション行列。Role Bからの履歴取得API URL(モック)、および「Cognito User Pool ID / Client ID」「Identity Pool ID」「IoT Coreエンドポイント」「テストユーザーのID/PASS」。

2. 実装手順と技術的課題の根本解決アプローチ

Step 1: Cognito認証(ログインUI)の実装

目的: プライバシー情報を保護し、認可された保護者のみがダッシュボードを閲覧できるようにする。

  1. aws-amplify のAuthモジュールを用いて、メールアドレスとパスワードによるログイン画面を実装する。
  2. ルーティングを保護し、未ログイン時はダッシュボードへのアクセスを弾きログイン画面へリダイレクトさせる。
  3. ログイン成功後、Amplifyの機能を用いてIdentity PoolからIoT Core接続用の一時クレデンシャルを取得する。

【重要】技術的課題と根本解決:
1. 開発工数の削減: ハッカソンのスピードを優先するため、「新規登録(サインアップ)」や「パスワードリセット」のUI実装は省略します。Role Bから提供されるテスト用アカウントを使用してログイン処理を実装してください。
2. セッションの維持: ページリロード時に毎回ログアウトされないよう、Amplifyのデフォルト機能(LocalStorageへのトークン保存)を正しく活用し、API呼び出し時には Authorization ヘッダにJWTトークン(IDトークン)を付与してください。

Step 2: React + Three.jsによる3D空間の構築

目的: Polycamの3Dモデルをブラウザ上でレンダリングする。

  1. @react-three/fiber をセットアップし、useGLTF フックでモデルを読み込みシーンに配置。OrbitControlsで視点操作を可能にする。

【重要】技術的課題と根本解決:
スキャンした高精細モデルはファイルサイズが大きく、モバイル端末でブラウザがクラッシュします。必ずBlender等で事前にポリゴン数を削減(Decimate)し、テクスチャを圧縮(Draco圧縮等)した軽量な .glb ファイルを使用してください。また、Reactの Suspense を用いてローディングUIを実装しUXの低下を防ぐこと。

Step 3: MQTT over WebSocketの受信

目的: 危険検知アラートをブラウザにリアルタイムでポップアップさせる。

  1. Step 1で取得した一時クレデンシャルでSigV4署名付きURLを生成し、aws-iot-device-sdk-v2 (ブラウザ版) または mqtt.js でIoT CoreにWebSocket接続してトピックをSubscribeする。

【重要】技術的課題と根本解決:
スマホの画面ロックやタブのバックグラウンド化によりWebSocket接続は頻繁に切断されます。切断を検知して自動再接続(Exponential Backoff)を行うロジックを実装し、UI上に「接続中/オフライン」のステータスインジケーターを必ず配置して状態の不整合を防いでください。

Step 4: リアルタイムアラートの3Dマッピング

目的: 受信したアラートの座標を3D空間上に視覚化する。

  1. Role Aから提供されたカメラの内部パラメータ(歪み係数等)と外部パラメータ(3D空間内での位置・姿勢行列)を元に、仮想カメラをThree.jsのシーン内に配置する。
  2. MQTTで受信した2D座標を、逆投影変換またはRaycasterを用いて3D空間の床面座標(X, Y, Z)に変換し、マーカーを描画する。

【重要】技術的課題と根本解決:
2Dから3Dへの変換はカメラの設置角度や画角に依存するため単純な計算ではずれます。必ずRole Aから正確なキャリブレーション行列を受け取り、数学的に正しい射影変換を行うか、Three.jsの Raycaster を用いて仮想カメラから3Dモデルのメッシュに向けてレイを飛ばし、交差判定(Intersection)によって座標を算出してください。

Step 5: 履歴データの可視化とリスクサジェスト

目的: 過去の危険エリアの重畳表示と、AIによる潜在的リスクの提示を行う。

  1. Role BのAPI(JWTトークン付き)から履歴データを取得し、座標データ群を元にヒートマップやパーティクルを生成する。
  2. APIから取得したデータのうち、event_type: "risk_suggestion"(パターン4)のデータを用いて、ダッシュボード上に潜在的リスクの警告(サジェストUIや3D空間上のハイライト)を表示する。

【重要】技術的課題と根本解決:
大量のデータポイントを個別のメッシュとして描画するとドローコールが増大しFPSが著しく低下します。必ずThree.jsの InstancedMesh を使用するか、カスタムシェーダーを用いてGPU側で一括描画するパフォーマンス最適化を行ってください。

Step 6: プロダクションビルドとデプロイ

目的: 完成したWebアプリケーションをAWS環境に公開する。

  1. ViteやWebpack等でReactアプリのプロダクションビルド(npm run build)を実行する。
  2. 生成された静的ファイルを、Role Bが用意したS3バケットにアップロードする。

【重要】技術的課題と根本解決:
React Router等でクライアントサイドルーティングを行っている場合、S3/CloudFront上で直接URLアクセスすると404エラーになります。CloudFrontのエラーページ設定で、404エラー時に /index.html を返しステータスコードを200にするよう、Role Bに設定が完了しているか確認してください。

3. システム共通JSONスキーマと連携ポイント

【重要】APIおよびWebSocketで受信するJSONスキーマが以下に確定しました。 event_type の値を見てポップアップUIを出し分け、ai_hazard の場合は details.x と details.y を用いて3D空間への座標変換を行ってください。

// パターン1: AI推論アラート
{
  "device_id": "mv_camera_01", "room_id": "living_room", "timestamp": 1723307400000, "event_type": "ai_hazard",
  "details": { "hazard_type": "fall", "x": 640, "y": 480, "confidence": 0.85 }
}
// パターン2: Merakiセンサーアラート
{
  "device_id": "mt20_door_01", "room_id": "living_room", "timestamp": 1723307405000, "event_type": "sensor_alert",
  "details": { "sensor_type": "door", "status": "open", "battery_level": 95 }
}
// パターン3: 複合アラート
{
  "device_id": "system_logic_01", "room_id": "living_room", "timestamp": 1723307410000, "event_type": "complex_alert",
  "details": { "alert_type": "night_wandering", "trigger_device": "mt20_door_01", "lux": 5 }
}
// パターン4: 行動パターン解析結果
{
  "device_id": "system_logic_01", "room_id": "living_room", "timestamp": 1723307420000, "event_type": "risk_suggestion",
  "details": { "risk_level": "high", "suggested_area": { "x": 100, "y": 200, "radius": 50 }, "reason": "unusual_access_time" }
}
  • Role Aへ: 3Dマッピングの計算に必要な、カメラの実世界での設置位置(高さ、角度)、画角(FOV)、およびキャリブレーション行列のパラメータを要求します。
  • Role Bへ: CORSエラー発生時の対応、およびCloudFrontのルーティング(404エラー時のindex.htmlフォールバック)設定を依頼します。

4. 早期結合テストと並行開発(モック)アプローチ

Role BのDB設計やRole AのAI推論完了を待つ必要はありません。Role Bが先行して用意する「インフラ(モックAPI)」を利用し、以下の手順でフロントエンドのロジックとUIを完成させつつ、最も厄介なインフラ層の結合テストを終わらせます。

  • CognitoとAPIの早期結合テスト(最優先): Role Bから「テストユーザー」と「モックAPIのURL」をもらい次第、ログインUIを実装します。ログインで得たJWTトークンをヘッダに付与してモックAPIを叩き、「CORSエラーが出ないか」「Cognitoの認可を通ってダミーデータが返ってくるか」を真っ先にテストしてください。
  • ヒートマップの実装: モックAPIから返ってくるダミーの座標データ(JSON)を利用して、3D空間上のヒートマップやパーティクル描画ロジックを作り込みます。
  • MQTTアラートのモック化: IoT CoreからのWebSocket受信の代わりに、setInterval や画面上の「テスト発火ボタン」を用いて、数秒おきにランダムな座標のアラートイベントを発生させ、リアルタイムポップアップのUI挙動をテストします。
  • 環境変数の分離: バックエンドが本番仕様に切り替わった際にコードを書き換えなくて済むよう、エンドポイントURLやCognitoのID群は必ず .env ファイルから読み込む設計にしてください。