Phase 1-2: DynamoDBテーブルの設計と実装
目的
Mesh v2システムのデータ永続化層としてDynamoDBテーブルを設計・実装します。Domain概念を導入し、グローバルIPベースのスコープ管理を実現します。
設計要件
Domain概念
- グループIDの正式名:
{group_id}@{domain} - Domain: グローバルIP(自動)または任意文字列(手動指定、最大256文字)
- 検索スコープ: 同一domain内のグループのみリストアップ可能
タスク
テーブル設計
- Domain対応のPK/SK設計
PK: DOMAIN#{domain},SK: GROUP#{group_id}#METADATA- グループメタデータPK: DOMAIN#{domain},SK: GROUP#{group_id}#NODE#{node_id}- Node情報PK: NODE#{node_id},SK: METADATA- Node所属情報
- 属性定義
- Group:
id,domain,fullId,name,hostId,createdAt - Node:
id,name,groupId,domain - NodeStatus:
nodeId,groupId,domain,data,timestamp
- Group:
- GSI設計
- GSI-PK:
GROUP#{group_id}, GSI-SK:DOMAIN#{domain}- グループID逆引き
- GSI-PK:
CDK実装
- DynamoDB Table リソースの定義
- 課金モード: PAY_PER_REQUEST (オンデマンド)
- GSIの定義
- RemovalPolicy設定 (開発環境: DESTROY)
バリデーション
- Domain文字列の最大長: 256文字
- 許可文字: 英数字、記号、マルチバイト文字
テスト
- テーブル作成の動作確認
- PK/SK設計の妥当性検証
- Domain検索の動作確認
成果物
- DynamoDBテーブル定義コード (
lib/mesh_v2_stack.rb) - デプロイ可能なStack
テーブル設計詳細
メインテーブル
グループメタデータ
PK: DOMAIN#{domain}
SK: GROUP#{group_id}#METADATA
属性:
- id (String): group_id部分
- domain (String): domain部分(最大256文字)
- fullId (String): {group_id}@{domain}
- name (String): グループ名
- hostId (String): ホストのnodeId
- createdAt (String): ISO8601形式のタイムスタンプ
例:
PK: DOMAIN#203.0.113.1
SK: GROUP#abc123#METADATA
id: abc123
domain: 203.0.113.1
fullId: abc123@203.0.113.1
name: My Group
hostId: node_001
createdAt: 2025-01-15T12:00:00Z
Node情報と状態
PK: DOMAIN#{domain}
SK: GROUP#{group_id}#NODE#{node_id}
属性:
- nodeId (String): nodeId
- groupId (String): groupId
- domain (String): domain
- name (String): Node名
- data (List): SensorData配列
- M: {key: String, value: String}
- timestamp (String): 最終更新時刻
例:
PK: DOMAIN#203.0.113.1
SK: GROUP#abc123#NODE#node_001
nodeId: node_001
groupId: abc123
domain: 203.0.113.1
name: Node 1
data: [
{key: "temperature", value: "25"},
{key: "humidity", value: "60"}
]
timestamp: 2025-01-15T12:05:00Z
Node所属情報
PK: NODE#{node_id}
SK: METADATA
属性:
- nodeId (String): nodeId
- groupId (String): 所属しているgroupId
- domain (String): 所属しているdomain
例:
PK: NODE#node_001
SK: METADATA
nodeId: node_001
groupId: abc123
domain: 203.0.113.1
GSI (Global Secondary Index)
名前: GroupIdIndex
GSI-PK: GROUP#{group_id}
GSI-SK: DOMAIN#{domain}
用途: グループIDからdomain逆引き
例:
GSI-PK: GROUP#abc123
GSI-SK: DOMAIN#203.0.113.1
アクセスパターン
| 操作 | アクセス方法 |
|---|---|
| Domain内のグループ一覧取得 | Query: PK = DOMAIN#{domain}, SK begins_with GROUP# |
| グループメタデータ取得 | GetItem: PK = DOMAIN#{domain}, SK = GROUP#{group_id}#METADATA |
| グループ内のNode一覧取得 | Query: PK = DOMAIN#{domain}, SK begins_with GROUP#{group_id}#NODE# |
| NodeStatus取得 | GetItem: PK = DOMAIN#{domain}, SK = GROUP#{group_id}#NODE#{node_id} |
| Node所属グループ取得 | GetItem: PK = NODE#{node_id}, SK = METADATA |
| グループID逆引き | Query GSI: GSI-PK = GROUP#{group_id} |
技術仕様
Ruby CDK実装例
# lib/mesh_v2_stack.rb (一部抜粋) # DynamoDB テーブル定義 iot_table = AwsCdkLib::AwsDynamodb::Table.new(self, 'MeshV2Table', partition_key: { name: 'pk', type: AwsCdkLib::AwsDynamodb::AttributeType::STRING }, sort_key: { name: 'sk', type: AwsCdkLib::AwsDynamodb::AttributeType::STRING }, billing_mode: AwsCdkLib::AwsDynamodb::BillingMode::PAY_PER_REQUEST, removal_policy: AwsCdkLib::Core::RemovalPolicy::DESTROY # 開発環境用 ) # GSI: グループID逆引き用 iot_table.add_global_secondary_index( index_name: 'GroupIdIndex', partition_key: { name: 'gsi_pk', type: AwsCdkLib::AwsDynamodb::AttributeType::STRING }, sort_key: { name: 'gsi_sk', type: AwsCdkLib::AwsDynamodb::AttributeType::STRING }, projection_type: AwsCdkLib::AwsDynamodb::ProjectionType::ALL ) # DynamoDB データソース dynamo_ds = api.add_dynamo_db_data_source('DynamoDataSource', table: iot_table )
関連
- EPIC Issue: EPIC: Mesh v2 拡張機能の実装 #444
- Phase: 1 (インフラストラクチャ基盤)
- 依存: Phase 1-1: infra/mesh-v2リポジトリのセットアップとCDK基本構成 #446 (Phase 1-1)
- 更新: Domain概念の導入(Phase 0レビューフィードバック)
🤖 Generated with Claude Code
Co-Authored-By: Claude noreply@anthropic.com