EPIC: Mesh v2 拡張機能の実装

概要

GitHub Issue #350 の実装のため、Mesh v2 拡張機能を実装します。既存のMeshと同じブロックとイベント処理を提供しつつ、バックエンドに新しいMesh v2システム(AWS AppSync + GraphQL)を使用します。

背景・目的

抽象的なクライアントである「Node」を「Group」に所属させ、リアルタイムでデータ共有とイベント通知を行うIoTバックエンドシステムを構築します。

システム要件と性能要件

基本要件

  • クライアント: Node (センサー、ブラウザタブ等)
  • データ共有範囲: Group 内に限定
  • データ更新: 項目名と値のペア (値は文字列)
  • イベント通知: 任意のイベント名で発火
  • グループ管理: ホスト (作成者) の退出でグループ解散

性能要件 (ピーク時)

  • 最大 40台 / グループ
  • 同時稼働 10グループ
  • データ更新: 15 回/秒 / グループ
  • イベント通知: 2 回/秒 / グループ
  • 全体書き込み負荷: 170 TPS

システムアーキテクチャ

データ構造とエンティティ

エンティティ 役割 主要フィールド
Group データ共有とイベント通知のスコープ id, name, hostId
Node データを報告・受信する抽象クライアント id, name, groupId
NodeStatus Nodeが報告した最新のデータ集合 nodeId, groupId, data
SensorData 報告される単一のデータ項目 key (マルチバイト可), value (String)
Event Nodeが発火する通知ペイロード name, firedByNodeId, payload

GraphQL操作概要

操作タイプ フィールド名 目的 実装最適化
Mutation (高頻度) reportDataByNode センサーデータをグループに報告 DynamoDB直結 (JS/VTL) で低遅延・低コスト
Mutation (イベント) fireEventByNode グループ内イベントを発火 Noneデータソース、DB書き込み省略
Mutation (管理) createGroup, joinGroup グループの作成と参加 DynamoDB直結
Mutation (管理) leaveGroup グループ退出、ホスト退出時はグループ削除 Lambda でホスト判定ロジック
Subscription onDataUpdateInGroup データ更新をリアルタイム通知 groupId フィルター必須
Subscription onEventInGroup イベント発火をリアルタイム通知 groupId フィルター必須
Query listGroupStatuses, getNodeStatus グループやNodeの現在の状態を取得 DynamoDB PK/SK設計で高速取得

GraphQL スキーマ

スキーマ定義を表示
# --- データの基本構造 ---

input SensorDataInput {
  key: String!
  value: String!
}

type SensorData {
  key: String!
  value: String!
}

# --- 主要エンティティ ---

type Group {
  id: ID!
  name: String!
  hostId: ID! 
  createdAt: AWSDateTime!
}

type Node {
  id: ID!
  name: String!
  groupId: ID 
}

type NodeStatus {
  nodeId: ID!
  groupId: ID!
  data: [SensorData!]! 
  timestamp: AWSDateTime!
}

type Event {
  name: String! 
  firedByNodeId: ID!
  groupId: ID!
  payload: String 
  timestamp: AWSDateTime!
}

type GroupDissolvePayload {
  groupId: ID!
  message: String!
}

# --- クエリ (Queries) ---

type Query {
  getGroup(groupId: ID!): Group
  getNodeStatus(nodeId: ID!): NodeStatus
  listGroupStatuses(groupId: ID!): [NodeStatus!]!
  listNodesInGroup(groupId: ID!): [Node!]!
}

# --- ミューテーション (Mutations) ---

type Mutation {
  # グループ管理
  createGroup(name: String!, hostId: ID!): Group!
  joinGroup(groupId: ID!, nodeId: ID!): Node!
  leaveGroup(groupId: ID!, nodeId: ID!): Node 

  # データ通信
  reportDataByNode(
    groupId: ID!
    nodeId: ID!
    data: [SensorDataInput!]!
  ): NodeStatus!

  fireEventByNode(
    groupId: ID!
    nodeId: ID!
    eventName: String!
    payload: String
  ): Event!
}

# --- サブスクリプション (Subscriptions) ---

type Subscription {
  onDataUpdateInGroup(groupId: ID!): NodeStatus!
    @aws_subscribe(mutations: ["reportDataByNode"])

  onEventInGroup(groupId: ID!): Event!
    @aws_subscribe(mutations: ["fireEventByNode"])

  onGroupDissolve(groupId: ID!): GroupDissolvePayload!
    @aws_subscribe(mutations: ["leaveGroup"])
}

実装コンポーネント

1. gui/smalruby3-gui の修正

  • Mesh v2 拡張機能ブロックの実装
  • 既存のMeshブロックと同じUI/UX
  • バックエンドはMesh v2システム (GraphQL) を使用
  • WebSocket経由でSubscriptionを受信

2. infra/mesh-v2 (新規サブモジュール)

  • AWS CDK (Ruby) でインフラ構築
  • AWS AppSync GraphQL API
  • DynamoDB (オンデマンド課金)
  • Lambda (Ruby 3.2) - 複雑なロジック処理用
  • JavaScript/VTLリゾルバー - 高頻度処理用

DynamoDBテーブル設計

PK (Partition Key) SK (Sort Key) 属性 用途
GROUP#<groupId> METADATA hostId, name グループメタデータ
GROUP#<groupId> NODE#<nodeId> name, statusData Node情報と状態
NODE#<nodeId> METADATA groupId Node所属グループ

技術スタック

  • フロントエンド: React (smalruby3-gui)
  • バックエンドAPI: AWS AppSync (GraphQL)
  • データベース: Amazon DynamoDB
  • リアルタイム通信: AppSync Subscriptions (WebSocket)
  • サーバーレス関数: AWS Lambda (Ruby 3.2)
  • IaC: AWS CDK (Ruby)
  • リゾルバー: AppSync JavaScript / VTL

実装タスク

Phase 0: 既存Mesh拡張機能の調査と分析

Phase 1: インフラストラクチャ基盤

Phase 2: バックエンドロジック

Phase 3: フロントエンド

Phase 4: テストとドキュメント

参考資料

🤖 Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com