Migration Guide: v1.1.0
This guide helps you upgrade from v1.0.x to v1.1.0. Version 1.1.0 includes breaking changes related to tenant code handling that require data migration.
Release Date
2026-02-03
Breaking Changes Summary
| Change | Impact | Action Required |
|---|---|---|
TENANT_COMMON value changed to 'common' | Partition keys changed from TENANT#COMMON to TENANT#common | Data migration required |
| Tenant code normalization | All tenant codes normalized to lowercase | Data migration may be required |
| Deprecated methods removed | publish(), publishPartialUpdate(), genNewSequence() removed | Update method calls |
Pre-Migration Checklist
Before upgrading, verify the following:
- Backup your DynamoDB tables
- Identify all tables using
TENANT#COMMONpartition keys - Identify all tables using uppercase tenant codes in partition keys
- Plan a maintenance window for the migration
- Test the migration in a non-production environment first
Breaking Change 1: TENANT_COMMON Value
What Changed
The SettingTypeEnum.TENANT_COMMON enum value changed:
// Before (v1.0.x)
export enum SettingTypeEnum {
TENANT_COMMON = 'COMMON', // Uppercase
// ...
}
// After (v1.1.0)
export enum SettingTypeEnum {
TENANT_COMMON = 'common', // Lowercase
// ...
}
Impact
This affects partition keys in DynamoDB:
| Table | Before | After |
|---|---|---|
| Tenant settings | TENANT#COMMON | TENANT#common |
| Master settings | MASTER_SETTING#COMMON#... | MASTER_SETTING#common#... |
| Master data | MASTER_DATA#COMMON#... | MASTER_DATA#common#... |
Migration Steps
Step 1: Identify Affected Data
Run a scan to find all items with COMMON in partition keys:
# Using AWS CLI
aws dynamodb scan \
--table-name YOUR_TABLE_NAME \
--filter-expression "contains(pk, :common)" \
--expression-attribute-values '{":common":{"S":"COMMON"}}' \
--output json > common_tenant_items.json
Step 2: Create Migration Script
// scripts/migrate-tenant-common.ts
import {
DynamoDBClient,
ScanCommand,
TransactWriteItemsCommand,
} from '@aws-sdk/client-dynamodb';
const client = new DynamoDBClient({});
const TABLE_NAME = process.env.DATA_TABLE_NAME || 'your-table-name';
async function migrateCommonTenant() {
console.log('Starting TENANT_COMMON migration...');
// Scan for items with COMMON in pk
const scanResult = await client.send(new ScanCommand({
TableName: TABLE_NAME,
FilterExpression: 'contains(pk, :common)',
ExpressionAttributeValues: {
':common': { S: 'COMMON' },
},
}));
const items = scanResult.Items || [];
console.log(`Found ${items.length} items to migrate`);
// Process in batches of 25 (DynamoDB limit)
for (let i = 0; i < items.length; i += 25) {
const batch = items.slice(i, i + 25);
const transactItems = [];
for (const item of batch) {
const oldPk = item.pk.S!;
const newPk = oldPk.replace(/COMMON/g, 'common');
// Delete old item
transactItems.push({
Delete: {
TableName: TABLE_NAME,
Key: {
pk: { S: oldPk },
sk: item.sk,
},
},
});
// Create new item with lowercase pk
const newItem = { ...item, pk: { S: newPk } };
// Update tenantCode if present
if (newItem.tenantCode?.S === 'COMMON') {
newItem.tenantCode = { S: 'common' };
}
transactItems.push({
Put: {
TableName: TABLE_NAME,
Item: newItem,
},
});
}
await client.send(new TransactWriteItemsCommand({
TransactItems: transactItems,
}));
console.log(`Migrated batch ${Math.floor(i / 25) + 1}`);
}
console.log('Migration complete!');
}
migrateCommonTenant().catch(console.error);
Step 3: Run Migration
# Set environment variables
export DATA_TABLE_NAME=your-table-name
export AWS_REGION=ap-northeast-1
# Run migration (dry run first)
npx ts-node scripts/migrate-tenant-common.ts
Step 4: Verify Migration
# Verify no items with uppercase COMMON remain
aws dynamodb scan \
--table-name YOUR_TABLE_NAME \
--filter-expression "contains(pk, :common)" \
--expression-attribute-values '{":common":{"S":"#COMMON"}}' \
--select COUNT
Breaking Change 2: Tenant Code Normalization
What Changed
The getUserContext() function now normalizes tenant codes to lowercase:
// Before (v1.0.x)
const ctx = getUserContext(invokeContext);
console.log(ctx.tenantCode); // "MY_TENANT" (as stored in Cognito)
// After (v1.1.0)
const ctx = getUserContext(invokeContext);
console.log(ctx.tenantCode); // "my_tenant" (normalized to lowercase)
Impact
If your existing data uses uppercase tenant codes in partition keys, queries will fail to find that data.
Migration Strategy
See the detailed migration guide: Tenant Code Normalization Migration
Key options:
- Strategy 1: Update DynamoDB Data - Migrate existing data to use lowercase tenant codes
- Strategy 2: Custom Normalization - Override normalization behavior (not recommended for new projects)
- Strategy 3: Gradual Migration - Use dual-read pattern during transition
Breaking Change 3: Deprecated Methods Removed
What Changed
The following deprecated methods have been removed in v1.1.0:
| Package | Removed Method | Replacement |
|---|---|---|
@mbc-cqrs-serverless/core | CommandService.publish() | CommandService.publishAsync() |
@mbc-cqrs-serverless/core | CommandService.publishPartialUpdate() | CommandService.publishPartialUpdateAsync() |
@mbc-cqrs-serverless/sequence | SequencesService.genNewSequence() | SequencesService.generateSequenceItem() |
Migration Steps
CommandService Methods
// Before (v1.0.x)
const item = await this.commandService.publish(input, opts);
const updated = await this.commandService.publishPartialUpdate(partialInput, opts);
// After (v1.1.0)
const item = await this.commandService.publishAsync(input, opts);
const updated = await this.commandService.publishPartialUpdateAsync(partialInput, opts);
SequencesService Methods
// Before (v1.0.x)
const sequence = await this.sequencesService.genNewSequence(dto, opts);
// After (v1.1.0)
const sequence = await this.sequencesService.generateSequenceItem(dto, opts);
Why These Methods Were Removed
These methods were deprecated because:
-
publish()/publishPartialUpdate(): The naming was ambiguous. TheAsyncsuffix clarifies that these methods use DynamoDB Streams for asynchronous data synchronization. -
genNewSequence(): The method was replaced bygenerateSequenceItem()which provides a more consistent API and better return type.
New Features in v1.1.0
Utility Functions
New utility functions are available for tenant code handling:
import {
normalizeTenantCode,
isCommonTenant,
} from '@mbc-cqrs-serverless/core';
// Normalize a tenant code
const normalized = normalizeTenantCode('MY_TENANT'); // "my_tenant"
// Check if tenant is common
const isCommon = isCommonTenant('common'); // true
const isCommon2 = isCommonTenant('COMMON'); // true (case-insensitive)
Improved Test Coverage
v1.1.0 includes comprehensive tests for:
- TenantService methods (17 new tests)
- SettingTypeEnum validation (7 new tests)
- Tenant code normalization (70+ test cases)
- Tenant normalization commands (30+ test cases)
Upgrade Steps
Step 1: Update Dependencies
npm install @mbc-cqrs-serverless/core@1.1.0
npm install @mbc-cqrs-serverless/tenant@1.1.0
npm install @mbc-cqrs-serverless/master@1.1.0
# Update other packages as needed
Step 2: Run Data Migration
Follow the migration steps above for:
TENANT_COMMONpartition key changes- Tenant code normalization (if applicable)
Step 3: Update Code (if necessary)
If you have hardcoded 'COMMON' strings, update them:
// Before
const pk = `TENANT#COMMON`;
// After
import { SettingTypeEnum } from '@mbc-cqrs-serverless/tenant';
const pk = `TENANT#${SettingTypeEnum.TENANT_COMMON}`;
Step 4: Test
# Run your test suite
npm test
# Test in staging environment
npm run deploy:stg
Rollback Procedure
If you need to rollback to v1.0.x:
- Restore DynamoDB tables from backup
- Downgrade packages:
npm install @mbc-cqrs-serverless/core@1.0.26
# etc. - Redeploy application
FAQ
Q: Can I skip the migration if I don't use common tenant?
If you never use the common tenant feature (shared resources across all tenants), you may not need to migrate TENANT_COMMON data. However, you should still review tenant code normalization impact.
Q: How long does the migration take?
Migration time depends on data volume. Estimate approximately:
- 1,000 items: ~1 minute
- 10,000 items: ~5-10 minutes
- 100,000 items: ~30-60 minutes
Q: Can I run the migration while the application is running?
We recommend performing migration during a maintenance window to avoid race conditions. If zero-downtime is required, use the gradual migration strategy with dual-read pattern.
Support
If you encounter issues during migration: