Use Cases (अपडेट: 3/6/2026)

Claude Code और AWS DynamoDB: टेबल डिजाइन, सुरक्षित writes और लागत

Claude Code के साथ DynamoDB का व्यावहारिक गाइड: keys, local tests, TTL, IAM, cost और hot partitions.

Claude Code और AWS DynamoDB: टेबल डिजाइन, सुरक्षित writes और लागत

Claude Code से सिर्फ “DynamoDB जोड़ दो” कहना production के लिए काफी नहीं है। DynamoDB schema-less लगता है, लेकिन असली schema access patterns में होता है: कौन सा screen कौन सा data पढ़ता है, query किस key से चलेगी, कौन सी write overwrite नहीं होनी चाहिए, और traffic partition keys में बराबर फैल रहा है या नहीं।

यह लेख Claude Code को code generator नहीं, बल्कि DynamoDB design reviewer की तरह इस्तेमाल करता है। हम table design, partition keys, simple design बनाम single-table design, conditional writes, TTL, local testing, IAM, cost और hot partition mistakes को एक practical flow में देखेंगे। AWS की बाकी setup के लिए AWS Lambda guide, AWS IAM guide और CloudWatch guide भी पढ़ें।

Implementation करते समय AWS की official docs से verify करें: data modeling foundations, partition key best practices, Query key condition expressions, condition expressions, TTL, DynamoDB local, throughput capacity और IAM fine-grained access control.

पहले access patterns लिखें

Access pattern का मतलब है application की असली read/write operation: project की tasks list करना, एक task complete करना, user session को 7 दिन बाद expire करना, या webhook event को सिर्फ एक बार process करना। अगर Claude Code को ये operations नहीं दिए गए, तो वह अक्सर generic CRUD बना देगा और बाद में Scan या index से कमी पूरी करने की कोशिश करेगा।

Code मांगने से पहले यह prompt दें:

Code लिखने से पहले इस DynamoDB design को review करें।
Requirements:
- Project के हिसाब से tasks list करना
- taskId से एक task update करना
- User sessions 7 दिन बाद expire हों
- हर webhook eventId सिर्फ एक बार process हो

Return:
1. Access pattern table
2. PK/SK proposal
3. कौन सी operations Query से हो सकती हैं और कौन सी नहीं
4. कहां conditional writes चाहिए
5. Hot partition और cost risks

DynamoDB में Query के लिए partition key पर equality condition चाहिए। Sort key से range या prefix जैसे begins_with लगाए जा सकते हैं। FilterExpression SQL के WHERE जैसा cost-saving filter नहीं है; यह पढ़ने के बाद data हटाता है। अगर Claude Code user-facing list के लिए Scan लिखता है, तो पहले design को ठीक करें।

Simple design या single-table design

Single-table design में कई entity types एक table में रखे जाते हैं, आमतौर पर PK और SK जैसे generic keys के साथ। यह तब अच्छा है जब एक screen को related data एक ही Query में चाहिए। लेकिन IAM, Streams, backups और key naming ज्यादा disciplined हो जाते हैं।

Simple design में entities अलग tables में रहती हैं, या एक table को सीमित access patterns तक रखा जाता है। MVP, internal tools और शुरुआती teams के लिए यह review करना आसान होता है।

निर्णयSimple designSingle-table design
शुरुआतसमझाना आसानमजबूत review चाहिए
कई entities वाली screenकई reads लग सकते हैंअक्सर एक Query
IAMtable-level separation आसानLeadingKeys जरूरी
बदलावनई table जोड़ना आसानkey naming स्थिर चाहिए
best fitMVP और learningstable business patterns

यह example एक table रखता है, पर scope छोटा है: projects, tasks, sessions और webhook dedupe.

ClaudeCodeLabDemo

PK                 SK                   entityType
PROJECT#alpha      META                 Project
PROJECT#alpha      TASK#task-001        Task
USER#u-001         SESSION#s-001        Session
WEBHOOK#stripe     EVENT#evt_001        WebhookEvent

Queries:
- Project tasks: PK = PROJECT#alpha AND begins_with(SK, TASK#)
- User sessions: PK = USER#u-001 AND begins_with(SK, SESSION#)
- Webhook dedupe: same PK/SK पर conditional PutItem

Practical use cases

पहला use case project task board है। PK = PROJECT#projectId और SK = TASK#taskId रखने से task list Query बनती है, Scan नहीं। अगर status filter चाहिए, तो Claude Code से पूछें कि GSI सच में चाहिए या project query के बाद application-side grouping काफी है।

दूसरा use case sessions, invite links और temporary tokens है। DynamoDB TTL एक Number attribute में Unix epoch seconds रखता है। यह cleanup के लिए अच्छा है, लेकिन exact scheduler नहीं है। Expired item background deletion से पहले पढ़ा जा सकता है, इसलिए security-sensitive flow में application को भी expiresAt check करना चाहिए।

तीसरा use case webhook idempotency है। Idempotency का मतलब है same event दोबारा आए तो side effect दोबारा न हो। WEBHOOK#provider, EVENT#eventId और attribute_not_exists(PK) AND attribute_not_exists(SK) से पहला processing जीतेगा और duplicate fail होगा।

चौथा use case rate limit है। PK = RATE#userId और SK = WINDOW#2026-06-03T10:00 छोटे internal APIs में काम कर सकता है। लेकिन बहुत popular user या tenant hot partition बना सकता है, इसलिए high-traffic APIs में अलग protection चाहिए।

Local setup

DynamoDB Local चलाएं:

services:
  dynamodb-local:
    image: "amazon/dynamodb-local:latest"
    command: "-jar DynamoDBLocal.jar -sharedDb -dbPath ./data"
    ports:
      - "8000:8000"
    volumes:
      - "./docker/dynamodb:/home/dynamodblocal/data"
    working_dir: /home/dynamodblocal
docker compose up -d
export AWS_ACCESS_KEY_ID=fakeMyKeyId
export AWS_SECRET_ACCESS_KEY=fakeSecretAccessKey
export AWS_REGION=us-west-2

Local table बनाएं:

aws dynamodb create-table \
  --table-name ClaudeCodeLabDemo \
  --attribute-definitions AttributeName=PK,AttributeType=S AttributeName=SK,AttributeType=S \
  --key-schema AttributeName=PK,KeyType=HASH AttributeName=SK,KeyType=RANGE \
  --billing-mode PAY_PER_REQUEST \
  --endpoint-url http://localhost:8000 \
  --region us-west-2

TTL attribute enable करें:

aws dynamodb update-time-to-live \
  --table-name ClaudeCodeLabDemo \
  --time-to-live-specification "Enabled=true,AttributeName=expiresAt" \
  --endpoint-url http://localhost:8000 \
  --region us-west-2

Dependencies install करें:

npm init -y
npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb

Copy-paste implementation

इसे app.mjs के रूप में save करें। यह task create करता है, project tasks list करता है, conditional update से task complete करता है और TTL वाली session item बनाता है।

import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
  DynamoDBDocumentClient,
  PutCommand,
  QueryCommand,
  UpdateCommand,
} from "@aws-sdk/lib-dynamodb";

const TABLE_NAME = process.env.TABLE_NAME ?? "ClaudeCodeLabDemo";
const isLocal = process.env.DDB_LOCAL !== "0";

const client = new DynamoDBClient({
  region: process.env.AWS_REGION ?? "us-west-2",
  ...(isLocal
    ? {
        endpoint: "http://localhost:8000",
        credentials: {
          accessKeyId: "fakeMyKeyId",
          secretAccessKey: "fakeSecretAccessKey",
        },
      }
    : {}),
});

const ddb = DynamoDBDocumentClient.from(client, {
  marshallOptions: { removeUndefinedValues: true },
});

const nowIso = () => new Date().toISOString();
const ttlAfterDays = (days) => Math.floor(Date.now() / 1000) + days * 86400;
const taskKey = (projectId, taskId) => ({
  PK: `PROJECT#${projectId}`,
  SK: `TASK#${taskId}`,
});

async function createTask({ projectId, taskId, title, ownerId }) {
  const item = {
    ...taskKey(projectId, taskId),
    entityType: "Task",
    title,
    ownerId,
    status: "OPEN",
    createdAt: nowIso(),
    updatedAt: nowIso(),
  };

  await ddb.send(
    new PutCommand({
      TableName: TABLE_NAME,
      Item: item,
      ConditionExpression: "attribute_not_exists(PK) AND attribute_not_exists(SK)",
    }),
  );

  return item;
}

async function listProjectTasks(projectId) {
  const result = await ddb.send(
    new QueryCommand({
      TableName: TABLE_NAME,
      KeyConditionExpression: "PK = :pk AND begins_with(SK, :taskPrefix)",
      ExpressionAttributeValues: {
        ":pk": `PROJECT#${projectId}`,
        ":taskPrefix": "TASK#",
      },
      ReturnConsumedCapacity: "TOTAL",
    }),
  );

  console.log("consumed capacity:", result.ConsumedCapacity);
  return result.Items ?? [];
}

async function completeTask({ projectId, taskId, expectedOwnerId }) {
  const result = await ddb.send(
    new UpdateCommand({
      TableName: TABLE_NAME,
      Key: taskKey(projectId, taskId),
      UpdateExpression: "SET #status = :done, updatedAt = :now",
      ConditionExpression: "ownerId = :ownerId AND #status <> :done",
      ExpressionAttributeNames: {
        "#status": "status",
      },
      ExpressionAttributeValues: {
        ":done": "DONE",
        ":ownerId": expectedOwnerId,
        ":now": nowIso(),
      },
      ReturnValues: "ALL_NEW",
    }),
  );

  return result.Attributes;
}

async function createSession({ userId, sessionId }) {
  await ddb.send(
    new PutCommand({
      TableName: TABLE_NAME,
      Item: {
        PK: `USER#${userId}`,
        SK: `SESSION#${sessionId}`,
        entityType: "Session",
        createdAt: nowIso(),
        expiresAt: ttlAfterDays(7),
      },
      ConditionExpression: "attribute_not_exists(PK) AND attribute_not_exists(SK)",
    }),
  );
}

async function main() {
  const projectId = "alpha";
  const taskId = `task-${Date.now()}`;

  await createTask({
    projectId,
    taskId,
    title: "Review DynamoDB key design",
    ownerId: "masa",
  });

  await createSession({
    userId: "masa",
    sessionId: `session-${Date.now()}`,
  });

  console.log(await listProjectTasks(projectId));
  console.log(
    await completeTask({
      projectId,
      taskId,
      expectedOwnerId: "masa",
    }),
  );
}

main().catch((error) => {
  if (error.name === "ConditionalCheckFailedException") {
    console.error("Condition failed:", error.message);
    process.exit(2);
  }

  console.error(error);
  process.exit(1);
});
DDB_LOCAL=1 node app.mjs

Claude Code से refactor कराते समय guardrails दें:

app.mjs को Lambda handler में refactor करें।
ConditionExpression न हटाएं।
जब तक Query क्यों नहीं चलेगा यह न समझाएं, Scan न जोड़ें।
expiresAt को Unix epoch seconds Number रखें।
development में ReturnConsumedCapacity रखें।

IAM, cost और pitfalls

Single table में पूरी table access देना अक्सर बहुत broad होता है। dynamodb:LeadingKeys से partition key के आधार पर access limit किया जा सकता है।

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ProjectScopedDynamoDBAccess",
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:UpdateItem",
        "dynamodb:DeleteItem",
        "dynamodb:Query"
      ],
      "Resource": [
        "arn:aws:dynamodb:ap-northeast-1:123456789012:table/ClaudeCodeLabProd",
        "arn:aws:dynamodb:ap-northeast-1:123456789012:table/ClaudeCodeLabProd/index/*"
      ],
      "Condition": {
        "ForAllValues:StringEquals": {
          "dynamodb:LeadingKeys": [
            "PROJECT#${aws:PrincipalTag/projectId}"
          ]
        }
      }
    }
  ]
}

On-demand mode शुरू करने में आसान है, क्योंकि आप requests के लिए pay करते हैं। Predictable traffic में provisioned mode cost control दे सकता है। Common mistakes हैं: list pages में Scan, FilterExpression को SQL WHERE मानना, GLOBAL या TODAY जैसी hot keys, TTL को instant delete समझना, access pattern बिना GSI जोड़ना, conditional write छोड़ना और local endpoint production में रख देना।

इस DynamoDB implementation को Scan dependency, hot partition risk, TTL misunderstanding, missing conditional writes, broad IAM permissions और on-demand cost spikes के लिए audit करें। पहले findings दें, फिर fixes।

Reusable prompts और checklists के लिए ClaudeCodeLab products देखें। Team adoption में AWS, IAM, CI review और production verification साथ में चाहिए तो Claude Code training and consultation उपयोगी है।

निष्कर्ष

DynamoDB में सफलता table count से नहीं, explicit access patterns से आती है। Keys, failure conditions, TTL, IAM और cost signals पहले तय करें। Claude Code implementation तेज कर सकता है, लेकिन उसे constraints invent करने देना जोखिम है।

Hands-on note (実際に試した結果): सबसे भरोसेमंद flow था कि पहले Claude Code से access pattern table बनवाएं, फिर PK/SK और failure cases review करें, और अंत में DynamoDB Local पर conditional writes चलाएं। attribute_not_exists वाला webhook dedupe example production review में सीधे इस्तेमाल होने वाला safety guard है।

#claude-code #aws #dynamodb #nosql #typescript #database
मुफ़्त

मुफ़्त PDF: Claude Code cheatsheet

Email डालें और commands, review habits तथा safe workflow वाली एक-page PDF पाएँ.

हम आपका data सुरक्षित रखते हैं और spam नहीं भेजते.

Masa

लेखक के बारे में

Masa

Claude Code workflow और team adoption पर काम करने वाला engineer.