claude-flow-multilang
Version:
Revolutionary multilingual AI orchestration framework with cultural awareness and DDD architecture
804 lines (707 loc) • 23.2 kB
text/typescript
/**
* Claude Flow Multilang Framework - DDD Development Service
* Integrates DDD into the development workflow
*/
import { SupportedLanguage } from '../../polyglot/types.js';
import { ILogger } from '../../core/logger.js';
import { WorkflowAggregate } from '../workflow-aggregate.js';
import { CommandBus, ICommand, ICommandResult } from './command-handler.js';
import { PolyglotAgent } from '../../polyglot/polyglot-agent.js';
import { MultilingualString, EntityId } from '../base-domain.js';
/**
* DDD development phase
*/
export enum DDDPhase {
DISCOVERY = 'discovery',
MODELING = 'modeling',
IMPLEMENTATION = 'implementation',
TESTING = 'testing',
DEPLOYMENT = 'deployment',
}
/**
* Bounded context definition
*/
export interface BoundedContext {
id: string;
name: MultilingualString;
description: MultilingualString;
aggregates: AggregateDefinition[];
services: ServiceDefinition[];
events: EventDefinition[];
language: SupportedLanguage;
team?: string;
}
/**
* Aggregate definition for development
*/
export interface AggregateDefinition {
id: string;
name: MultilingualString;
description: MultilingualString;
properties: PropertyDefinition[];
methods: MethodDefinition[];
events: string[];
invariants: string[];
}
/**
* Property definition
*/
export interface PropertyDefinition {
name: string;
type: string;
required: boolean;
multilingual: boolean;
validation?: string;
}
/**
* Method definition
*/
export interface MethodDefinition {
name: string;
description: MultilingualString;
parameters: ParameterDefinition[];
returnType: string;
businessRules: string[];
}
/**
* Parameter definition
*/
export interface ParameterDefinition {
name: string;
type: string;
required: boolean;
description?: string;
}
/**
* Service definition
*/
export interface ServiceDefinition {
id: string;
name: MultilingualString;
description: MultilingualString;
operations: MethodDefinition[];
dependencies: string[];
}
/**
* Event definition
*/
export interface EventDefinition {
id: string;
name: string;
description: MultilingualString;
payload: PropertyDefinition[];
source: string;
targets: string[];
}
/**
* DDD Development Service
*/
export class DDDDevelopmentService {
private boundedContexts: Map<string, BoundedContext> = new Map();
private currentPhase: DDDPhase = DDDPhase.DISCOVERY;
private commandBus: CommandBus;
private workflows: Map<string, WorkflowAggregate> = new Map();
private commandHandlers: Map<string, any> = new Map();
constructor(
private logger: ILogger,
private polyglotAgent: PolyglotAgent,
) {
this.commandBus = new CommandBus(logger);
this.registerDefaultHandlers();
}
/**
* Register default command handlers
*/
private registerDefaultHandlers(): void {
// Register handlers for workflow commands
this.commandBus.register('CreateBoundedContext', {
handle: async (command: ICreateCommand) => this.handleCreateBoundedContext(command),
canHandle: (cmd) => cmd.type === 'CreateBoundedContext',
});
this.commandBus.register('AddAggregate', {
handle: async (command: any) => this.handleAddAggregate(command),
canHandle: (cmd) => cmd.type === 'AddAggregate',
});
this.commandBus.register('GenerateCode', {
handle: async (command: any) => this.handleGenerateCode(command),
canHandle: (cmd) => cmd.type === 'GenerateCode',
});
}
/**
* Handle create bounded context command
*/
private async handleCreateBoundedContext(command: ICreateCommand): Promise<ICommandResult> {
try {
const context = await this.createBoundedContext(
command.name,
command.description,
{
team: command.properties?.team,
language: command.language,
},
);
return {
success: true,
data: context,
aggregateId: context.id,
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
/**
* Handle add aggregate command
*/
private async handleAddAggregate(command: any): Promise<ICommandResult> {
try {
await this.addAggregate(command.contextId, command.aggregate);
return {
success: true,
data: { message: 'Aggregate added successfully' },
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
/**
* Handle generate code command
*/
private async handleGenerateCode(command: any): Promise<ICommandResult> {
try {
const files = await this.generateCode(command.contextId, command.options);
return {
success: true,
data: { files: Array.from(files.entries()) },
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
/**
* Start DDD development process
*/
async startDevelopment(
projectName: Partial<Record<SupportedLanguage, string>>,
description: Partial<Record<SupportedLanguage, string>>,
options: {
methodology?: 'event-storming' | 'domain-storytelling' | 'example-mapping';
team?: string;
primaryLanguage?: SupportedLanguage;
} = {},
): Promise<WorkflowAggregate> {
this.logger.info('Starting DDD development process', {
project: projectName,
methodology: options.methodology || 'event-storming',
});
// Create DDD workflow
const workflow = this.createDDDWorkflow(projectName, description, options);
this.workflows.set(workflow.id.toString(), workflow);
// Start discovery phase
await this.startDiscoveryPhase(workflow, options);
return workflow;
}
/**
* Create DDD development workflow
*/
private createDDDWorkflow(
projectName: Partial<Record<SupportedLanguage, string>>,
description: Partial<Record<SupportedLanguage, string>>,
options: any,
): WorkflowAggregate {
const workflow = WorkflowAggregate.create(
projectName,
description,
options.primaryLanguage ? [options.primaryLanguage] : [SupportedLanguage.EN],
);
// Add DDD phases as workflow steps
this.addDDDPhases(workflow, options.primaryLanguage || SupportedLanguage.EN);
workflow.activate();
return workflow;
}
/**
* Add DDD phases to workflow
*/
private addDDDPhases(workflow: WorkflowAggregate, language: SupportedLanguage): void {
const phases = [
{
phase: DDDPhase.DISCOVERY,
name: {
[SupportedLanguage.EN]: 'Domain Discovery',
[SupportedLanguage.RU]: 'Исследование домена',
[SupportedLanguage.JA]: 'ドメイン探索',
[SupportedLanguage.ZH_CN]: '领域发现',
},
description: {
[SupportedLanguage.EN]: 'Discover domain concepts through event storming',
[SupportedLanguage.RU]: 'Обнаружение доменных концепций через event storming',
[SupportedLanguage.JA]: 'イベントストーミングによるドメイン概念の発見',
[SupportedLanguage.ZH_CN]: '通过事件风暴发现领域概念',
},
agent: 'domain-expert',
capabilities: ['event-storming', 'domain-analysis', 'ubiquitous-language'],
},
{
phase: DDDPhase.MODELING,
name: {
[SupportedLanguage.EN]: 'Domain Modeling',
[SupportedLanguage.RU]: 'Моделирование домена',
[SupportedLanguage.JA]: 'ドメインモデリング',
[SupportedLanguage.ZH_CN]: '领域建模',
},
description: {
[SupportedLanguage.EN]: 'Create domain models with aggregates and entities',
[SupportedLanguage.RU]: 'Создание доменных моделей с агрегатами и сущностями',
[SupportedLanguage.JA]: '集約とエンティティを使用したドメインモデルの作成',
[SupportedLanguage.ZH_CN]: '使用聚合和实体创建领域模型',
},
agent: 'architect',
capabilities: ['aggregate-design', 'entity-modeling', 'value-objects'],
},
{
phase: DDDPhase.IMPLEMENTATION,
name: {
[SupportedLanguage.EN]: 'Implementation',
[SupportedLanguage.RU]: 'Реализация',
[SupportedLanguage.JA]: '実装',
[SupportedLanguage.ZH_CN]: '实现',
},
description: {
[SupportedLanguage.EN]: 'Implement domain models and services',
[SupportedLanguage.RU]: 'Реализация доменных моделей и сервисов',
[SupportedLanguage.JA]: 'ドメインモデルとサービスの実装',
[SupportedLanguage.ZH_CN]: '实现领域模型和服务',
},
agent: 'developer',
capabilities: ['coding', 'repository-pattern', 'domain-services'],
},
{
phase: DDDPhase.TESTING,
name: {
[SupportedLanguage.EN]: 'Testing',
[SupportedLanguage.RU]: 'Тестирование',
[SupportedLanguage.JA]: 'テスト',
[SupportedLanguage.ZH_CN]: '测试',
},
description: {
[SupportedLanguage.EN]: 'Test domain logic and invariants',
[SupportedLanguage.RU]: 'Тестирование доменной логики и инвариантов',
[SupportedLanguage.JA]: 'ドメインロジックと不変条件のテスト',
[SupportedLanguage.ZH_CN]: '测试领域逻辑和不变量',
},
agent: 'tester',
capabilities: ['unit-testing', 'integration-testing', 'invariant-testing'],
},
];
let previousStep: string | undefined;
for (const phase of phases) {
workflow.addStep(
phase.name,
phase.description,
phase.agent,
phase.capabilities,
previousStep ? [previousStep] : [],
);
previousStep = `step-${workflow.getProgress().total}`;
}
}
/**
* Start discovery phase
*/
private async startDiscoveryPhase(
workflow: WorkflowAggregate,
options: any,
): Promise<void> {
this.currentPhase = DDDPhase.DISCOVERY;
const methodology = options.methodology || 'event-storming';
switch (methodology) {
case 'event-storming':
await this.runEventStorming(workflow, options);
break;
case 'domain-storytelling':
await this.runDomainStorytelling(workflow, options);
break;
case 'example-mapping':
await this.runExampleMapping(workflow, options);
break;
}
}
/**
* Run event storming session
*/
private async runEventStorming(
workflow: WorkflowAggregate,
options: any,
): Promise<void> {
this.logger.info('Running event storming session');
// Use polyglot agent to facilitate event storming
const prompt = `
Facilitate an event storming session for ${workflow.getName(options.primaryLanguage || SupportedLanguage.EN)}.
Identify:
1. Domain events (things that happen)
2. Commands (triggers for events)
3. Aggregates (consistency boundaries)
4. Bounded contexts (logical boundaries)
5. Read models (queries and views)
`;
const result = await this.polyglotAgent.processInNativeLanguage(
prompt,
options.primaryLanguage,
);
// Parse and store discovered concepts
// In real implementation, this would be interactive
this.logger.info('Event storming completed', {
language: result.language,
confidence: result.confidence,
});
}
/**
* Run domain storytelling session
*/
private async runDomainStorytelling(
workflow: WorkflowAggregate,
options: any,
): Promise<void> {
this.logger.info('Running domain storytelling session');
// Implementation for domain storytelling
}
/**
* Run example mapping session
*/
private async runExampleMapping(
workflow: WorkflowAggregate,
options: any,
): Promise<void> {
this.logger.info('Running example mapping session');
// Implementation for example mapping
}
/**
* Create bounded context
*/
async createBoundedContext(
name: Partial<Record<SupportedLanguage, string>>,
description: Partial<Record<SupportedLanguage, string>>,
options: {
team?: string;
language?: SupportedLanguage;
} = {},
): Promise<BoundedContext> {
const id = EntityId.generate().toString();
const context: BoundedContext = {
id,
name: new MultilingualString(name),
description: new MultilingualString(description),
aggregates: [],
services: [],
events: [],
language: options.language || SupportedLanguage.EN,
team: options.team,
};
this.boundedContexts.set(id, context);
this.logger.info('Created bounded context', {
id,
name: name[SupportedLanguage.EN],
});
return context;
}
/**
* Add aggregate to bounded context
*/
async addAggregate(
contextId: string,
aggregate: AggregateDefinition,
): Promise<void> {
const context = this.boundedContexts.get(contextId);
if (!context) {
throw new Error(`Bounded context not found: ${contextId}`);
}
context.aggregates.push(aggregate);
this.logger.info('Added aggregate to bounded context', {
contextId,
aggregateName: aggregate.name.get(SupportedLanguage.EN),
});
}
/**
* Generate code from bounded context
*/
async generateCode(
contextId: string,
options: {
language?: 'typescript' | 'javascript' | 'python' | 'java';
includeTests?: boolean;
includeRepositories?: boolean;
includeServices?: boolean;
} = {},
): Promise<Map<string, string>> {
const context = this.boundedContexts.get(contextId);
if (!context) {
throw new Error(`Bounded context not found: ${contextId}`);
}
const files = new Map<string, string>();
// Generate aggregate files
for (const aggregate of context.aggregates) {
const code = this.generateAggregateCode(aggregate, options);
const fileName = `${aggregate.name.get(SupportedLanguage.EN)}.${options.language === 'python' ? 'py' : 'ts'}`;
files.set(fileName, code);
if (options.includeTests) {
const testCode = this.generateAggregateTests(aggregate, options);
const testFileName = `${aggregate.name.get(SupportedLanguage.EN)}.test.${options.language === 'python' ? 'py' : 'ts'}`;
files.set(testFileName, testCode);
}
}
// Generate repository interfaces
if (options.includeRepositories) {
for (const aggregate of context.aggregates) {
const repoCode = this.generateRepositoryInterface(aggregate, options);
const repoFileName = `${aggregate.name.get(SupportedLanguage.EN)}Repository.${options.language === 'python' ? 'py' : 'ts'}`;
files.set(repoFileName, repoCode);
}
}
// Generate domain services
if (options.includeServices) {
for (const service of context.services) {
const serviceCode = this.generateServiceCode(service, options);
const serviceFileName = `${service.name.get(SupportedLanguage.EN)}Service.${options.language === 'python' ? 'py' : 'ts'}`;
files.set(serviceFileName, serviceCode);
}
}
this.logger.info('Generated code for bounded context', {
contextId,
filesGenerated: files.size,
});
return files;
}
/**
* Generate aggregate code
*/
private generateAggregateCode(
aggregate: AggregateDefinition,
options: any,
): string {
const className = aggregate.name.get(SupportedLanguage.EN);
if (options.language === 'typescript' || !options.language) {
return `/**
* ${className} Aggregate
* ${aggregate.description.get(SupportedLanguage.EN)}
*/
import { AggregateRoot, EntityId, MultilingualString } from '@claude-flow/domain';
import { SupportedLanguage } from '@claude-flow/types';
export interface ${className}Props {
${aggregate.properties.map(p => ` ${p.name}${p.required ? '' : '?'}: ${p.multilingual ? 'MultilingualString' : p.type};`).join('\n')}
}
export class ${className} extends AggregateRoot<${className}Props> {
constructor(props: ${className}Props, id?: EntityId) {
super(props, id);
this.validateInvariants();
}
private validateInvariants(): void {
${aggregate.invariants.map(inv => ` // ${inv}`).join('\n')}
}
${aggregate.methods.map(m => `
${m.name}(${m.parameters.map(p => `${p.name}: ${p.type}`).join(', ')}): ${m.returnType} {
// Business rules:
${m.businessRules.map(rule => ` // - ${rule}`).join('\n')}
// Implementation here
throw new Error('Not implemented');
}`).join('\n')}
}
// Domain Events
${aggregate.events.map(event => `
export class ${event} extends DomainEvent {
constructor(aggregateId: string, public readonly data: any) {
super(aggregateId, '${event}');
}
}`).join('\n')}`;
}
// Python implementation
return '# Python implementation not yet available';
}
/**
* Generate aggregate tests
*/
private generateAggregateTests(
aggregate: AggregateDefinition,
options: any,
): string {
const className = aggregate.name.get(SupportedLanguage.EN);
return `import { ${className} } from './${className}';
describe('${className}', () => {
describe('creation', () => {
it('should create with valid props', () => {
const aggregate = new ${className}({
// Add test props
});
expect(aggregate).toBeDefined();
expect(aggregate.id).toBeDefined();
});
});
${aggregate.methods.map(m => `
describe('${m.name}', () => {
it('should ${m.description.get(SupportedLanguage.EN)}', () => {
// Test implementation
});
});`).join('\n')}
describe('invariants', () => {
${aggregate.invariants.map(inv => `
it('should enforce: ${inv}', () => {
// Test invariant
});`).join('\n')}
});
});`;
}
/**
* Generate repository interface
*/
private generateRepositoryInterface(
aggregate: AggregateDefinition,
options: any,
): string {
const className = aggregate.name.get(SupportedLanguage.EN);
return `import { ${className} } from './${className}';
import { IRepository, EntityId } from '@claude-flow/domain';
export interface I${className}Repository extends IRepository<${className}> {
// Custom query methods
findByName(name: string): Promise<${className} | null>;
// Add more custom queries as needed
}`;
}
/**
* Generate service code
*/
private generateServiceCode(
service: ServiceDefinition,
options: any,
): string {
const className = service.name.get(SupportedLanguage.EN);
return `import { DomainService } from '@claude-flow/domain';
${service.dependencies.map(dep => `import { ${dep} } from './${dep}';`).join('\n')}
export class ${className} extends DomainService {
constructor(
${service.dependencies.map(dep => ` private ${dep.toLowerCase()}: ${dep},`).join('\n')}
) {
super('${className}');
}
${service.operations.map(op => `
async ${op.name}(${op.parameters.map(p => `${p.name}: ${p.type}`).join(', ')}): Promise<${op.returnType}> {
// ${op.description.get(SupportedLanguage.EN)}
throw new Error('Not implemented');
}`).join('\n')}
}`;
}
/**
* Validate domain model
*/
async validateDomainModel(contextId: string): Promise<{
valid: boolean;
issues: string[];
suggestions: string[];
}> {
const context = this.boundedContexts.get(contextId);
if (!context) {
throw new Error(`Bounded context not found: ${contextId}`);
}
const issues: string[] = [];
const suggestions: string[] = [];
// Validate aggregates
for (const aggregate of context.aggregates) {
// Check for aggregate root
if (!aggregate.properties.some(p => p.name === 'id')) {
issues.push(`Aggregate ${aggregate.name.get(SupportedLanguage.EN)} missing id property`);
}
// Check for at least one method
if (aggregate.methods.length === 0) {
suggestions.push(`Aggregate ${aggregate.name.get(SupportedLanguage.EN)} has no behavior - consider if it should be a value object`);
}
// Check for invariants
if (aggregate.invariants.length === 0) {
suggestions.push(`Aggregate ${aggregate.name.get(SupportedLanguage.EN)} has no invariants - add business rules`);
}
}
// Check for bounded context cohesion
if (context.aggregates.length > 10) {
suggestions.push('Bounded context might be too large - consider splitting');
}
return {
valid: issues.length === 0,
issues,
suggestions,
};
}
/**
* Execute DDD command
*/
async executeCommand(command: ICommand): Promise<ICommandResult> {
this.logger.info('Executing DDD command', {
type: command.constructor.name,
id: command.id,
});
return await this.commandBus.execute(command);
}
/**
* Execute multiple commands in a transaction
*/
async executeCommandSequence(commands: ICommand[]): Promise<ICommandResult[]> {
this.logger.info('Executing command sequence', {
count: commands.length,
});
const results: ICommandResult[] = [];
for (const command of commands) {
const result = await this.executeCommand(command);
results.push(result);
// Stop on first failure
if (!result.success) {
this.logger.error('Command sequence failed', {
failedCommand: command.id,
error: result.error,
});
break;
}
}
return results;
}
/**
* Register custom command handler
*/
registerCommandHandler<TCommand extends ICommand>(
commandType: string,
handler: any,
): void {
this.commandBus.register(commandType, handler);
this.commandHandlers.set(commandType, handler);
this.logger.info('Registered command handler', { commandType });
}
/**
* Get current development status
*/
getStatus(): {
phase: DDDPhase;
boundedContexts: number;
aggregates: number;
services: number;
events: number;
} {
let totalAggregates = 0;
let totalServices = 0;
let totalEvents = 0;
for (const context of this.boundedContexts.values()) {
totalAggregates += context.aggregates.length;
totalServices += context.services.length;
totalEvents += context.events.length;
}
return {
phase: this.currentPhase,
boundedContexts: this.boundedContexts.size,
aggregates: totalAggregates,
services: totalServices,
events: totalEvents,
};
}
}