Skip to main content

The Nodevel Framework

Nodevel (v1.1, the core/ directory in each repo) is a lightweight, in-house dependency-injection boot framework over Express + Mongoose + Redis. It is shared by three services: backend, ms-communication, and ms-sessions. (ms-ai does not use it — it's NestJS.)

If you've worked in one Nodevel service, the others are structurally identical.

The boot sequence

// index.js
require('./otel.js') // tracing/Sentry first
const Application = require('./core/application.js')
new Application().run()

core/application.js run() executes a fixed sequence:

  1. loadEnvironmentSettings() — dotenv → a global Config singleton.
  2. loadDependencySettings() — build the DI container; resolve models, services, and controllers.
  3. loadHookSettings() — run app/hooks.js boot() then server().
  4. loadRouteSettings() — load route files referenced from app/configs/routes.js / app/routes/api.js.
  5. startServer() — bind HTTP (and attach Socket.IO), unless global.__skip_server = true (used by worker processes).

Core components

PathRole
core/application.jsBoot orchestrator (the sequence above)
core/dependency/resolver.jsDI container — maps app.models.UserModel → a singleton instance; caches in global.__resolver_cache
core/http/router.jsExpress wrapper (Router.get/post, middleware chaining)
core/helpers/config.jsConfig singleton — Config.get('redis.host')
core/controller.jsBase controller + DI injection

The app/ layout (every Nodevel service)

app/
├── configs/ service toggles, database, redis, routes, integrations
├── controllers/ request handlers (resolved + injected by the DI container)
├── models/ Mongoose models
├── routes/ route files; api.js is the root
├── services/ singletons loaded via app.loadService(...)
├── jobs/ cron jobs (node-cron, wrapped by a monitor)
├── lib/ helpers/ shared utilities
└── hooks.js boot(app) — init DB/services/middleware; server(app) — sockets, error handlers

Magic methods

The framework decorates the Express application with helpers:

app.loadService('redis', 'app.services.RedisService') // register a singleton service
app.dependOn('some-package') // ensure an npm dep is present
express_application.controller('UserController') // fetch a resolved controller

app/hooks.js boot() is where a service wires itself up — e.g. backend loads Redis, Auth, Mongo, Scheduler, Mailer, the identity-graph subsystem, and the Knox auto-engagement pipeline there.

Why it matters in practice

  • Services lazy-load via loadService() and are singletons — don't new them yourself.
  • Workers (e.g. ms-sessions' recording worker) reuse the same app but set __skip_server = true so they don't bind a port — they just consume queues.
  • Adding a feature means: a model in app/models/, a service in app/services/, a controller in app/controllers/, and a route file wired into app/routes/api.js — not free-form Express middleware.

Cron & queues

  • Cron is node-cron, registered through a SchedulerService and wrapped by a CronMonitor (Redis-backed run history, visible at /admin/cron in backend). It is not BullMQ.
  • BullMQ is used for heavier async work in ms-sessions (recording analysis) and ms-ai. Bull Board is mounted at /admin/queues.

This split (cron for scheduled sweeps, BullMQ for heavy pipelines) is a recurring pattern across the platform.