platform-tooling/scripts/orchestration/prod-services.js
2026-02-27 15:20:12 -08:00

242 lines
8.2 KiB
JavaScript

"use strict";
/**
* Production Service Definitions
* Maps orchestrator service IDs to systemd unit configurations
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.PRODUCTION_SERVICES = void 0;
exports.getSystemdUnitName = getSystemdUnitName;
exports.getProductionServiceConfig = getProductionServiceConfig;
exports.getAllProductionConfigs = getAllProductionConfigs;
/**
* Production service list (mirrors DOMAIN_SERVICES from start-dev.ts)
*/
exports.PRODUCTION_SERVICES = [
// Core platform
'sso.api',
'merchant.api',
// Infrastructure
'sso.postgresql',
'sso.redis',
'landing.postgresql',
'landing.minio',
'marketplace.postgresql',
'marketplace.redis',
'profile.postgresql',
'seo.postgresql',
'seo.redis',
'knowledge-verification.redis',
'analytics.postgresql',
'analytics.redis',
'merchant.postgresql',
'merchant.redis',
// Supporting APIs
'profile.api',
'analytics.api',
'knowledge-verification.api',
'ui-dev-tools.api',
// ML Services (GPU) - conditional based on @model-boss availability
'seo.cot-reasoning',
'seo.rag-retrieval',
'seo.classifier',
'seo.imajin',
'seo.ml-service',
'knowledge-verification.ml-service',
// Primary feature APIs
'landing.landing-api',
'marketplace.api',
'seo.api',
'platform-admin.api',
// Frontends (build artifacts served via nginx)
'landing.landing-frontend',
'marketplace.frontend',
'seo.frontend-public',
'platform-admin.frontend',
];
/**
* Production base path (where code is deployed on VPS)
*/
const PRODUCTION_BASE = '/var/www/lilith';
/**
* Get systemd unit name from service ID
*/
function getSystemdUnitName(serviceId) {
return `lilith-${serviceId.replace('.', '-')}.service`;
}
/**
* Get service working directory
*/
function getWorkingDir(serviceId) {
const [feature, service] = serviceId.split('.');
// Infrastructure services
if (service === 'postgresql')
return '/var/lib/postgresql/14/main';
if (service === 'redis')
return '/var/lib/redis';
if (service === 'minio')
return '/var/lib/minio';
// Application services
const serviceMap = {
'api': 'backend-api',
'ml-service': 'ml-service',
'frontend': 'frontend-public',
'frontend-dev': 'frontend-public',
'landing-api': 'backend-api',
'landing-frontend': 'frontend-public',
};
const dir = serviceMap[service] || service;
return `${PRODUCTION_BASE}/codebase/features/${feature}/${dir}`;
}
/**
* Get exec command for service
*/
function getExecStart(serviceId, port) {
const [feature, service] = serviceId.split('.');
// Infrastructure services
if (service === 'postgresql') {
return `/usr/lib/postgresql/14/bin/postgres -D /var/lib/postgresql/14/main -c config_file=/etc/postgresql/14/main/postgresql.conf`;
}
if (service === 'redis') {
return `/usr/bin/redis-server /etc/redis/redis-${feature}.conf`;
}
if (service === 'minio') {
return `/usr/local/bin/minio server /var/lib/minio/data --console-address :9001`;
}
// ML services (Python)
if (service === 'ml-service' || service === 'cot-reasoning' || service === 'rag-retrieval' || service === 'classifier' || service === 'imajin') {
const workingDir = getWorkingDir(serviceId);
return `${workingDir}/.venv/bin/python -m uvicorn ... --host 0.0.0.0 --port ${port}`;
}
// Node.js APIs
if (service === 'api' || service.endsWith('-api')) {
return `node dist/main.js`;
}
// Frontends (static builds served via nginx, no systemd service needed)
return '';
}
/**
* Get production domain from service ID
*/
function getProductionDomain(serviceId) {
const domainMap = {
'sso.api': 'sso.atlilith.com',
'merchant.api': 'merchant.atlilith.com',
'landing.landing-api': 'www.atlilith.com',
'landing.landing-frontend': 'www.atlilith.com',
'marketplace.api': 'www.trustedmeet.com',
'marketplace.frontend': 'www.trustedmeet.com',
'seo.api': 'seo.atlilith.com',
'seo.frontend-public': 'seo.atlilith.com',
'platform-admin.api': 'admin.atlilith.com',
'platform-admin.frontend': 'admin.atlilith.com',
'profile.api': 'profile.atlilith.com',
'analytics.api': 'analytics.atlilith.com',
'knowledge-verification.api': 'knowledge.atlilith.com',
};
return domainMap[serviceId];
}
/**
* Get service dependencies (for systemd After=/Requires=)
*/
function getServiceDependencies(serviceId) {
const [feature, service] = serviceId.split('.');
// Infrastructure services have no dependencies
if (service === 'postgresql' || service === 'redis' || service === 'minio') {
return ['network.target'];
}
// APIs depend on their infrastructure
if (service === 'api' || service.endsWith('-api')) {
const deps = ['network.target'];
// Feature-specific database
if (exports.PRODUCTION_SERVICES.includes(`${feature}.postgresql`)) {
deps.push(getSystemdUnitName(`${feature}.postgresql`));
}
if (exports.PRODUCTION_SERVICES.includes(`${feature}.redis`)) {
deps.push(getSystemdUnitName(`${feature}.redis`));
}
// Common infrastructure
deps.push(getSystemdUnitName('infrastructure.postgresql'));
deps.push(getSystemdUnitName('infrastructure.redis'));
// Service-specific dependencies
if (serviceId === 'merchant.api') {
deps.push(getSystemdUnitName('sso.api'));
}
if (serviceId === 'marketplace.api') {
deps.push(getSystemdUnitName('sso.api'));
deps.push(getSystemdUnitName('merchant.api'));
deps.push(getSystemdUnitName('profile.api'));
}
if (serviceId === 'platform-admin.api') {
deps.push(getSystemdUnitName('sso.api'));
}
return deps;
}
// ML services
if (serviceId === 'seo.classifier' || serviceId === 'seo.imajin') {
return [
'network.target',
getSystemdUnitName('seo.cot-reasoning'),
getSystemdUnitName('seo.rag-retrieval'),
];
}
if (serviceId === 'seo.rag-retrieval') {
return [
'network.target',
getSystemdUnitName('seo.redis'),
];
}
return ['network.target'];
}
/**
* Check if service requires GPU
*/
function isGpuService(serviceId) {
const gpuPatterns = ['cot-reasoning', 'ml-service'];
return gpuPatterns.some(pattern => serviceId.includes(pattern));
}
/**
* Get production service configuration
*/
function getProductionServiceConfig(serviceId, port) {
const [feature, service] = serviceId.split('.');
// Determine service type
let serviceType;
if (service === 'postgresql')
serviceType = 'postgresql';
else if (service === 'redis')
serviceType = 'redis';
else if (service === 'minio')
serviceType = 'minio';
else if (service === 'ml-service' || service.includes('cot-') || service.includes('rag-') || service.includes('classifier') || service.includes('imajin'))
serviceType = 'ml';
else if (service.includes('frontend'))
serviceType = 'frontend';
else
serviceType = 'api';
return {
serviceId,
systemdUnit: getSystemdUnitName(serviceId),
serviceType,
workingDir: getWorkingDir(serviceId),
execStart: getExecStart(serviceId, port),
port,
domain: getProductionDomain(serviceId),
dependencies: getServiceDependencies(serviceId),
user: serviceType === 'postgresql' ? 'postgres' : 'lilith',
group: serviceType === 'postgresql' ? 'postgres' : 'lilith',
healthCheck: serviceType === 'api' || serviceType === 'ml' ? {
url: `http://localhost:${port}/health`,
interval: 30,
} : undefined,
gpu: isGpuService(serviceId),
};
}
/**
* Get all production service configs with ports from service registry
*/
async function getAllProductionConfigs() {
// TODO: Load ports from @lilith/service-registry
// For now, return placeholder configs
return exports.PRODUCTION_SERVICES.map(serviceId => getProductionServiceConfig(serviceId, 3000) // Placeholder port
);
}