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テーブルを共有します。アプリごとにテーブルが増えるわけではありません |
pk と sk は両方必要です。たとえば 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 対応版か、独自の認証設定で標準認証を上書きしていないか確認します |
AccessDeniedException | DYNAMODB_TABLE、リージョン、許可されたデータ操作かを確認します。権限の追加やテーブル作成で回避しないでください |
ResourceNotFoundException | テーブル名とリージョンを確認します。市民登録直後は準備が終わるまで少し待ち、続く場合は運営へ問い合わせます |
| キーの形式エラー | pk と sk を両方、文字列で渡しているか確認します |
| throttling | SDK のバックオフ付きリトライを使い、同時要求を減らします。毎回の全件 Scan を避け、用途に合うキーで Query します |
アプリのログは MCP の logs で確認できます。問い合わせ先は 壊れたときの直し方 にあります。認証情報や保存データの本文をログや問い合わせに載せないでください。