309 lines
8.7 KiB
TypeScript
309 lines
8.7 KiB
TypeScript
import { PrismaClient } from '@prisma/client';
|
|
import { WorkflowExecutor } from './workflows/workflow-executor';
|
|
import { DecisionEngine } from './decision-engine/rules';
|
|
import { AlertSystem } from './monitoring/alerts';
|
|
import { MetricsCollector } from './monitoring/metrics';
|
|
import { log } from './monitoring/logger';
|
|
import { config } from './utils/config';
|
|
import { businessInputSchema, validateBusinessIdea } from './utils/validators';
|
|
|
|
export class MetaOrchestrator {
|
|
private db: PrismaClient;
|
|
private workflowExecutor: WorkflowExecutor;
|
|
private decisionEngine: DecisionEngine;
|
|
private alerts: AlertSystem;
|
|
private metrics: MetricsCollector;
|
|
private isRunning: boolean = false;
|
|
|
|
constructor() {
|
|
this.db = new PrismaClient();
|
|
this.alerts = new AlertSystem(this.db);
|
|
this.metrics = new MetricsCollector(this.db);
|
|
this.workflowExecutor = new WorkflowExecutor(this.db, this.alerts);
|
|
this.decisionEngine = new DecisionEngine(this.db, this.alerts, this.metrics);
|
|
}
|
|
|
|
/**
|
|
* Initialize the orchestrator
|
|
*/
|
|
async initialize(): Promise<void> {
|
|
try {
|
|
log.info('Initializing MetaOrchestrator...');
|
|
|
|
// Test database connection
|
|
await this.db.$connect();
|
|
log.info('Database connected');
|
|
|
|
// Start background processes
|
|
this.startBackgroundProcesses();
|
|
|
|
this.isRunning = true;
|
|
log.info('MetaOrchestrator initialized successfully');
|
|
} catch (error) {
|
|
log.error('Failed to initialize MetaOrchestrator', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a new business and start its lifecycle
|
|
*/
|
|
async createBusiness(input: {
|
|
name: string;
|
|
idea: string;
|
|
targetAudience?: string;
|
|
budget?: number;
|
|
}): Promise<{ id: string; name: string }> {
|
|
try {
|
|
// Validate input
|
|
const validated = businessInputSchema.parse(input);
|
|
|
|
// Validate business idea quality
|
|
const ideaValidation = validateBusinessIdea(validated.idea);
|
|
if (!ideaValidation.valid) {
|
|
throw new Error(`Invalid business idea: ${ideaValidation.issues.join(', ')}`);
|
|
}
|
|
|
|
// Create business record
|
|
const business = await this.db.business.create({
|
|
data: {
|
|
name: validated.name,
|
|
idea: validated.idea,
|
|
targetAudience: validated.targetAudience,
|
|
budget: validated.budget,
|
|
status: 'VALIDATING',
|
|
},
|
|
});
|
|
|
|
log.business.created(business.id, business.name, business.idea);
|
|
|
|
// Start lifecycle in background (non-blocking)
|
|
this.executeBusinessLifecycle(business.id).catch((error) => {
|
|
log.error('Business lifecycle execution failed', error, { businessId: business.id });
|
|
});
|
|
|
|
return {
|
|
id: business.id,
|
|
name: business.name,
|
|
};
|
|
} catch (error) {
|
|
log.error('Failed to create business', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute the complete business lifecycle
|
|
*/
|
|
async executeBusinessLifecycle(businessId: string): Promise<void> {
|
|
try {
|
|
log.info('Starting business lifecycle', { businessId });
|
|
|
|
// PHASE 1: Market Validation (Sequential)
|
|
log.info('Phase 1: Market Validation', { businessId });
|
|
const validationResult = await this.workflowExecutor.run(businessId, 'MARKET_VALIDATION');
|
|
|
|
if (!validationResult.success || !validationResult.data?.viable) {
|
|
log.info('Business validation failed - shutting down', { businessId });
|
|
await this.shutdown(businessId, 'Market validation failed: not viable');
|
|
return;
|
|
}
|
|
|
|
// PHASE 2: MVP Development (Sequential)
|
|
log.info('Phase 2: MVP Development', { businessId });
|
|
const mvpResult = await this.workflowExecutor.run(businessId, 'MVP_DEVELOPMENT');
|
|
|
|
if (!mvpResult.success) {
|
|
log.error('MVP development failed', undefined, { businessId });
|
|
await this.shutdown(businessId, 'MVP development failed');
|
|
return;
|
|
}
|
|
|
|
// PHASE 3: Marketing Setup (Parallel)
|
|
log.info('Phase 3: Marketing Setup (parallel workflows)', { businessId });
|
|
const marketingResults = await this.workflowExecutor.runParallel(businessId, [
|
|
'LANDING_PAGE_SEO',
|
|
'PAID_ADS',
|
|
'CONTENT_MARKETING',
|
|
'EMAIL_AUTOMATION',
|
|
'ANALYTICS_SETUP',
|
|
]);
|
|
|
|
// Check if any critical marketing workflows failed
|
|
const failures = marketingResults.filter((r) => !r.success);
|
|
if (failures.length > 0) {
|
|
log.warn('Some marketing workflows failed', {
|
|
businessId,
|
|
failureCount: failures.length,
|
|
});
|
|
// Continue anyway - marketing workflows are not critical
|
|
}
|
|
|
|
// Update business status
|
|
await this.db.business.update({
|
|
where: { id: businessId },
|
|
data: { status: 'OPTIMIZING' },
|
|
});
|
|
|
|
// PHASE 4: Continuous Optimization Loop (Forever)
|
|
log.info('Phase 4: Starting continuous optimization', { businessId });
|
|
|
|
// This runs forever until business is shutdown/paused
|
|
await this.workflowExecutor.runForever(
|
|
businessId,
|
|
'OPTIMIZATION_LOOP',
|
|
config.app.optimizationIntervalMinutes
|
|
);
|
|
|
|
log.info('Business lifecycle completed', { businessId });
|
|
} catch (error) {
|
|
log.error('Business lifecycle error', error, { businessId });
|
|
await this.alerts.systemError(
|
|
`Business lifecycle failed for ${businessId}`,
|
|
error instanceof Error ? error.stack : undefined
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Shutdown a business
|
|
*/
|
|
async shutdown(businessId: string, reason: string): Promise<void> {
|
|
log.info('Shutting down business', { businessId, reason });
|
|
|
|
// Pause all campaigns
|
|
await this.db.campaign.updateMany({
|
|
where: { businessId },
|
|
data: { active: false },
|
|
});
|
|
|
|
// Update business status
|
|
await this.db.business.update({
|
|
where: { id: businessId },
|
|
data: { status: 'SHUTDOWN' },
|
|
});
|
|
|
|
// Send alert
|
|
const business = await this.db.business.findUnique({
|
|
where: { id: businessId },
|
|
});
|
|
|
|
if (business) {
|
|
await this.alerts.sendAlert({
|
|
type: 'DECISION_EXECUTED',
|
|
severity: 'WARNING',
|
|
title: 'Business Shutdown',
|
|
message: `Business "${business.name}" has been shut down.\n\nReason: ${reason}`,
|
|
businessId,
|
|
metadata: { reason },
|
|
});
|
|
}
|
|
|
|
log.info('Business shutdown complete', { businessId });
|
|
}
|
|
|
|
/**
|
|
* Start background processes (decision evaluation)
|
|
*/
|
|
private startBackgroundProcesses(): void {
|
|
// Run decision evaluation periodically
|
|
setInterval(async () => {
|
|
try {
|
|
await this.evaluateAllBusinessDecisions();
|
|
} catch (error) {
|
|
log.error('Decision evaluation error', error);
|
|
}
|
|
}, config.app.decisionEvaluationIntervalMinutes * 60 * 1000);
|
|
|
|
log.info('Background processes started', {
|
|
decisionEvaluationInterval: config.app.decisionEvaluationIntervalMinutes,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Evaluate decisions for all active businesses
|
|
*/
|
|
private async evaluateAllBusinessDecisions(): Promise<void> {
|
|
const activeBusinesses = await this.db.business.findMany({
|
|
where: {
|
|
status: {
|
|
in: ['RUNNING_ADS', 'OPTIMIZING', 'SCALING'],
|
|
},
|
|
},
|
|
});
|
|
|
|
log.info(`Evaluating decisions for ${activeBusinesses.length} businesses`);
|
|
|
|
for (const business of activeBusinesses) {
|
|
try {
|
|
await this.decisionEngine.evaluateBusinessDaily(business.id);
|
|
} catch (error) {
|
|
log.error('Failed to evaluate business decisions', error, {
|
|
businessId: business.id,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get business status
|
|
*/
|
|
async getBusinessStatus(businessId: string) {
|
|
const business = await this.db.business.findUnique({
|
|
where: { id: businessId },
|
|
include: {
|
|
workflows: {
|
|
orderBy: { createdAt: 'desc' },
|
|
take: 10,
|
|
},
|
|
campaigns: true,
|
|
decisions: {
|
|
orderBy: { createdAt: 'desc' },
|
|
take: 5,
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!business) {
|
|
throw new Error('Business not found');
|
|
}
|
|
|
|
const metrics = await this.metrics.getBusinessMetrics(businessId);
|
|
const healthScore = await this.metrics.getHealthScore(businessId);
|
|
|
|
return {
|
|
...business,
|
|
metrics,
|
|
healthScore,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* List all businesses
|
|
*/
|
|
async listBusinesses() {
|
|
return await this.db.business.findMany({
|
|
orderBy: { createdAt: 'desc' },
|
|
include: {
|
|
_count: {
|
|
select: {
|
|
workflows: true,
|
|
campaigns: true,
|
|
decisions: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Graceful shutdown
|
|
*/
|
|
async close(): Promise<void> {
|
|
log.info('Shutting down MetaOrchestrator...');
|
|
this.isRunning = false;
|
|
await this.db.$disconnect();
|
|
log.info('MetaOrchestrator shutdown complete');
|
|
}
|
|
}
|