GenieACS is a TR-069 Auto Configuration Server for remote management of CPE devices (routers, modems, gateways). TypeScript codebase compiled with esbuild, backed by MongoDB.
Four services share a single MongoDB instance:
- CWMP (port 7547) — TR-069 protocol handler; manages device sessions
- NBI (port 7557) — Northbound REST API for external consumers
- FS (port 7567) — File server for firmware/config (GridFS-backed)
- UI (port 3000) — Web interface (Koa backend + Mithril.js SPA frontend)
Key subsystems: expression engine (lib/common/expression/) compiles a
Lisp-like DSL used for queries, config, and authorization; session engine
(lib/session.ts) drives CWMP interactions via declarations rather than
imperative RPCs; sandbox (lib/sandbox.ts) runs user-defined provision scripts
in vm.Script with deterministic replay.
Read ARCHITECTURE.md for a full map of the codebase when working on unfamiliar
areas. It covers service boundaries, the expression pipeline, the path system,
the CWMP session state machine, the database layer, and architectural
invariants.
lib/— Core server-side logiclib/common/— Shared code (runs in both Node.js and browser)lib/db/— MongoDB database layerlib/ui/— UI backend helpersui/— Frontend SPA (Mithril.js)bin/— Service entry points (5 executables)build/— Build scripts (esbuild pipeline)test/— Unit tests (node:test)docs/— User docs (Sphinx/reStructuredText)public/— Static assets (favicon, logo)
npm run build # Production build (esbuild pipeline -> dist/)
NODE_ENV=development npm run build # Dev build (no minification)
npm run lint # Prettier + ESLint + tsc --noEmit in parallel
npm test # Compile tests with esbuild, run with node --testesbuild --log-level=warning --bundle --platform=node --target=node18 \
--packages=external --sourcemap=inline --outdir=test test/path.ts \
&& node --test --enable-source-maps test/path.js \
&& rm test/path.jsesbuild --log-level=warning --bundle --platform=node --target=node18 \
--packages=external --sourcemap=inline --outdir=test test/path.ts \
&& node --test --enable-source-maps --test-name-pattern="^parse$" test/path.js \
&& rm test/path.jsprettier --prose-wrap always --write .
eslint 'bin/*.ts' 'lib/**/*.ts' 'ui/**/*.ts' 'test/**/*.ts' 'build/**/*.ts'
tsc --noEmitRead CONTRIBUTING.md and ensure your changes comply with it. In particular:
- Run
npm run lintandnpm testand fix any failures. - Follow the code style, naming, import, and comment conventions documented there.
- Use the Conventional Commits format for commit messages.