Skip to main content

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: license service, 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

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, rag
    • conversation, summary, context, chatbot, promptBuilder
    • cube, cubeChunk, sttStream, callEvent, callSummary, rangePollingStream
  • Providers (plugins): openai, gemini
  • Declared deps: aicontext, openai, gemini; ragcube

CRM

  • Services:
    • crm, crmModuleManager (aka moduleManager under services/crm), crm-audit-log, crm-section, crm-filter, crmDependency, contacts
  • Declared deps: crmpermission
  • Notes: dynamic schema/actions; heavy workflow integration

Campaign

  • Services:
    • campaign, campaign_voice, campaign_sms
  • Declared deps: campaigncrm, 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: smsmodule, serviceManager

Email

  • Services:
    • email, system/email, email-templates
  • Providers (plugins): smtp, mailgun, sendgrid, aws-ses
  • Declared deps: emailmodule; smtpconfig

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 via serviceManager)

Declared Dependencies (from service definitions)

  • workflow: crmModuleManager, moduleManager, crm
  • register: crmModuleManager, moduleManager, crm, workflow
  • websocket: api
  • crm: permission
  • campaign: crm, calls, 3cx-api
  • activecalls: 3cx-api
  • email: module; smtp: config
  • sms: module, serviceManager
  • ai: 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; calls cube.generateSchema; file-management
  • Campaign: CRM audience; DNC checks; 3cx-api.makeCall; sms.send; group.get; logging
  • Telephony: 3cx-api live calls, user/group/IVR sync; workflow.handleModuleEvent; WebSocket updates
  • IAM: auth integrates 3cx-api.signIn; user sends system/email, syncs 3CX users
  • Email/SMS: provider selection via serviceManager.find; attachments via file-management
  • AI (Auri): ai.generate, conversation/context/summary; live transcription; updates activecalls
  • Integration/Webhook: emits workflow.handleModuleEvent; manages service users
  • WebSocket: sends to users/roles; queries users and CRM queues

License‑Based Start/Stop — Current State

  • license service enforces running/stopping based on each service’s settings.licenseModules and settings.alwaysOn.
  • commonServices configured in config/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-api from many modules (Campaign, Calls, Presence, IAM), limiting pluggability.
    • AI services directly call openai/gemini instead of a provider façade.
  • Inconsistent dependencies: [...] declarations vs. actual ctx.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 ensureServiceRunning path derivation.

Optimization Recommendations

1) Provider Abstraction

  • Telephony: introduce a telephony façade service (dial, presence, queues) that selects provider (3cx, twilio, …) via serviceManager. Replace direct 3cx-api calls with façade calls.
  • AI: route all ai.generate and STT/TTS through a provider selector using serviceManager and 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, scopeiam
    • Reports: report, edge-dashboardreports
    • Common: set settings.alwaysOn: true for api, config, license, websocket, system, file-management, serviceManager, moduleManager, templates, theme
    • Workflows: workflow, workflowExecution, registerworkflows
    • Edge: userEdgeConfig, edge-dashboardedge
    • Auri: AI services → auri
    • CRM: CRM services → crm
    • Campaign: campaign, campaign_voice, campaign_smscampaign
    • Telephony: calls, activecalls, livecalls, call-popup, presence-statustelephony
    • Integration: integration, webhookintegration
    • SMS: sms, sms_2, sms-notifysms
    • Email: email, system/email, email-templatesemail
    • Workforce: shift, user-status, user-status-logworkforce
  • Alternatively (and complementarily), extend config/service-modules.json with a comprehensive serviceMappings and pathOverrides used 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 emits presence.changed.
    • CRM schema: emit crm.schema.updated; AI Cube regenerates.

5) Path Metadata for License Loader

  • Ensure all services expose metadata/filePath (or register via pathOverrides in service-modules.json) so license.ensureServiceRunning can 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.json with above mappings, ensure pathOverrides cover non-standard locations. License service can leverage this mapping or you can annotate services progressively.
  • Phase 2 (Service annotations): Add settings.licenseModules (and settings.alwaysOn) to services per module classification.
  • Phase 3 (Provider façades): Introduce telephony and AI provider selectors via serviceManager; refactor direct provider calls.
  • Phase 4 (Guards & dependencies): Add dependencies: [...] declarations and action guards using moduleManager.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 dependencies and waitForServices.
  • Provider health — serviceManager should surface capability and health, with retries/backoff.

Next Steps

  • Approve the service-modules.json extension.
  • Decide whether to annotate services first or update the license service to read service-modules.json mappings 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.