Skip to main content

DynamoDB

Overview

MBC CQRS Serverless uses DynamoDB as its primary data store, implementing CQRS and Event Sourcing patterns through a structured table design. Understanding the table structure is essential for building efficient applications.

Table Architecture

In the MBC CQRS Serverless, DynamoDB tables are organized into the following types:

Entity Tables

Table TypeNaming ConventionPurpose
Command Tableentity-commandStores write commands (write model)
Data Tableentity-dataStores current state (read model)
History Tableentity-historyStores all versions for event sourcing

System Tables

TablePurpose
tasksStores information about long-running asynchronous tasks
sequencesHolds sequence data for ID generation

Table Definition

Table definitions are stored in the prisma/dynamodbs folder. To add a new entity table:

Step 1: Define Table in Configuration

Add the table name to prisma/dynamodbs/cqrs.json:

["cat", "dog", "order"]

Step 2: Run Migration

For local development:

# Migrate DynamoDB tables only
npm run migrate:ddb

# Migrate both DynamoDB and RDS
npm run migrate

Key Design Patterns

Standard Key Structure

All tables use a composite primary key consisting of:

KeyFormatExample
pkTYPE#tenantCodeORDER#ACME
skTYPE#codeORDER#ORD-000001

Entity Key Examples

// Order entity
const orderKey = {
pk: `ORDER#${tenantCode}`,
sk: `ORDER#${orderId}`,
};

// User entity
const userKey = {
pk: `USER#${tenantCode}`,
sk: `USER#${userId}`,
};

// Hierarchical data (e.g., organization)
const departmentKey = {
pk: `ORG#${tenantCode}`,
sk: `DEPT#${parentId}#${deptId}`,
};

Table Attributes

Common Attributes

All entity tables share these common attributes:

AttributeTypeDescription
pkStringPartition key
skStringSort key
idStringUnique identifier (pk#sk hash)
codeStringBusiness code
nameStringDisplay name
tenantCodeStringTenant identifier
typeStringEntity type
versionNumberVersion for optimistic locking
attributesMapCustom entity attributes
createdByStringCreator user ID
createdIpStringCreator IP address
createdAtStringCreation timestamp (ISO 8601)
updatedByStringLast modifier user ID
updatedIpStringLast modifier IP address
updatedAtStringLast update timestamp (ISO 8601)

Command-Specific Attributes

AttributeTypeDescription
sourceStringCommand source identifier
requestIdStringRequest tracking ID

History-Specific Attributes

AttributeTypeDescription
seqNumberSequence number in history

Secondary Indexes

Adding Global Secondary Indexes

The default table configuration does not include GSIs. You can add them based on your query patterns. A common pattern is adding a code-index for fast lookups by business code:

Example GSI definition (add to your table configuration):

{
"GlobalSecondaryIndexes": [
{
"IndexName": "code-index",
"KeySchema": [
{ "AttributeName": "tenantCode", "KeyType": "HASH" },
{ "AttributeName": "code", "KeyType": "RANGE" }
],
"Projection": { "ProjectionType": "ALL" }
}
]
}

Example usage with custom GSI:

// Find entity by code (requires code-index GSI)
const params = {
TableName: 'entity-data',
IndexName: 'code-index',
KeyConditionExpression: 'tenantCode = :tenant AND code = :code',
ExpressionAttributeValues: {
':tenant': tenantCode,
':code': entityCode,
},
};

Best Practices

Key Design

  1. Keep partition keys broad: Distribute data evenly across partitions
  2. Use hierarchical sort keys: Enable efficient range queries
  3. Include tenant in partition key: Ensure data isolation

Query Optimization

  1. Use Query over Scan: Always use partition key in queries
  2. Limit result sets: Use pagination for large datasets
  3. Project needed attributes: Only retrieve required fields

Capacity Planning

  1. Use on-demand capacity: Recommended for unpredictable workloads
  2. Monitor consumed capacity: Set up CloudWatch alarms
  3. Consider DAX: For read-heavy workloads requiring microsecond latency

Local Development

DynamoDB Local

The framework includes DynamoDB Local for development:

# Start DynamoDB Local (included in docker-compose)
docker-compose up -d dynamodb-local

# Access DynamoDB Local Admin UI
open http://localhost:8001

Environment Variables

# Local DynamoDB endpoint
DYNAMODB_ENDPOINT=http://localhost:8000
DYNAMODB_REGION=ap-northeast-1