esign_oss

One-liner (verified from README.md + package.json:4)

“FaceKom eSign operator side server” — the OSS (Operator-Side Server) of the FaceKom eSign product. A Node.js monolith that backs the bank/operator web back-office, the mobile-app-facing endpoints, the external bank webhook API, and the RabbitMQ RPC surface for the rest of the eSign system. Sibling repos referenced from code: the CSS (customer-side server, queue esign:css-ping), vuer integration (queues vuer-esign-rpc, esign-vuer-rpc, rpc-esign:external), and the portal.

This doc describes the devel base branch. The checked-out working branch at verification time was update/customization/instacash-2026-05-27 (a customization branch; see customization-branch-catalog); it differs from origin/devel only by a 4-line addition in config.js (an instacash-specific block). package.json is identical to devel. See also architecture-overview, customization-architecture.


1. Purpose & role in FaceKom

esign_oss is the operator-facing half of the FaceKom eSign two-server design. From the entrypoints and routers it provides four independently-bound surfaces (server.js:323-400):

SurfaceBindPortSourceAudience
Web (back-office UI + /api/*)127.0.0.110181server/web/web-server.jsBank operators / admins (browser)
External webhook API127.0.0.110182server/external/external-server.jsBank back-end systems (server-to-server)
Socket.IO realtime127.0.0.110180server/socket/socket-server.jsOperator browser live updates
RabbitMQ RPC/queueAMQP(S)server/queue/**CSS, vuer, cron, other services

All three HTTP servers bind to loopback only — TLS termination / public exposure is handled by nginx in front (nginx_dev.conf, nginx_docker.conf), and processes are supervised by supervisord (supervisor_docker.conf). The domain entities it owns are signing Offers, Contracts, Customers, Signatures, Documents, and the mobile App/Device registry (server/db/models.js:4-30).

.notes/signature-process.md and .notes/rest-api.md document the end-to-end customer signing flow (app registration → SMS token → operator approval → bank-signed offer → push notification → in-app signature with trusted timestamp).

Naming

Code/queues use the literal prefix esign: for OSS-owned channels and vuer-/rpc-esign:external for vuer-integration channels. The customization/ tree layers integration-specific behaviour on top of the core (see §7, customization-architecture).


2. Tech stack & runtime

Verified from package.json:

  • Language/runtime: Node.js, CommonJS (require), no TypeScript in app code (TS only as a dev/test dep for ts-jest).
  • Declared engine: engines.node: ">=22.13.0" (package.json:6-8).
  • CI Node version: NODE_VERSION: "24" (.github/workflows/pull-request.yaml:11). > [!warning] Engine vs CI mismatch — manifest floor is 22.13.0 but CI builds/tests on Node 24. Use Node ≥22.13 locally; CI is the source of truth for the tested version.
  • Package manager: Yarn (classic). yarn.lock present (447 KB); .yarnrc sets --install.ignore-optional true. CI runs yarn install --frozen-lockfile.
  • Web framework: Express 5 (express: ^5.2.1).
  • DB / ORM: PostgreSQL (pg: ^8.18.0) via Sequelize 6 (sequelize: ^6.30.1, sequelize-cli, umzug for programmatic migrations).
  • Messaging: @techteamer/mq ^7.0.1 (RabbitMQ wrapper) over amqps://.
  • Realtime: socket.io / socket.io-client ^4.6.1.
  • Templating: server-side twig ^3 (operator pages) + dustjs-linkedin (client bundles, compiled via browserify), email via inky/juice/dustjs.
  • Crypto / signing: node-jose (JWE token encryption), jsonwebtoken, @techteamer/timestamp (RFC-3161 trusted timestamps via OpenSSL), @techteamer/cert-utils (seal cert parsing), pdf-lib + @pdf-lib/fontkit (PDF signing), bcryptjs, hashids.
  • Auth/ACL: passport (+ passport-local, passport-activedirectory, passport-unique-token), @techteamer/acl, express-session + connect-session-sequelize, csurf, helmet, express-basic-auth.
  • Notifications: firebase-admin ^13.6.0 (FCM push).
  • Config: getconfig (env-driven JSON config), dotenv, cloud-config-client (optional Spring Cloud Config), ajv.
  • Client build toolchain: browserify, stylus, autoprefixer, @techteamer/poststylus, hideout, chokidar, browser-sync (livereload).
  • Lint/test: eslint 9 (flat config, eslint-config-standard), jest 30.

3. Build & run

package.json scripts (verbatim from package.json:9-21)

ScriptCommandWhat it does
stylenode bin/style/style.taskCompiles client Stylus → CSS bundles into web/css (one-shot).
scriptnode bin/script/script.taskBrowserify-bundles client *.script.js / *.layout.jsweb/js (one-shot).
watchnode bin/watch/watchRuns script + style tasks with --watch + livereload (BrowserSync).
buildnode bin/build/buildRuns both script and style tasks (pushes --no-exit); pass --watch to keep watching.
transnode bin/test/trans-checkTranslation linter: scans client/ui/pages/** twig+script for missing/unused t.t('…') keys vs each page’s *.trans.js.
linteslint . --max-warnings 0 --ignore-pattern "test/*" && echo 'npm run eslint --max-warnings 0'ESLint the repo (excluding test/), fail on any warning.
lint:fixeslint . --fix && eslint --max-warnings 0 .Auto-fix then re-lint with zero-warning gate.
creditsnode bin/credits > CREDITS.htmlRegenerates CREDITS.html dependency-license table via license-checker.
testjest --config ./test/jest.config.js --runInBand --forceExitFull Jest run, serial.
test:unityarn node --experimental-vm-modules $(yarn bin jest) --config ./test/jest.config.jsUnit-test run with ESM VM modules flag (used by CI).
test:e2eyarn jest e2e/* --forceExitE2E tests under an e2e/* path. > [!warning] No e2e/ directory exists in this repo at devel; only test/tests/unit/** is present. This script targets a path that ships in another context/customization.

Entrypoints (process binaries)

main is server.js. There are three long-running Node processes, all wired by supervisord (supervisor_docker.conf):

FileSupervisor programNODE_ENVRole
server.jsesign_ossnode server.jsdockerWeb + external + socket + queue RPC servers. Boot chain: setupServices → checkEmail+setupDb → initServices → setupQueue → setupCustomizations → StartWebServer → StartExternalServer → StartSocketServer → checkSeal (server.js:432-445).
cron.jsesign_cronnode cron.jsdockerScheduled jobs: delete-expired-shortener-URLs, revoke-expired-offers, delete-old-documents (cron.js:194-211). Registers RPC server esign:cron-ping.
background.jsesign_backgroundnode background.jsdockerBackground worker; instantiates the same service set as server.js plus BackgroundProcessService(true) (worker mode) (background.js:139-143).

exitcodes=0,2 in supervisord matches the app convention process.exit(2) on fatal startup errors.

No Dockerfile / docker-compose in this repo

A repo-wide search for Dockerfile* and docker-compose* (excluding node_modules) returns nothing. The docker NODE_ENV + config/docker.json + nginx_docker.conf + supervisor_docker.conf imply the image is built externally (a shared FaceKom base image / orchestration repo), not here.

Start commands (local dev, NODE_ENV=dev)

From the manifests/configs (not a documented runbook in-repo): build the client assets (yarn build), ensure Postgres + RabbitMQ are reachable per config/dev.json, then run node server.js, node cron.js, node background.js. With config.db.syncOnStart=true (dev default), server.js shells out to ./bin/db/sync then sequelize db:migrate on boot (server.js:178-200).

CI (.github/workflows/pull-request.yaml)

Triggered on pull_request. Jobs: Lint (yarn lint), Unit Tests (yarn test:unit --json --coverage), Audit (yarn audit --groups dependencies + improved-yarn-audit --min-severity critical), SonarQube Scan (consumes jest lcov; config in sonar-project.properties), Build (yarn build). All on ubuntu-latest, Node 24, yarn install --frozen-lockfile.


4. Top-level structure

Verified by listing + sampling (ls, find). Excludes node_modules, .git, logs/.

PathWhat
server.js / cron.js / background.jsThe three process entrypoints (§3).
config.jsConfig loader: wraps getconfig, adds config.get()/config.has(), optional Spring Cloud Config, dev host derivation, build-number suffix, CORS hardening.
config/Env config JSON: dev.json, docker.json, roles.json (ACL role→right map).
server/Core backend (services, db, queue, web, external, socket, sms, e-mail, cron). Bulk of the code.
client/Browser front-end source (ui/pages, ui/layouts, services, engine, utils, resources, polyfills) compiled by bin/script + bin/style.
web/Build output + static assets: compiled js//css/ land here; plus font/, icon/, img/, audio/, libs/, favicon.ico, 502.html.
customization/Per-integration override layer mounted via service-bus hooks; mirrors server/ + client/ui substructure. See §7 & customization-architecture.
engines/Reusable build/templating helpers: build/ (browserify+stylus bundler), dust/, twig/, translator/ (Dictionary), util/.
bin/First-party CLI/build helper scripts (§5).
db/migrate/7 Sequelize/umzug migration files (db/migrate/*.js, flat dir; 2018–2019 era).
test/Jest config + tests/unit/** (§8).
docs/features/Markdown feature docs (Hungarian): eSign user manual, offer-forward, vuer-external RPC, webserver firewall auth, sms-api, access-css.
.notes/Design notes: signature-process.md, signature-algorithm.md, rest-api.md, esign-stats.sql.
maintenance/34 dated *.md maintenance logs (2023-07 → 2026-05).
security/34 dated *.md security-audit logs (2023-07 → 2026-05).
.agents/AgentOps workspace (knowledge/plans/research/etc.) — tooling, not app code.
.github/workflows/pull-request.yaml CI.
seed-test.jsDev seeder: creates an enabled test customer (masterId 1001), a created offer with a bank-signed PDF, and forges the URL login token (seed-test.js header).
nginx_dev.conf / nginx_docker.confReverse-proxy configs (front of the loopback servers).
supervisor_dev.conf / supervisor_docker.confProcess supervision (the 3 node procs + nginx).
eslint.config.mjs, .editorconfig, .browserslistrc, sonar-project.properties, .sequelizerc, .yarnrcTooling config.
CREDITS.html, changelog.md, PULL_REQUEST_TEMPLATE.md, README.mdDocs/meta.

5. First-party bin/ scripts (every file, read)

Located under bin/ (NOT node_modules). Build helpers + DB/ops CLIs.

Build / asset pipeline:

  • bin/build/build.js — Pushes --no-exit to argv, then runs script.task + style.task in parallel; exits unless --watch. Backs yarn build.
  • bin/script/script.task.js — Declares browserify bundles for client/ui/pages|layouts and customization/ui/pages|layouts *.script.js/*.layout.jsweb/js; under --watch watches client/customization **/*.js|*.dust with livereload. Delegates to engines/build/build.
  • bin/script/script.compiler.jscompileBrowserify: bundles one JS file with browserify + browserifyDust transform + browserify-require-not-found-parent plugin; source maps gated on config.build.generateSourceMaps.
  • bin/style/style.task.js — Same shape as script.task but for *.style.styl / *.layout.stylweb/css; --watch watches **/*.styl.
  • bin/style/style.compiler.jscompileStylus: renders Stylus, injecting client/resources breakpoints, device-sizes.json, and colors as Stylus globals; auto-imports client/ui/styles/global.styl; runs autoprefixer via poststylus.
  • bin/watch/watch.js — Pushes --watch to argv and requires both tasks. Backs yarn watch.
  • bin/credits#!/usr/bin/env node; runs license-checker and prints an HTML license table to stdout (redirected to CREDITS.html by yarn credits).
  • bin/test/trans-check.js#!/usr/bin/env node commander CLI (--no-missing, -u/--unused, -c/--collapse). For each page under client/ui/pages, loads its *.trans.js via engines/translator/Dictionary, scans the twig template (following {% include %}) + script for t.t('key') references, and reports missing/unused translation keys. Backs yarn trans.

DB / operations CLIs (under bin/db/):

  • bin/db/create_user#!/usr/bin/env node commander <role> <username> <password> [email] [firstName] [lastName]. Validates role against config/roles.json via @techteamer/acl; refuses if config.activeDirectory is set; bcrypt-hashes the password (config.security.password.bcryptCost), inserts a User with rights:[role], and writes an AuditLog user/created event (fromCli:true).
  • bin/db/sync#!/usr/bin/env node commander -f/--force. sequelize.sync(); with --force prompts (inquirer) “you will lose all your data?” before sync({force:true}). Invoked at boot when db.syncOnStart (server.js:183).
  • bin/db/truncate#!/usr/bin/env node. Inquirer-confirmed truncate of all models except User, OpenHourStandard, OpenHourException; cascade:true, disables FK checks on MySQL.
  • bin/db/migrate-data#!/usr/bin/env node. Umzug-based old-DB → new-DB data migration tool: authenticates an old DB by URL, force-syncs + umzug.up() a new DB (from server/db/sequelize), and truncates tables before copying. (Glob ./db/migrate/*.js.)
  • bin/db/pg_sanity_check#!/usr/bin/env node. Postgres-only introspection: dumps JSON of every public table with row counts, sizes (pg_size_pretty), columns, FK relations, other constraints, and index names. Read-only.
  • bin/db/fetchCustomerDataAndExtendCSV.js — Node script (no shebang). Reads a CSV whose first column is a vuer_oss customerId/external id, looks up customer data from the DB, and writes an extended CSV; ensures the output dir exists. commander-driven.

Other:

  • bin/attachment.js#!/usr/bin/env node commander exports command (-o/--output, -i/--id csv). Exports Attachment rows named ScreenShot for the given customer id(s) to <output>/customer-<id>/<id>-<name>-<category>.<ext>.
  • bin/sms-api#!/usr/bin/env node commander (-f/-t datetime range, -s source CSV, -d dest CSV, -e extended). Joins SMS-provider CSV export against SmsLog rows in [from,to] and computes delivery-delta columns (status-date − createdAt; extended adds SMSAPI-TSP / OSS-SMSAPI deltas). Documented in docs/features/bin/sms-api.md.

6. Key modules / services / entities

Service container & boot wiring

  • server/serviceContainer.js — Exports a singleton { emitter } where emitter is a ServiceBus extends WildEmitter. The central DI + hook bus: addHook/callHooks/callOnlyHook (promise fan-out over named tags like services, queue, routes, cron, webserver:setup) and registerOverride/callOverride. Everything (serviceContainer.service.*, .queue, .db, .dbModels, .io, …) is hung off this object at boot.
  • server/logger.js — log4js config. Channels: esign, sql, express, csp, background, cron; appenders console (always) + optional file/syslog/papertrail (gated on config.logging.*). Default channel chosen from the entry script name (server.jsesign, cron.jscron, etc.). Throws if an unsupported appender is configured.
  • server/acl.js — Loads config/roles.json into a @techteamer/acl ACLService singleton.
  • server/auth.jsisAuthorized/hasRight plus doIfAuthorized/doIfHasRight wrappers used by socket/web handlers; reloads client.user before invoking the callback.
  • server/gcm.js — AES-256-GCM authenticated-encryption stream (Transform) + PBKDF2 key/salt helpers (used for at-rest data protection).
  • server/diagnostic.js, server/auditlog.js, server/SocketTokenStorage.js, server/child_process_promise.js — diagnostics round-trips, audit-log writer, socket token store, promisified exec.

Services (server/service/, 28 files; instantiated in server.js:112-153 / background.js)

Most important (read):

  • OfferService.js (28 KB) — Offer lifecycle: create, receiveBankSignedOffer, packaging/zip (archiver), forwarding to bank via HTTPS agent (cv.rejectUnauthorized), JWT-signed links (config.jwt).
  • CustomerService.js (23.5 KB) — Customer registration/bootstrap/approval/data.
  • SignatureService.js (16.7 KB) — Core signing state machine: processCustomerPublicKeyMessage (m1 ts1Data/ts1/ts1JSON), cancelSignatureAttempts, createSignature, two-factor token, SignatureValidator; shells out to OpenSSL (execFile).
  • AppService.js (17.4 KB) — Mobile app/device registration, version compatibility (semver), FCM push (e.g. on contract:sealed hook).
  • ContractService.js (10.9 KB), DocumentService.js, DealService.js, ActivityService.js — contract sealing, document storage, deal grouping, activity log.
  • TrustedTimestampService.js — wraps @techteamer/timestamp (TrustedTimestampServiceLib('short', config.trustedTimestamp, …)): createTimestampToken(digest, hashAlgorithm, dataSize), verifyTsr, getTimestampInfo, testService (validates OpenSSL setup at boot).
  • TokenService.jsnode-jose JWE encrypt/decrypt using the facekom key from config.jwt.keystore.
  • SettingsService.js — DB-backed (Setting model) runtime settings with in-memory Map + defaults; init() runs at boot.
  • BackgroundProcessService.js (13.3 KB) — background job runner (worker mode in background.js).
  • Others: FcmService, SmsService (server/sms/), EmailService (server/e-mail/), HashService, RsaService, CryptoService, PasswordService, ShortenerService (hashids URL shortener), IpFilterService, OnlinePresenceService, SocketService, DisasterModeService, JWTService, LiveUpdateService, SignatureTemplateService (+ server/signature-template/SignatureTemplateHandler.js), TempFileService, ClientErrorLogService, diagnostic.

Persistence (server/db/)

  • server/db/sequelize.js — Single Sequelize instance from config.db.url (+ config.db.options), pool max default 20, SQL logging only in dev. Adds beforeFind/beforeCount hooks that strip undefined WHERE keys (and warn) — a guard against accidental full-table queries. A 5s interval logs pool-usage (info/warn/error at 0.4/0.6 thresholds).
  • server/db/models.js — Registers ~27 models from server/db/model/*.js and wires associations. Core graph: Customer hasMany Offer/Contract/Signature/Document/CustomerData/Activity/App/SmsLog/EmailLog; Contract belongsTo Customer/Signature/Offer/TimestampToken; Signature belongsTo Customer/App/Offer, hasMany SignatureData; App belongsTo Customer/FcmInfo/Device. Plus User, AuditLog, Setting, Shortener, Cert, ClientErrorLog, BackgroundProcess(+Log), Attachment, VerificationToken, Session (connect-session-sequelize).
  • server/db/model/*.js (26 model defs) + server/db/translations/*.trans.js (21 enum/label translation maps; flat dir) + helpers.js, migrationHelpers.js, SignatureValidator.js.
  • db/migrate/*.js — 7 umzug migrations.

HTTP surfaces

  • Web server/web/web-server.js (WebServer class) — Express 5 app: per-request nonce, fully config-driven helmet + a hand-built CSP (script 'self'+nonce, connect wss://host, sandboxed, CSP exempt for /api/document/* & /api/screenshot/*, allow-downloads on /offer/*), body/cookie parsers, log4js connect logger, locale. Chained setup setupLocale/Session/Flash/Twig/Routes/CSPReportViolation/404/Disaster/ErrorHandler (server.js:325-344).
    • server/web/routes.js — back-office GET pages (/, /customerlist, /offerlist, /contractlist, /signature/:id, /auditlog, /users, /systemsettings, /eseal, …, each ACL-gated via isAllowed/anyAllowed against config/roles.json) + /api/* (document/attachment/signature/screenshot, offer upload/revoke/forward, cert upload, customer approve/disable, role-switch, sentry). Many routes are feature-flagged on config.features.* / config.seal / config.certManager.
    • server/web/api/{admin,common}/ (16 files), server/web/routes/*.endpoint.js (20 files), server/web/{session,flash,Template,WebServerAuth}.js.
  • External server/external/external-server.js — separate Express app (helmet, noCache, body/cookie parsers, disaster-mode guard). server/external/routes.js mounts bank webhooks, each individually toggled by config.webHooks.* and optionally Basic-Auth’d: POST /offer/upload, /offer/revoke, /contract/upload, /signature/verify, /customer/bootstrap, /customer/send-association-token, /customer/approve, /app/notification. (server/external/auth.js is a no-op placeholder; real auth is per-route basic-auth + the external:routes hook.)
  • Socket server/socket/socket-server.js + server/socket/events/{acl,auth,headerinfo,pagevisit,ping}.js, client.js.

Queue (server/queue/) — see §9.


7. Configuration

  • Loader: config.js requires getconfig (selects config/<NODE_ENV>.json; e.g. devconfig/dev.json, dockerconfig/docker.json). On a JSON SyntaxError it parses the offending file/offset and prints a context window before process.exit(2). Adds:
    • config.get('a.b.c', default=null) and config.has('a.b.c') accessors (config.js:115-152).
    • Build-number suffix: appends .${ESIGN_BUILD_NUMBER} from ./.env to config.version (config.js:104-112).
    • Optional Spring Cloud Config (config.springCloudConfigServer): loads remote config via cloud-config-client with promise-retry, dot-merges into config; result on config.loaded (config.js:73-99). Otherwise config.loaded = Promise.resolve().
    • Dev host derivation (NODE_ENV==='dev'): fills hosts.css/oss/api + portal.url from DEV_DOMAIN or /etc/hostname (config.js:41-62).
    • CORS/socket hardening: rewrites web.cors.origin: '*' / web.socket origins to the actual hosts.oss (config.js:154-172).
  • Config files:
    • config/dev.json (~320 lines) — the canonical full schema sample. Top-level keys: portal, demo, hosts, jwt (secret + JWE keystore), web (session, socket, socketioSettings, trustedProxy, cors), app.compatibility, shortener, trustedTimestamp(PdfSigner), security (password.bcryptCost, cookie, twoFactorAuth, login throttling, ipFilter), features (disasterMode, offerUpload/Forward/Revoke/Package, approveCustomer, roleSwitch, …), seal (pfx path+password), customizations, signatures (templates), certManager.cryptoKey, db (url, syncOnStart), fcm.serviceAccount, email.transport.SMTP, sms (sender SmsApiCom), queue (amqps url + mTLS cert/key/ca, rpcTimeoutMs, rpcQueueMaxSize), locales, logging, diagnostic, settings, build (generateSourceMaps, liveReloadSettings), timeouts (signOffer, deleteDocuments with cron schedules), version, externalApi, webHooks, backgroundProcess. config/docker.json is the production-shaped equivalent.
    • config/roles.json — ACL role→rights. admin has ~14 rights (auditLog.view, customers.documents/attachments/signatures.view, disasterMode.change, electronicSeal.view, systemSettings.view, users.create/list/change.*, cert.upload, email.preview); operator has only users.list, cert.upload.
  • .sequelizerc — points sequelize-cli at config.db.url, migrations db/migrate, models server/db/model.
  • Env vars (observed in code): NODE_ENV (getconfig file + dev branches), DEV_DOMAIN, ESIGN_BUILD_NUMBER (via .env), TZ (forced to Etc/UTC at boot), NODE_TLS_REJECT_UNAUTHORIZED (set to 0 when settings.allowSelfSignedCerts). Supervisor injects NODE_ENV=docker, DOCKER_USER, APP_HOME.
  • AJV: ajv is a dependency and a resolutions pin (umzug/**/ajv: >=8.18.0); no first-party top-level AJV schema files were located in the surveyed source (validation usage, if any, lives inside services/customization not exhaustively read — see gaps).

Secrets committed to config/dev.json

config/dev.json contains real-looking dev secrets: a Firebase service-account private key, JWT/session/shortener secrets, an SmsApiCom AuthToken, a seal pfx password (techteamer), and mailtrap creds. These are dev fixtures, but treat the file as sensitive and never copy its values to non-dev environments.


8. Tests

  • Framework: Jest 30 (jest, ts-jest, @types/jest).
  • Config: test/jest.config.jsrootDir = repo root; ignores node_modules, web/, yarn-offline-cache/; coverage on (v8, lcovonlytest/coverage/jest), testTimeout: 30000, empty transform (no Babel).
  • Location: test/tests/unit/:
    • web-server-auth.test.js
    • services/signature-service.test.js
    • webfolder/api/common/cert-upload.test.js
    • customization/server/queue/vuer-external.test.js
  • Run: yarn test (jest … --runInBand --forceExit) or yarn test:unit (ESM VM modules, used by CI). yarn test:e2e targets a non-existent e2e/* here (see §3 warning).

9. Dependencies on other FaceKom services (evidenced in code)

RabbitMQ (@techteamer/mq, config.queue.url amqps://, mTLS)

server.js:223-317 (setupQueue) wires the OSS queue topology. cron.js:132-192 and the customization/customization.js queue hook add more.

RPC servers exposed by OSS (esign:rpc-* etc.): esign:rpc-app, esign:rpc-customer, esign:rpc-timestamp, esign:rpc-document, esign:rpc-contract, esign:rpc-offer, esign:rpc-signature, esign:rpc-signature-check. (cron adds esign:cron-ping.) Customization adds esign-vuer-rpc and rpc-esign:external (customization/customization.js).

RPC clients OSS calls out on:

  • esign:css-ping (PingRPCClient) → CSS (customer-side server) liveness.
  • esign:cron-ping (PingRPCClient) → cron process.
  • esign:rpc-system-oss (SystemOssRPCClient).
  • vuer-esign-rpc (EsignRPCClient, customization) → vuer integration.

Queue servers (consumers): esign:queue-revoke-expired-offers, queue-clienterror-log. Queue clients (producers): esign:queue-service-bus (sends 'started' after socket boot, server.js:398), esign:queue-customer, esign:queue-contract. Publishers/subscribers: esign:settings-change, and (when config.backgroundProcess) esign:background-process.

On RabbitMQ connection close the process exits with code 2 (server.js:233-237) so supervisord restarts it.

PostgreSQL

Required. config.db.url (postgres://…); Sequelize 6 pool (max 20). Migrations via sequelize-cli/umzug. See §6.

HTTP integrations

  • Bank back-end — inbound via the External webhook API (§6) and outbound via OfferService HTTPS calls + config.externalApi.* / config.portal.callbackApi (offer-timeout report, signed-offer endpoint, customer login/auth/data endpoints in config/dev.json).
  • TSA (trusted-timestamp authority)config.trustedTimestamp.providers[].url (e.g. https://bteszt.e-szigno.hu/tsa) via @techteamer/timestamp.
  • Firebase / FCMfirebase-admin for push (config.fcm).
  • SMSAPI.comconfig.sms.sender.SmsApiCom.baseUrl for SMS.
  • CSS configPOST /api/admin/css-config web route pushes config to the customer-side server.

No Redis dependency was found (no redis/ioredis in package.json; sessions use Postgres via connect-session-sequelize).


10. Verified gotchas

All HTTP servers bind to loopback ( 127.0.0.1)

Web (10181), External (10182), Socket (10180) are not directly reachable off-box — nginx (nginx_*.conf) must front them. (server.js:350,364,380.)

Fatal-startup convention is process.exit(2)

server/cron/background all exit 2 on boot failure or RabbitMQ disconnect; supervisord whitelists exitcodes 0,2 and autorestart=true.

db.syncOnStart=true runs schema sync + migrate on every boot

In dev, server.js execs ./bin/db/sync then sequelize db:migrate at startup (server.js:178-200). Safe for dev DBs; do not enable against a DB you can’t lose.

bin/db/truncate and bin/db/sync --force are destructive

Both wipe data (truncate keeps only User/OpenHour*; sync --force drops everything). Inquirer-guarded, but irreversible.

Sequelize undefined-WHERE guard

server/db/sequelize.js deletes undefined keys from every where (and logs a warning) before find/count. A query built with an undefined filter value silently loses that condition — check logs for “WHERE parameter … invalid ‘undefined’ value”.

Customization via service-bus hooks

customization/{customization,cron-customization,background-customization}.js register services/queue/routes/cron/webserver:setup/socket hooks on serviceContainer.emitter. The instacash branch builds on this; the core customization.js already wires vuer RPC + a customization-layer CustomerService/ExternalService and core listeners (customer-bootstrap, customer-auth-token, etc.). See customization-architecture, customization-branch-catalog.

config/dev.json is the de-facto config schema

There is no JSON-schema/AJV contract file in-repo; config/dev.json + config/docker.json are the reference for valid keys. New config keys are read defensively via config.get(path, default).


Unverified / gaps

  • Large subtrees surveyed structurally (listed + key files sampled), not line-by-line:
    • server/web/api/{admin,common}/ (16 files) and server/web/routes/*.endpoint.js (20 files) — router wiring read via server/web/routes.js; individual endpoint handlers not all read.
    • server/queue/** (23 files) — topology read from server.js/cron.js; individual RPC/queue handler bodies (e.g. rpc_server/Signature.js) not read line-by-line.
    • client/** front-end source — structure mapped; only the build wiring (bin/script, bin/style, engines/build) was read, not page scripts/templates.
    • customization/** (api/external/server/listeners/portal/sms/translations/ui) — entrypoints (customization.js, cron-customization.js, background-customization.js) read; integration sub-modules and the instacash branch overrides not exhaustively read (covered by customization-architecture/customization-branch-catalog).
    • server/db/model/*.js (26 model defs) + *.trans.js — registration + associations read from models.js; per-field column definitions not enumerated.
    • maintenance/ (34) and security/ (34) dated logs — listed, not read.
  • Service internals: of the 28 services, the largest (Offer/Customer/Signature/App/Contract/Background) were read at the top/representative level, not in full. DealService, IpFilterService, OnlinePresenceService, etc. read only as headers/sizes.
  • AJV usage: confirmed as a dependency; no top-level first-party schema file found. Whether services validate payloads with AJV at runtime was not traced into every handler.
  • Branch scope: documented devel (working tree = update/customization/instacash-2026-05-27, +4 lines in config.js vs devel). Other 40+ customization/feature branches not inspected here.
  • Deployment image: no Dockerfile/compose in-repo; the actual container build and how nginx+supervisor+certs are assembled live outside this repo (not verified).

Sources

Files/dirs actually read:

  • package.json, README.md, changelog.md, .sequelizerc, .yarnrc, config.js
  • server.js, cron.js, background.js, seed-test.js
  • config/dev.json, config/roles.json
  • supervisor_docker.conf, .github/workflows/pull-request.yaml
  • bin/attachment.js, bin/credits, bin/sms-api, bin/build/build.js, bin/script/script.task.js, bin/script/script.compiler.js, bin/style/style.task.js, bin/style/style.compiler.js, bin/watch/watch.js, bin/test/trans-check.js
  • bin/db/create_user, bin/db/sync, bin/db/truncate, bin/db/migrate-data, bin/db/pg_sanity_check, bin/db/fetchCustomerDataAndExtendCSV.js (head)
  • server/serviceContainer.js, server/logger.js, server/acl.js, server/auth.js, server/gcm.js (head)
  • server/db/sequelize.js, server/db/models.js (head)
  • server/service/SignatureService.js (head), server/service/OfferService.js (head), server/service/AppService.js (head), server/service/TrustedTimestampService.js (head), server/service/TokenService.js, server/service/SettingsService.js (head)
  • server/external/external-server.js, server/external/routes.js, server/external/auth.js
  • server/web/web-server.js (head), server/web/routes.js
  • engines/build/build.js (head)
  • customization/customization.js, customization/cron-customization.js, customization/background-customization.js, customization/RELEASE.md
  • test/jest.config.js, .notes/signature-process.md (head), .notes/rest-api.md (head)
  • Directory listings: repo root, server/ (+ all subdir file counts), server/service/, server/queue/, server/external/, server/web/{api,routes}, server/db/{model,translations}, server/socket/, server/sms/, server/e-mail/, server/signature-template/, config/, customization/ (depth 2), db/migrate/, docs/features/, .notes/, engines/, test/, bin/
  • Git: git -C … branch -a, git -C … log (devel + working branch), git -C … diff --stat origin/devel