Uniconnect Enterprise Core — Service Dependencies, Modules, Plugins, and Optimization Plan
This document maps services to business modules and plugins, identifies key inter-service dependencies, highlights anti-patterns, and proposes optimizations to enable license-driven start/stop of services with minimal disruption.
Objectives
- Categorize all services into modules and plugins.
- Identify dependencies across services and modules.
- Recommend changes to minimize coupling and safely stop unlicensed modules/plugins.
- Provide an actionable plan to operationalize license-based start/stop.
Architecture Context
- Framework: Moleculer.js microservices (NATS-ready), Prisma (PostgreSQL)
- Gateway:
api - Auth/RBAC: JWT, roles, permissions, scopes
- Cross-cutting: Workflow orchestration, WebSocket, Config, File management
- License enforcement:
licenseservice, license-based service start/stop
Module Classification and Services
IAM (Users, Roles, Groups)
- Services:
auth,user,role,group,permission,scope
- Typical dependencies:
- Outgoing:
workflow.handleModuleEvent,system/email,file-management,websocket - Incoming: integration/webhook triggers; lookup by
calls/telephony; CRM references
- Outgoing:
Reports (Reports and Dashboard)
- Services:
report,edge-dashboard
- Typical dependencies:
websocket.sendToRoleUsers,permission.getUserPermissions, CRM data sources in some flows
Common (Logs, BullMQ, Scheduler, etc.)
- Services:
api,system(health, audit, logs, backup, update),websocket,templates(email/sms),theme,file-management,config,serviceManager,moduleManager,license
- Notes:
- These are core runtime services. In license failures, remain running.
Workflows
- Services:
workflow,workflowExecution,register
- Declared deps:
crmModuleManager,moduleManager,crm - Role: action/condition orchestration, CRM action registry, module event bus
Edge
- Services:
userEdgeConfig,edge-dashboard
- Role: edge runtime UI/config
Auri (AI)
- Services:
ai,agent,agentCall,agentChat,mcp,speech,ragconversation,summary,context,chatbot,promptBuildercube,cubeChunk,sttStream,callEvent,callSummary,rangePollingStream
- Providers (plugins):
openai,gemini - Declared deps:
ai→context,openai,gemini;rag→cube
CRM
- Services:
crm,crmModuleManager(akamoduleManagerunderservices/crm),crm-audit-log,crm-section,crm-filter,crmDependency,contacts
- Declared deps:
crm→permission - Notes: dynamic schema/actions; heavy workflow integration
Campaign
- Services:
campaign,campaign_voice,campaign_sms
- Declared deps:
campaign→crm,calls,3cx-api - Notes: audience via CRM; dispositioning; telephony & SMS execution
Telephony
- Services:
calls,activecalls,livecalls,call-popup,presence-status,user-status,user-status-log
- Plugins:
3cx-api,3cx-tcp,3cx-db - Notes: live call state, presence changes, queue login/ringing/mobile, CDR
Integration (API / WebHook)
- Services:
integration,webhook
- Notes: external API/webhook; emits workflow events; service users
SMS
- Services:
sms,sms_2,sms-notify
- Providers (plugins):
hutch(example generic SMS) - Declared deps:
sms→module,serviceManager
Email
- Services:
email,system/email,email-templates
- Providers (plugins):
smtp,mailgun,sendgrid,aws-ses - Declared deps:
email→module;smtp→config
Workforce Management (Shift and Status)
- Services:
shift,presence-status,user-status,user-status-log
- Notes: shifts impact campaign continuation; presence integrates with telephony provider
Plugin Classification
- Telephony:
3cx-api,3cx-tcp,3cx-db - AI:
openai,gemini - Email:
smtp,mailgun,sendgrid,aws-ses - SMS:
hutch(and other generic SMS providers) - Extensible:
Twilio,ElevenLabs, etc. (not currently present, but plan to integrate viaserviceManager)
Declared Dependencies (from service definitions)
workflow:crmModuleManager,moduleManager,crmregister:crmModuleManager,moduleManager,crm,workflowwebsocket:apicrm:permissioncampaign:crm,calls,3cx-apiactivecalls:3cx-apiemail:module;smtp:configsms:module,serviceManagerai:context,openai,gemini;rag:cube
Observed Inter‑Service Calls (selected)
- Workflow: calls into CRM module manager and CRM; queues/execution; emits events
- CRM: frequent
workflow.handleModuleEvent; callscube.generateSchema;file-management - Campaign: CRM audience; DNC checks;
3cx-api.makeCall;sms.send;group.get; logging - Telephony:
3cx-apilive calls, user/group/IVR sync;workflow.handleModuleEvent; WebSocket updates - IAM:
authintegrates3cx-api.signIn;usersendssystem/email, syncs 3CX users - Email/SMS: provider selection via
serviceManager.find; attachments viafile-management - AI (Auri):
ai.generate,conversation/context/summary; live transcription; updatesactivecalls - Integration/Webhook: emits
workflow.handleModuleEvent; manages service users - WebSocket: sends to users/roles; queries users and CRM queues
License‑Based Start/Stop — Current State
licenseservice enforces running/stopping based on each service’ssettings.licenseModulesandsettings.alwaysOn.commonServicesconfigured inconfig/service-modules.json:api,config,license,websocket,auth,user.- Only a few services currently set
settings.licenseModules(e.g.,crm,contacts,campaign). Many are missing, causing incomplete enforcement.
Anti‑Patterns and Risks
- Hard coupling to provider services:
- Telephony directly calls
3cx-apifrom many modules (Campaign, Calls, Presence, IAM), limiting pluggability. - AI services directly call
openai/geminiinstead of a provider façade.
- Telephony directly calls
- Inconsistent
dependencies: [...]declarations vs. actualctx.call(...)usage → unpredictable startup/start order. - License gating gaps: actions proceed even when modules/plugins are disabled; missing guards.
- Workflow bidirectional coupling with CRM and other modules (tight entanglement) → harder isolation.
- Non-standard service file locations complicate license service’s
ensureServiceRunningpath derivation.
Optimization Recommendations
1) Provider Abstraction
- Telephony: introduce a
telephonyfaçade service (dial, presence, queues) that selects provider (3cx,twilio, …) viaserviceManager. Replace direct3cx-apicalls with façade calls. - AI: route all
ai.generateand STT/TTS through a provider selector usingserviceManagerand config. - SMS/Email already use
serviceManager.find— extend consistently across Telephony and AI.
2) License Enforcement Consistency
- Annotate services with
settings.licenseModules:- IAM:
auth,user,role,group,permission,scope→iam - Reports:
report,edge-dashboard→reports - Common: set
settings.alwaysOn: trueforapi,config,license,websocket,system,file-management,serviceManager,moduleManager,templates,theme - Workflows:
workflow,workflowExecution,register→workflows - Edge:
userEdgeConfig,edge-dashboard→edge - Auri: AI services →
auri - CRM: CRM services →
crm - Campaign:
campaign,campaign_voice,campaign_sms→campaign - Telephony:
calls,activecalls,livecalls,call-popup,presence-status→telephony - Integration:
integration,webhook→integration - SMS:
sms,sms_2,sms-notify→sms - Email:
email,system/email,email-templates→email - Workforce:
shift,user-status,user-status-log→workforce
- IAM:
- Alternatively (and complementarily), extend
config/service-modules.jsonwith a comprehensiveserviceMappingsandpathOverridesused by the license service.
3) Declared Dependencies & Guards
- Add
dependencies: [...]for services that synchronously rely on others (e.g., Telephony →serviceManager,moduleManager,websocket; Campaign →crm,calls). - At action boundaries, check availability:
moduleManager.isModuleEnabled({ moduleCode })and/or license payload.- Short-circuit with informative errors or no-op when disabled.
4) Event‑Driven Contracts
- Replace direct cross-module calls with events where possible:
- Campaign voice: emit
campaign.requestDial; Telephony provider handles execution and emits lifecycle events. - Presence updates: emit
presence.changeRequested; provider applies mapping and emitspresence.changed. - CRM schema: emit
crm.schema.updated; AI Cube regenerates.
- Campaign voice: emit
5) Path Metadata for License Loader
- Ensure all services expose metadata/filePath (or register via
pathOverridesinservice-modules.json) solicense.ensureServiceRunningcan start services correctly.
Proposed service-modules.json Extension
{
"commonServices": [
"api", "config", "license", "websocket", "system", "file-management",
"serviceManager", "moduleManager", "templates", "theme", "auth", "user"
],
"serviceMappings": [
{ "name": "auth", "modules": ["iam"] },
{ "name": "user", "modules": ["iam"] },
{ "name": "role", "modules": ["iam"] },
{ "name": "group", "modules": ["iam"] },
{ "name": "permission", "modules": ["iam"] },
{ "name": "scope", "modules": ["iam"] },
{ "name": "report", "modules": ["reports"] },
{ "name": "edge-dashboard", "modules": ["reports"] },
{ "name": "workflow", "modules": ["workflows"] },
{ "name": "workflowExecution", "modules": ["workflows"] },
{ "name": "register", "modules": ["workflows"] },
{ "name": "userEdgeConfig", "modules": ["edge"] },
{ "name": "ai", "modules": ["auri"] },
{ "name": "agents", "modules": ["auri"] },
{ "name": "agentCall", "modules": ["auri"] },
{ "name": "agentChat", "modules": ["auri"] },
{ "name": "mcp", "modules": ["auri"] },
{ "name": "speech", "modules": ["auri"] },
{ "name": "rag", "modules": ["auri"] },
{ "name": "conversation", "modules": ["auri"] },
{ "name": "summary", "modules": ["auri"] },
{ "name": "context", "modules": ["auri"] },
{ "name": "chatbot", "modules": ["auri"] },
{ "name": "promptBuilder", "modules": ["auri"] },
{ "name": "cube", "modules": ["auri"] },
{ "name": "cubeChunk", "modules": ["auri"] },
{ "name": "sttStream", "modules": ["auri"] },
{ "name": "callEvent", "modules": ["auri"] },
{ "name": "callSummary", "modules": ["auri"] },
{ "name": "rangePollingStream", "modules": ["auri"] },
{ "name": "crm", "modules": ["crm"] },
{ "name": "crmModuleManager", "modules": ["crm"] },
{ "name": "crm-audit-log", "modules": ["crm"] },
{ "name": "crm-section", "modules": ["crm"] },
{ "name": "crm-filter", "modules": ["crm"] },
{ "name": "crmDependency", "modules": ["crm"] },
{ "name": "contacts", "modules": ["crm"] },
{ "name": "campaign", "modules": ["campaign"] },
{ "name": "campaign_voice", "modules": ["campaign"] },
{ "name": "campaign_sms", "modules": ["campaign"] },
{ "name": "calls", "modules": ["telephony"] },
{ "name": "activecalls", "modules": ["telephony"] },
{ "name": "livecalls", "modules": ["telephony"] },
{ "name": "call-popup", "modules": ["telephony"] },
{ "name": "presence-status", "modules": ["telephony", "workforce"] },
{ "name": "user-status", "modules": ["workforce"] },
{ "name": "user-status-log", "modules": ["workforce"] },
{ "name": "integration", "modules": ["integration"] },
{ "name": "webhook", "modules": ["integration"] },
{ "name": "sms", "modules": ["sms"] },
{ "name": "sms_2", "modules": ["sms"] },
{ "name": "sms-notify", "modules": ["sms"] },
{ "name": "email", "modules": ["email"] },
{ "name": "system/email", "modules": ["email"] },
{ "name": "email-templates", "modules": ["email"] }
],
"pathOverrides": {
"api": "services/api.service.js",
"system": "services/system/system.service.js",
"websocket": "services/websocket/websocket.service.js",
"file-management": "services/fileUpload/file-management.service.js",
"templates": "services/templates/templateManager.service.js",
"theme": "services/theme/theme.service.js",
"workflow": "services/workflow/workflow.service.js",
"workflowExecution": "services/workflow/workflowExecution.service.js",
"register": "services/workflow/register.service.js",
"crm": "services/crm/crm.service.js",
"crmModuleManager": "services/crm/moduleManager.service.js",
"crm-audit-log": "services/crm/crmAuditLog.service.js",
"crm-section": "services/crm/section.service.js",
"crm-filter": "services/crm/filter.service.js",
"crmDependency": "services/crm/dependency.service.js",
"contacts": "services/contacts/contacts.service.js",
"campaign": "services/campaign/campaign.service.js",
"campaign_sms": "services/campaign/sms/sms.service.js",
"campaign_voice": "services/campaign/voice/voice.service.js",
"calls": "services/channels/calls/calls.service.js",
"activecalls": "services/channels/calls/activecalls.service.js",
"livecalls": "services/channels/calls/livecalls.service.js",
"call-popup": "services/call-popup/callpopup.service.js",
"presence-status": "services/presence-status/presence-status.service.js",
"user-status": "services/presence-status/user-status.service.js",
"user-status-log": "services/presence-status/user-status-log.service.js",
"integration": "services/integration/integration.service.js",
"webhook": "services/webhook/webhook.service.js",
"sms": "services/channels/sms/sms.service.js",
"sms_2": "services/channels/sms/sms2.service.js",
"sms-notify": "services/channels/sms/sms-notify.service.js",
"email": "services/channels/email/email.service.js",
"system/email": "services/channels/email/system-email.service.js",
"email-templates": "services/templates/emailTemplate/emailTemplate.service.js"
}
}
Note: This JSON is additive to the existing file. It should replace/merge entries to reflect the complete service list.
Implementation Plan
- Phase 1 (Config‑only): Extend
config/service-modules.jsonwith above mappings, ensurepathOverridescover non-standard locations. License service can leverage this mapping or you can annotate services progressively. - Phase 2 (Service annotations): Add
settings.licenseModules(andsettings.alwaysOn) to services per module classification. - Phase 3 (Provider façades): Introduce
telephonyand AI provider selectors viaserviceManager; refactor direct provider calls. - Phase 4 (Guards & dependencies): Add
dependencies: [...]declarations and action guards usingmoduleManager.isModuleEnabled/license payload. - Phase 5 (Events): Replace direct calls with domain events for dial/presence/schema updates.
Risks & Mitigations
- Stopping services may break callers expecting them — add guards and event-based fallbacks.
- Startup order issues — use
dependenciesandwaitForServices. - Provider health —
serviceManagershould surface capability and health, with retries/backoff.
Next Steps
- Approve the
service-modules.jsonextension. - Decide whether to annotate services first or update the license service to read
service-modules.jsonmappings for enforcement. - I can proceed to implement Phase 1 and annotate a first batch of services (IAM, CRM, Campaign, Telephony, Email, SMS, Workflows).
Visual Map (Single Mermaid Diagram)
Legend: modules (light yellow), plugins (light blue), services (light purple). Red edges mark anti‑patterns. Bidirectional arrows added for key dependencies to reflect incoming and outgoing flows.