Skip to main content

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

ChangeImpactAction Required
TENANT_COMMON value changed to 'common'Partition keys changed from TENANT#COMMON to TENANT#commonData migration required
Tenant code normalizationAll tenant codes normalized to lowercaseData migration may be required
Deprecated methods removedpublish(), publishPartialUpdate(), genNewSequence() removedUpdate method calls

Pre-Migration Checklist

Before upgrading, verify the following:

  • Backup your DynamoDB tables
  • Identify all tables using TENANT#COMMON partition 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:

TableBeforeAfter
Tenant settingsTENANT#COMMONTENANT#common
Master settingsMASTER_SETTING#COMMON#...MASTER_SETTING#common#...
Master dataMASTER_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:

  1. Strategy 1: Update DynamoDB Data - Migrate existing data to use lowercase tenant codes
  2. Strategy 2: Custom Normalization - Override normalization behavior (not recommended for new projects)
  3. 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:

PackageRemoved MethodReplacement
@mbc-cqrs-serverless/coreCommandService.publish()CommandService.publishAsync()
@mbc-cqrs-serverless/coreCommandService.publishPartialUpdate()CommandService.publishPartialUpdateAsync()
@mbc-cqrs-serverless/sequenceSequencesService.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:

  1. publish() / publishPartialUpdate(): The naming was ambiguous. The Async suffix clarifies that these methods use DynamoDB Streams for asynchronous data synchronization.

  2. genNewSequence(): The method was replaced by generateSequenceItem() 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:

  1. TENANT_COMMON partition key changes
  2. 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:

  1. Restore DynamoDB tables from backup
  2. Downgrade packages:
    npm install @mbc-cqrs-serverless/core@1.0.26
    # etc.
  3. 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: