Examples
This section provides practical examples and implementation guides for common use cases. Each example demonstrates real-world scenarios with complete, production-ready code.
Available Examples
| Example | Description | Key Concepts |
|---|---|---|
| Todo App Tutorial | Step-by-step CQRS app with full CRUD | Commands, queries, RDS sync, sequences |
| E-commerce | Order management with inventory tracking | Optimistic locking, event-driven sync, status transitions |
| SaaS Application | Multi-tenant subscription and usage metering | Tenant isolation, quota enforcement, billing integration |
| Survey Template | Dynamic form builder with validation | Schema design, versioning, complex attributes |
Implementation Patterns
Each example follows consistent patterns:
1. Entity Design
// Define your entity with proper key structure
export class OrderEntity extends DataEntity {
pk: string; // ORDER#tenantCode
sk: string; // ORDER#orderId
id: string;
tenantCode: string;
code: string;
name: string;
attributes: OrderAttributes;
}
2. Command Pattern
// Create commands for state changes
import { VERSION_FIRST, generateId } from '@mbc-cqrs-serverless/core';
async createOrder(dto: CreateOrderDto, context: IInvoke) {
const orderId = await this.sequencesService.generateSequenceItem(
{
tenantCode: dto.tenantCode,
typeCode: 'ORDER',
},
{ invokeContext: context },
);
const pk = `ORDER#${dto.tenantCode}`;
const sk = `ORDER#${orderId.formattedNo}`;
return this.commandService.publishAsync(
{
pk,
sk,
id: generateId(pk, sk), // Required: unique identifier (pk#sk)
code: orderId.formattedNo,
name: dto.name,
version: VERSION_FIRST, // Required: VERSION_FIRST (0) for new entities
tenantCode: dto.tenantCode,
type: 'ORDER', // Required: entity type
attributes: dto.attributes,
},
{ invokeContext: context },
);
}
3. Query Pattern
// Query data with proper filtering
async listOrders(tenantCode: string, options: ListOptions) {
return this.dataService.listItemsByPk(
`ORDER#${tenantCode}`,
{
limit: options.limit,
startFromSk: options.lastSk,
},
);
}
4. Event Handler
// Handle data sync events
import { EventHandler, IEventHandler } from '@mbc-cqrs-serverless/core';
import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma';
@EventHandler(OrderDataSyncEvent)
@Injectable()
export class OrderDataSyncHandler implements IEventHandler<OrderDataSyncEvent> {
constructor(private readonly prisma: PrismaService) {}
async execute(event: OrderDataSyncEvent): Promise<void> {
// Sync to read model (RDS, OpenSearch, etc.)
await this.prisma.order.upsert({
where: { sk: event.data.sk },
create: { sk: event.data.sk, ...event.data.attributes },
update: event.data.attributes,
});
}
}
Best Practices
Key Design
- Use consistent prefix patterns:
TENANT#code,ORDER#id - Keep partition keys broad enough for even distribution
- Use sort keys for hierarchical data
Error Handling
import { ConditionalCheckFailedException } from '@aws-sdk/client-dynamodb';
import { ConflictException } from '@nestjs/common';
try {
await this.commandService.publishAsync(command, options);
} catch (error) {
if (error instanceof ConditionalCheckFailedException) {
// Handle optimistic locking conflict (version mismatch)
throw new ConflictException('Item was modified by another process');
}
throw error;
}
Testing
describe('OrderService', () => {
it('should create order with sequence', async () => {
const result = await service.createOrder(mockDto, mockContext);
expect(result.code).toMatch(/^ORD-\d{6}$/);
});
});
Explore Examples
E-commerce Example
Complete E-commerce implementation example with order management, inventory, and multi-tenant support.
SaaS Application Example
Multi-tenant SaaS application example with subscription management, usage tracking, and billing integration.
Survey Template
Survey template management module for building dynamic multi-tenant surveys and questionnaires in MBC CQRS Serverless.
Related Documentation
- Service Patterns - CRUD service patterns
- Backend Development - Core backend guide
- Key Patterns - Key design for recipes