Platform City

City Guide / 使い方

DynamoDB にデータを保存する

Platform City では、ゲームのスコアや投稿など、再デプロイ後も残したいデータを DynamoDB に保存できます。市民登録時にテナント専用のテーブルが1つ自動で用意されるため、AWS アカウントの作成やデータベースの利用申請は不要です。

エージェントに伝える

開発中のプロジェクトで、保存したい内容をエージェントに伝えてください。

このゲームのスコアを Platform City が用意する DynamoDB に保存し、参加者共通のランキングを表示して。
City Guide の「DynamoDB にデータを保存する」と AGENTS.md を読んで実装して。
再デプロイ後もスコアが残ることを確認して。

MCP Resources を読めるエージェントは platform-city://guide/database からもこの手順を取得できます。

サーバー側から使う

DynamoDB に接続するのは、Platform City にデプロイしたアプリの サーバー側の処理です。ブラウザーの JavaScript から直接接続するための AWS 認証情報は配布していません。画面はアプリの API を呼び、その API がデータを読み書きします。

  • game / oshi / food の雛形は静的サイトです。データを保存する場合は、Dockerfile とアプリにサーバー処理を追加できます。ポート 8080/healthz/health、非 root での起動、CI のデプロイ手順を維持してください。
  • api の雛形にはサーバーがあるため、既存の処理にデータの読み書きを追加できます。新しく保存用 API を作る場合は API・Cloud Native 実験区画に建てる を参照してください。
  • self-intro は静的サイトのチュートリアルです。共有データを使う機能は api などの別アプリに作り、自己紹介ページからその公開 HTTPS API を呼び出す形で進めてください。

接続に使う値

項目使う値・方法
テーブル名デプロイ先のアプリに渡される環境変数 DYNAMODB_TABLE。名前を推測・固定しません
リージョンap-northeast-1
AWS 認証Pod Identity 対応 SDK の標準認証チェーン。アクセスキーを設定する必要はありません
パーティションキーpk(文字列)
ソートキーsk(文字列)
テーブルの共有範囲同じテナントのアプリで1テーブルを共有します。アプリごとにテーブルが増えるわけではありません

pksk は両方必要です。たとえば pk: "my-game#scores"sk: "player#demo" のように、キーに自分のアプリ名を含めて他のアプリのデータと分けます。同じテナント内で意図的にデータを共有する場合は、キーとデータ形式を揃えてください。

SDK の依存バージョンは固定し、Pod Identity 対応版を使います。アクセスキーや Platform City のテナントトークンを SDK に渡したり、ブラウザーへ埋め込んだりしないでください。

Node.js の実装例

サーバー側の依存関係に AWS SDK を追加し、package.json とロックファイルをコミットします。

npm install --save-exact @aws-sdk/client-dynamodb@3.1104.0 @aws-sdk/lib-dynamodb@3.1104.0

次は ES Modules の保存・取得処理です。my-game は自分のアプリ名に置き換え、アプリの API ハンドラーから呼び出してください。

import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient, PutCommand, GetCommand } from '@aws-sdk/lib-dynamodb';

const db = DynamoDBDocumentClient.from(
  new DynamoDBClient({ region: 'ap-northeast-1' }),
);

function tableName() {
  const name = process.env.DYNAMODB_TABLE;
  if (!name) throw new Error('DYNAMODB_TABLE is not configured');
  return name;
}

export async function saveScore(playerId, score) {
  await db.send(new PutCommand({
    TableName: tableName(),
    Item: { pk: 'my-game#scores', sk: 'player#' + playerId, score },
  }));
}

export async function loadScore(playerId) {
  const result = await db.send(new GetCommand({
    TableName: tableName(),
    Key: { pk: 'my-game#scores', sk: 'player#' + playerId },
    ConsistentRead: true,
  }));
  return result.Item?.score ?? null;
}

この例はプレイヤーごとの最新スコアを上書き保存します。ランキング全体の取得や最高記録だけの更新は、ゲームの仕様に合わせて Query や条件付き更新で実装してください。公開 API の入力検証や利用者の認証はアプリ側で行います。

ローカルと CI での確認

手元の PC と GitLab CI には、本番の DYNAMODB_TABLE や Pod Identity の認証情報は自動で渡りません。保存処理を差し替えられる形にし、ローカルと CI はモックやテスト用ストアで検証してください。AWS の接続やテーブル作成を、イメージのビルドや /healthz/health の実行に組み込まないでください。

デプロイ後は、公開 API 経由でテストデータを保存・取得し、通常の CI で再デプロイしても取得できることを確認します。メモリだけの保存やブラウザーの localStorage は、参加者共通の永続ストアにはなりません。本番で接続に失敗した場合に、黙ってメモリ保存へ切り替えないでください。

使える操作と困ったとき

自テナントのテーブルに対するデータの読み書き・削除、Query、Scan、Batch、トランザクション、DescribeTable を利用できます。テーブルの作成・削除・設定変更、インデックスや TTL 設定の変更、テーブル一覧の取得、他テナントのテーブルや他の AWS サービスへの操作は許可されていません。テーブルを作るコードや追加の権限設定は不要です。

症状確認すること
DYNAMODB_TABLE がないローカルや CI で本番へ接続しようとしていないか確認します。デプロイ済みなら logs で設定不足を調べ、テナント名とアプリ名を添えて運営へ問い合わせます
認証情報を取得できないサーバー側で実行しているか、SDK が Pod Identity 対応版か、独自の認証設定で標準認証を上書きしていないか確認します
AccessDeniedExceptionDYNAMODB_TABLE、リージョン、許可されたデータ操作かを確認します。権限の追加やテーブル作成で回避しないでください
ResourceNotFoundExceptionテーブル名とリージョンを確認します。市民登録直後は準備が終わるまで少し待ち、続く場合は運営へ問い合わせます
キーの形式エラーpksk を両方、文字列で渡しているか確認します
throttlingSDK のバックオフ付きリトライを使い、同時要求を減らします。毎回の全件 Scan を避け、用途に合うキーで Query します

アプリのログは MCP の logs で確認できます。問い合わせ先は 壊れたときの直し方 にあります。認証情報や保存データの本文をログや問い合わせに載せないでください。