vuer_css — Vuer Client Side Server (CSS)

The customer-facing web/socket server of FaceKom. It serves the browser/kiosk/mobile-webview UI for the whole identification + video-banking journey (homepage → system-check → waiting-room → videochat, plus the self-service mobile flow), bundles the frontend assets, and brokers everything to the back-office via RabbitMQ. It is the public node a remote customer hits; the operator-side counterpart is vuer_oss.

  • Repo: /Users/levander/coding/facekom/vuer_css
  • Base branch: devel (CI audit.yaml runs on devel + customization/*; PR CI on every PR).
  • Package name / version: vuer_css 1.9.11 (package.json:2-3); current devel-line tip commit is 62dad7f4 1.9.11.92.
  • Owner: TechTeamer (package.json:30, private: true).

Heavily customized via Git branches. devel is the core product; deployments ship from customization/<partner> branches (e.g. customization/raiffeisen, customization/instacash) that layer partner code into the customization/ tree. See customization-architecture and customization-branch-catalog.


1. Purpose & role in FaceKom

  • README (README.md:1) titles it “Facekom Client Side Server (CSS)”; package.json:4 describes it as “Vuer Client Side Server”.
  • It is a Node.js Express 5 web server + Socket.IO 4 realtime server that:
    • Renders Twig HTML pages and serves compiled JS/CSS bundles for the customer journey (server/web/routes.js, client/ui/pages/* — 25 immediate page dirs; the parallel customization/ui/pages/* tree adds 29 more).
    • Maintains the live WebRTC video session signalling over Socket.IO (server/socket/events/videochat*.js, server/transport/*).
    • Acts as an RPC/queue bridge to the rest of the FaceKom backend over RabbitMQ via @techteamer/mq (server.js:76-234).
  • Entry point server.js boots in this exact order (server.js:342-352): config.loadedrabbitmq() bootstrap → setupQueuesetupServicessetupCustomizationsStartWebServerStartSocketServer.

2. Tech stack & runtime

AspectValueSource
LanguageJavaScript (CommonJS server; some bin tools in TypeScript)package.json, bin/*.ts
Server frameworkExpress ^5.1.0package.json:64
Realtimesocket.io ^4.8.1 (+ socket.io-client)package.json:96-97
Templatingtwig ^1.15.4package.json:101, engines/twig/render-server.js
Frontend runtimeReact 18 + react-dom 18, bundled per-pagepackage.json:90-91, bin/script/*
Stylingstylus ^0.64.0 → clean-css → autoprefixer/poststylusbin/style/style.compiler.js
JS bundlersesbuild ^0.27.0 (page scripts), browserify ^17 (react/react-dom externals)bin/script/script.compiler.js, bin/script/external.compiler.js
Message queue@techteamer/mq ^7.2.0 (RabbitMQ, amqps)package.json:44, server/bootstrap/connection/rabbitmq.js
Session storeRedis (redis ^5.8.0, connect-redis ^9)server/web/WebServer.js:274-286
Configgetconfig ^4.1.0 + custom config.js wrapper; AJV ^8 schema validationconfig.js, bin/validate-config.js
Logginglog4js ^6 + @techteamer/ecs-plugin (ECS/JSON); optional syslog/papertrailserver/logger.js
Auth/cryptojsonwebtoken, node-jose (JWT keystore), csurf, helmetpackage.json, server/service/TokenService.js
Required Node>=22.0.0 (engines); CI matrix tests Node 22 & 24package.json:6-8, .github/workflows/pull-request.yaml:11
Package managerYarn (classic; yarn.lock present, .yarnrc sets --install.ignore-optional true); CI uses yarn install --frozen-lockfile.yarnrc, yarn.lock, CI yaml
Browser targets.browserslistrc: IE>=11, Safari>=11, Edge>=16, Firefox ESR, last 2 years; babel @babel/preset-env + preset-react.browserslistrc, .babelrc

engines.node >=22 but .browserslistrc still lists IE >= 11 — the browserslist drives client bundle transpilation targets, not the server runtime. Actual runtime browser support is enforced separately by the browsers.compatible/browsers.incompatible config (see §7).


3. Build & run

package.json scripts (verbatim — package.json:9-25)

ScriptCommandWhat it does
buildnode bin/build/build.jsOne-shot full build: runs externals + scripts + styles tasks in parallel, then exits (bin/build/build.js).
jestjest --config ./test/jest.config.js --runInBand --forceExitRuns Jest with the repo’s jest config, serially.
test:unityarn jest unit/* --forceExitRuns the unit test suites.
linteslint . --max-warnings 0 --ignore-pattern "test/*" && echo 'npm run eslint --max-warnings 0'Lints everything except test/ with zero-warning tolerance.
lint:fixeslint . --fix && eslint --max-warnings 0 .Auto-fixes then re-lints.
startnode server.jsStarts the production server (the actual app entrypoint).
stylenode bin/style/style.taskCompiles only the stylus → CSS bundles.
scriptnode bin/script/script.taskCompiles only the page/layout JS bundles (esbuild).
script:externalnode bin/script/external.taskBundles the React/react-dom “external” modules (browserify).
script:allnode bin/script/external.task && node bin/script/script.taskExternals then page scripts.
watchnode bin/watch/watchWatch-mode build of externals+scripts+styles+server (no restart).
devnode bin/watch/watch --restartDev server: watch + rebuild + supervisorctl restart vuer_css on server-file changes (README’s recommended yarn dev).
creditsnode bin/credits > CREDITS.htmlGenerates an HTML license table of all deps.
validate_config:devnode bin/validate-config.js config/dev.jsonAJV-validates config/dev.json against the unified schema.
validate_config:dockernode bin/validate-config.js config/docker.jsonSame for config/docker.json.

Entry points

  • Main: server.js (package.json:5 "main": "server.js"). Run with node server.js / yarn start.
  • Web SDK demo server: web-sdk-demo/web-sdk-server.js — a separate small server (port 10084) subclassing WebServer with CSP disabled, for the embeddable Web SDK demo page.
  • No bin field in package.json; the bin/ dir holds build/dev tooling invoked via npm scripts (not installed CLIs).

Listening ports (hard-coded / config)

  • Web (Express): 10083, bound to 127.0.0.1 (server.js:303-304).
  • Socket.IO: web.socket.port default 10082, host 127.0.0.1 (server.js:322-325).
  • Web SDK demo: 10084 (web-sdk-demo/web-sdk-server.js:3).
  • Public traffic is fronted by nginx which proxies /socket.io10082 and everything else→10083 (nginx_vuer_css_docker.conf:1-7,50-72).

Dockerfile / deployment

No Dockerfile exists in this repo (verified: find for Dockerfile/dockerfile returns nothing). Deployment is via supervisord + nginx, configured by the in-repo conf files. The Docker image is built elsewhere (not in this repo).

Deployment artifacts present:

  • supervisor_vuer_css_docker.conf — supervisord runs three programs: nginx, redis (/etc/redis/redis.conf), and vuer_css = node server.js with environment=NODE_ENV="docker", directory=/workspace/vuer_css, user=techteamer, autorestart=true, exitcodes=0,2, stopsignal=TERM.
  • supervisor_vuer_css_dev.conf — same shape but NODE_ENV=dev.
  • nginx_vuer_css_docker.conf / nginx_vuer_css_dev.conf — reverse proxy; docker listens :80, dev listens :30080/:30081, both with upstreams socketio-css 127.0.0.1:10082 and vuer-css 127.0.0.1:10083 (dev adds vuer-css-sdk 127.0.0.1:10084). Static root /workspace/vuer_css/web; client_max_body_size 25M; long-cache for /img /font /libs /icon /audio /js /css /entry.

NODE_ENV selects the getconfig file (config/dev.json / config/docker.json). config.js:41 additionally branches on NODE_ENV === 'dev' || 'travisci' to inject dev hostnames/CORS, and 'travisci' forces queue.url = amqp://localhost:5672.


4. Top-level structure

PathRoleVerified
server.jsApp entrypoint; wires queue, services, customizations, web + socket serversread
config.jsgetconfig wrapper adding .get()/.has()/.getSecureConfig(), dev-host injection, spring-cloud-config loaderread
config/Env config JSON: dev.json (~430 lines), docker.jsonread
server/All backend code (web, socket, queue, services, transport, logger) — see §6read/sampled
client/Frontend source: ui/ (pages/layouts/elements/screens/states/styles), engine/ (MVC-ish radio/view/controller), features/, react/, externals/, resources/, assets/, utils/listed/sampled
customization/Partner-customization tree: server/, ui/, listeners/, flow/, features/, resources/, customizations.js, branding-options.json, RELEASE.mdread core files
engines/Build + render engines: build/ (bundle/watch/livereload/restart), twig/, translator/, util/read
bin/Build/dev/validation tooling (see §5)read all
docs/Config JSON-Schemas (docs/config/schemas/*), OpenAPI specs (can-identify.yaml, is-compatible.yaml), feature markdownread schemas/specs
web/Build output + static assets (js/, css/, img/, font/, audio/, entry/, 502.html, error.html, robots.txt) — served by nginxlisted (artifact)
web-sdk-demo/Standalone Web SDK demo server (web-sdk-server.js) + page/read entry
maintenance/ security/Dated markdown notes (release/maintenance/security log per month, 2023→)listed
test/Jest config + tests/unit/** (115 .test.js, recursive: test/tests/unit/**/*.test.js) + testconfigs/local.json + travis.shread
logs/Runtime log dir (logs/server.log target)
.github/workflows/{pull-request,audit}.yaml, CODEOWNERSread
node_modules/Vendored deps — out of scopeignored

Root config/meta files: .babelrc, .browserslistrc, .editorconfig, .yarnrc, eslint.config.mjs, sonar-project.properties (SonarCloud, projectKey vuer-css), docs.json, changelog.md, PULL_REQUEST_TEMPLATE.md, .gitignore (only # Logs).


5. bin/ helper scripts (every first-party script, read)

PathWhat it does
bin/build/build.jsPushes --no-exit, runs external.task + script.task + style.task in Promise.all, logs done Build, exits unless --watch.
bin/watch/watch.jsPushes --watch, then requires external.task, script.task, style.task, server.task (the watch entrypoint behind yarn watch/yarn dev).
bin/script/script.task.jsDeclares esbuild bundle specs for client/ui/pages/**/*.script.js, customization/ui/pages/**, both **/layouts/**/*.layout.jsweb/js; in dev/travisci also bundles client/ui/test/*.js; sets watch globs + livereload *.js.
bin/script/script.compiler.jsesbuild compiler: bundles a single .js entry → web/js/..., minify/sourcemap from config, keepNames:true; optionally injects esbuild-plugin-istanbul when build.istanbul.
bin/script/external.task.jsBundle specs for client/externals/react/react.*.ext.js and react-dom.*.ext.jsweb/js/externals (react-dom built with react marked external to avoid a 2nd React instance).
bin/script/external.compiler.jsbrowserify compiler that .require()s a module exposed under a name (react/react-dom) and .external()s excluded modules — produces the global require('react') shim.
bin/style/style.task.jsStylus bundle specs: client/ui/pages/**/*.style.styl & layouts/*.layout.stylweb/css; customization/ui/branding/**/*.branding.stylweb/branding; custom pages/layouts → web/css; watch globs incl. customization/branding-options.json.
bin/style/style.compiler.jsStylus→CSS compiler: imports client/ui/styles/global.styl, injects breakpoints / device-sizes.json / colors / branding resources+values as stylus vars, runs autoprefixer via poststylus, minifies with clean-css when build.minify.
bin/server/server.task.js”server” build task: empty bundle list; in watch mode watches client/**/*.twig, *.trans.js, customization/**, config/*.json, engines/{translator,twig,util}, server/**/*.js, config.js, server.js, and calls restart() (supervisorctl).
bin/validate-config.jsESM AJV validator: loads docs/config/main.json, resolves $ref sub-schemas from docs/config/, validates the JSON config passed as argv[2] (used by validate_config:* scripts); exits 1 on invalid.
bin/credits#!/usr/bin/env node; uses license-checker to print an HTML <table> of all dependency licenses/URLs/publishers (piped to CREDITS.html).
bin/config.getter.tsTS tool (Node strip-types or Deno): greps all .js for config.get('a.b.c') keys, diffs against config/ref.json, prints missing keys, regenerates config/ref.json (backs up to old_ref.json).
bin/doc.gen.tsTS tool (Deno/Node shebang): inlines all $ref sub-schemas of docs/config/main.json, optionally writes docs/config/ref.json (-s), and generates Hungarian config docs markdown to docs/features/configuration/config-table.md.

bin/build/build.js, bin/style/style.compiler.js etc. import BrandingService and config.js at build time — the build reads the active config, so minify/generateSourceMaps/istanbul/branding all come from config/<env>.json (bin/build/build.js instantiates new BrandingService() and passes branding vars into the stylus compiler).

engines/build/restart.js is the restart helper used by dev: it spawns supervisorctl restart vuer_css and logs its output.


6. Key modules / services / entities

Bootstrap & DI

  • server/service_container.js — a ServiceBus extends WildEmitter singleton ({ emitter }) with addHook/removeHook/callHooks, registerOverride/callOverride, callOnlyHook. This is the customization seam: core code calls emitter.callOverride('routes:homepage', …, defaultFn) and callHooks('queue'|'services'|'routes'|'socket', …); customization/customizations.js registers the partner implementations. Everything (logger, queue, services, io, transport storages) is hung off this container.
  • server/bootstrap/connection/rabbitmq.js — builds a @techteamer/mq ConnectionPool from config.queue, exits the process (code 2) if any RabbitMQ connection closes, and seeds serviceContainer.queue/rpcServer/rpcClient/queueServer/queueClient.
  • config.js — see §1/§7; also getSecureConfig() redacts security.sensitiveConfigFields (supports a.*.b wildcards) for safe exposure to clients.

Web layer (server/web/)

  • WebServer.js — builds the Express app: host-header allowlist (config.hosts), per-request nonce, kiosk detection (getKioskType), UA parsing (ua-parser-js) with per-browser isCompatible/isIncompatible flags + webrtc constraints, helmet security headers, a large custom CSP middleware (per-path sandbox/scriptSrc/connectSrc incl. wss://hosts.css), body-parser (25 MB JSON limit + application/csp-report), locale negotiation, Redis-backed session (separate kiosk session middleware), a SAML-bypass-via-redis middleware for ClientGate IdP, setupRoutes, CSP report endpoint, and 405/404/error handlers. Web app listens on 127.0.0.1:10083.
  • routes.js — central route table. Wraps most routes in csrfProtection (csurf) + serviceContainer.emitter.callOverride('routes:*', …) so customizations can replace any route. Mounts page routes (/, /lobby, /system-check, /videochat, /waiting-room, /feedback, /good-bye, /we-are-closed, /ui-kit), the self-service suite (/self-service/*, /api/self-service-*, SAML /saml/sso/*), device-change, appointment, WebSDK (/sdk/*, /web-sdk), Apple App-Site-Association, kiosk endpoints, and API validation via openapi-validator-middleware for /api/can-identify & /api/mobile/is-compatible. Disaster mode redirects all HTML to /we-are-closed.
  • server/web/api/** (30 .js endpoint files, recursive), server/web/routes/** (35 .js page/route endpoint files, recursive), server/web/middleware/** (saml-middleware, we-are-open, kiosk-compatiblity, self-service-phase-redirect), server/web/helper/** (kiosk type, open-hours formatting, FaceKomPont request validation, lobby redirect, device-change). Template.js + engines/twig/render-server.js register Twig filters (timestamp, filesize, documentType, getNameOrder).

Socket layer (server/socket/)

  • socket-server.jsstart() creates the socket.io server from config.web.socket; setupEvents() builds the module list (client, auth, pagevisit, lobby, waiting-room, echotest, ping, videochat + .presentation/.customerDataChange/.validation/.signature, webrtclog, mobile, selfservice, selfservice-v2, flow), lets customizations push extra event modules via callHooks('socket', modules), and on each connection invokes every module with the client. Supports socket.io v4 connection-state-recovery.
  • server/socket/events/** (~18 handlers), server/socket/models/{CallData,LogItem,UserData}.js, server/socket/client.js, server/socket/diagnostic.js.

Transport (server/transport/)

  • TransportPool.js, TransportSession.js, session/{Echo,Room,SelfService}TransportSession.js, storage/{Room,SelfService}TransportStorage.js — the media/room transport bridge between socket clients and the OSS/back-office over MQ (queue-transport-oss/rpc-transport-oss pair, set up in server.js:208-225).

Services (server/service/, instantiated in server.js:236-282)

CompatibilityService, SocketService, DisasterModeService, TurnPasswordService (TURN credential generation from webrtc.turn.secret), BrandingService (resource/value override with fallback — see below), DeviceChangeService, IpFilterService (per-action IP throttling/cooldown), PartnerService, SelfServiceRoomService, TokenService (JWT keystore via node-jose, loaded at boot), WaitingRoomGraceService, plus factory-style waiting-room.js / service-bus.js. DeviceChangeService/selfService services are conditional on config.

  • BrandingService.js — loads customization/branding-options.json defaults, overrides values from config.branding.values, and swaps resource paths to config.branding.resources when the file exists under web/ (else logs a warning and keeps the fallback). Branding vars are fed into the stylus build (§5).

Queue integration (server/queue/) — the FaceKom backbone

server.js:76-234 registers a large set of RabbitMQ participants through @techteamer/mq. Clients/servers are thin classes extending RPCClient/RPCServer/QueueClient/QueueServer (e.g. JwtAuth.js is 9 lines: class JwtAuth extends RPCClient { auth(token){ return this.call({jwtToken:token}) } }). Full queue catalog in §9.

Frontend (client/)

  • client/engine/ — a custom client framework: radio/ (pub-sub channels), view/ (template/action/state switching), controller/, message/ (intents), service/, metadata/.
  • client/ui/pages/<page>/ — each page bundles a *.script.js (esbuild entry), *.style.styl, *.template.twig, *.trans.js (i18n), *.ui.js, etc. (e.g. videochat/ has videochat.script.js, .template.twig, .style.styl, .trans.js, .services.js, .ui.js, .errors.js). 25 immediate page dirs under client/ui/pages/ (recursive subdir count is 37; customization/ui/pages/ adds 29 more).
  • client/features/videochat, webrtc, system-check, DeviceChange, RequestCallback, time-slot-picker, socket, socket-ping, selfservice-session-expiration.

client/features/webrtc/ — the Peer wrapper (read this before touching RTC APIs)

The client RTC layer is two levels deep, and this trips people up (verified during FKITDEV-8887):

  • SenderPeer and ReceiverPeer (client/features/webrtc/SenderPeer.js, ReceiverPeer.js) each construct this.pc = new Peer(config).
  • Peer (client/features/webrtc/Peer.js, extends WildEmitter) is itself a wrapper. It holds the real RTCPeerConnection as its own this.pc and only proxies a fixed set of methodscreateOffer, setLocalDescription, setRemoteDescription, createAnswer, addStream, close — plus re-emits the icecandidate/track (and connection-state) events.

SenderPeer.pc / ReceiverPeer.pc is a Peer, not an RTCPeerConnection. The real connection is one more hop down, at senderPeer.pc.pc.

To use any RTCPeerConnection API that Peer does not already proxy (getSenders(), replaceTrack(), getStats(), addTrack, getTransceivers, restartIce, …) you must either:

  1. Add a proxy method to Peer (preferred — matches the existing pattern, keeps callers wrapper-agnostic), or
  2. reach through senderPeer.pc.pc explicitly.

Calling e.g. this.pc.getSenders() from inside SenderPeer silently returns nothing/false in production because Peer has no getSenders — no throw, just a no-op. This was the concrete bug in FKITDEV-8887.

Peer.startWatcher() is disabled — it return falses at the top, so the getStats watcher does not run. Don't assume stats polling is live.

  • client/externals/react — react/react-dom shims bundled separately (§5). client/react/ — react-loader + page-context + hooks/helpers. client/resources/breakpoints, device-sizes.json, colors, translations.

Translation engine (engines/translator/Dictionary.js)

Dictionary modules (*.trans.js) export dict.define({ key(){ return { hu:…, en:… } } }); loaded both server-side (twig global t) and browser-side. Default/supported locales come from config locales (dev.json: supported ['hu'], default hu).


7. Configuration

  • Mechanism: getconfig picks config/<NODE_ENV>.json (dev.json / docker.json); config.js wraps it. Access via config.get('a.b.c', default) and config.has('a.b.c'). springCloudConfigServer block (if present) pulls overrides from a Spring Cloud Config server with promise-retry (config.js:148-178).
  • Schema / validation: JSON-Schema (draft 2020-12) under docs/config/ — root main.json $refs 29 sub-schemas in docs/config/schemas/*.schema.json (app, appointment, browsers, build, callbackRequest, deviceChange, diagnostic, documentUpload, features, hosts, jwt, kiosk, locales, logging, mediaContent, portal, presentationMode, queue, registrationRedirect, screenshot, security, selfService, settings, systemCheck, waitingRoom, web, webrtc, webSDK, timezone, branding, activeFeedback, version). Validate with yarn validate_config:dev|docker (AJV, bin/validate-config.js). bin/doc.gen.ts regenerates a unified ref.json + HU docs table.
  • Key config domains (from config/dev.json):
    • queue — RabbitMQ amqps://localhost:5671, mutual-TLS certs under /workspace/vuer_mq_cert/, rpcTimeoutMs 10000, rpcQueueMaxSize 100.
    • web.session.redis — unix socket /var/run/redis/redis-server.sock; web.socket socket.io tuning (pingTimeout, connectionStateRecovery, 25 MB buffer); web.cors, web.trustedProxy.
    • webrtcpeerConnectionConfig.iceServers (STUN/TURN), turn.secret/validityInSec, per-OS mediaOptions.
    • browsers.compatible / browsers.incompatible — semver-style allow/deny per browser+OS (the real runtime gate).
    • features — toggles: selfService, presentationMode, feedback, registration, documentScanner, customerDocumentUpload, callbackRequest, etc. (drive which queue clients/routes load).
    • selfService (mobile/web/api.v2/smsAuthPattern/mimeTypes), kiosk (separate session + FaceKomPont webrtc constraints + compatibleVersion), app (compatible app/SDK versions, legacy socket.io), jwt (secret + keystore), security (helmet, ipFilter, csrf, sensitiveConfigFields), logging, branding.
  • Env vars (verified in code):
    • NODE_ENV — selects config file; special-cases dev/travisci (config.js:41,73).
    • DEV_DOMAIN — dev hostname; falls back to /etc/hostname (config.js:42-44).
    • TZ — force-set to Etc/UTC at boot (server.js:55).
    • NODE_TLS_REJECT_UNAUTHORIZED='0' — set when settings.allowSelfSignedCerts (server.js:57-59).

config/dev.json ships placeholder secrets (web.session.secret, jwt.secret, jwt.keystore[].k, webrtc.turn.secret, portal.headerToken.value). These are dev defaults only — never reuse in production. security.sensitiveConfigFields lists exactly which keys must be redacted before any config is exposed to a client (getSecureConfig).


8. Tests

  • Framework: Jest ^30 (config test/jest.config.js): rootDir = repo root, ignores node_modules|web|yarn-offline-cache, collectCoverage, coverageProvider: 'v8', lcov-only reporter → test/coverage/jest, testTimeout 30000, transform: {} (no transpile — tests run native).
  • Location: test/tests/unit/**115 .test.js files (glob test/tests/unit/**/*.test.js, recursive, excluding node_modules; repo-wide there are 116 — the extra one is customization/test/tests/unit/services/custom-compatibility-service.test.js), grouped: top-level (webserver.test.js, translations.test.js, device-change-info.test.js), api/* (19 endpoint tests), client/elements/*, client/engine/{message,radio,view}/*, client/features/{system-check,videochat,webrtc,time-slot-picker}/*. Customization tests live under customization/test/ (coverage-ignored).
  • How to run: yarn test:unit (= yarn jest unit/* --forceExit) or a single suite yarn jest <testfile> (README). Requires the test_resources repo cloned to /workspace/test_resources (README:7).
  • test/testconfigs/local.json overrides build/test config for the test env (build.istanbul:true, generateSourceMaps:false, geolocation, socket origins).
  • CI: .github/workflows/pull-request.yaml runs yarn lint + yarn build on Node 22 & 24 for every PR. .github/workflows/audit.yaml (push to devel/customization/*) runs yarn audit + improved-yarn-audit --min-severity critical (with 3 excluded GHSAs) and fails if executable files appear outside allowed dirs. test/travis.sh is the legacy Travis equivalent (lint/build/audit/git diff --exit-code).

No jest/mocha test runner config beyond test/jest.config.js; PR CI does not run the test suite — it only lints and builds. Tests are expected to be run locally / elsewhere.


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

All inter-service comms go over RabbitMQ via @techteamer/mq (mutual-TLS amqps). Registered in server.js:

RPC servers exposed BY css (server.js:81-90, 215-217): css-ping, rpc-system-oss, rpc-transport-css, and (if features.documentScanner) kiosk-document-scan.

RPC clients css CALLS (server.js:93-164, 214-216): rpc-create-customer, rpc-customer-portal-data, rpc-jwt-auth, rpc-get-customer, rpc-waiting-room, rpc-videochat-oss, rpc-callback-request, rpc-openhours, rpc-openhours-calendars, rpc-partner-service, rpc-custom-content, rpc-selfservice-actions, rpc-selfservice-upload, client-gate, background-room-export, background-self-service-room-export, rpc-system-check, rpc-jwt-kiosk-auth, rpc-kiosk-alive-check, rpc-media-content, rpc-identification-router, rpc-device-compatibility-check, rpc-appointment, rpc-transport-oss; conditional: rpc-selfservice-v2, rpc-device-change, rpc-document-upload, rpc-document-delete, rpc-customer-documents, rpc-flow-documents, rpc-presentation.

Queue servers css CONSUMES (server.js:172-212): queue-service-bus, queue-waiting-room, queue-videochat-css, queue-selfservice-css, queue-transport-css; conditional queue-selfservice-v2-css.

Queue clients css PUBLISHES TO (server.js:193-211): queue-feedback, queue-videochat-oss, queue-customer-history, queue-webrtc-log, queue-clienterror-log, queue-customer, queue-selfservice-events, queue-selfservice-v2, css-client-ping-result, queue-transport-oss; conditional kiosk-queue-document-scan.

Other infra:

  • Redis — session store + SAML-response cache, via unix socket /var/run/redis/redis-server.sock (WebServer.js, config dev.json web.session.redis).
  • OSS / back-office — reached through the *-oss / transport queues (the operator side, vuer_oss).
  • ClientGate SAML IdP/saml/sso/* endpoints + redis-cached SAMLResponse handshake (WebServer.setupSaml, routes.js:180-185).
  • TURN/STUN + Janus — WebRTC media servers referenced in webrtc.* config (URLs are sensitiveConfigFields).
  • Spring Cloud Config server — optional remote config (config.js:148).
  • No direct SQL/Mongo client in this repo — all persistence is delegated to backend services over MQ.

10. Verified gotchas

Process exits on RabbitMQ disconnect. server/bootstrap/connection/rabbitmq.js:14-19 registers connection.on('close')process.exit(2) for every connection. Combined with supervisord autorestart=true, exitcodes=0,2, a flaky MQ connection causes full restarts. Boot also process.exit(2) on any startup error (server.js:349-352).

Web + socket bind to 127.0.0.1 only. Ports 10082/10083 are loopback-bound (server.js:304,322-325); the app is not reachable except through nginx. Direct access in dev requires the nginx/supervisor stack or port-mapping.

No Dockerfile / no test step in PR CI. The image is built outside this repo, and PR CI (pull-request.yaml) only runs lint + build — green CI does not mean tests passed.

Read SonarCloud PR issues without a Sonar token (via GitHub check-run annotations). SonarCloud (sonar-project.properties: projectKey vuer-css, org techteamer, host sonarcloud.io) runs on each PR (the pull-request.yaml path) and posts every issue as a GitHub check-run annotation on the PR head commit + a summary PR comment from the sonarqubecloud bot. So the full issue list is reachable through gh/the GitHub API alone — no SonarCloud login:

gh pr view <n> --repo techteamer/vuer_css --json statusCheckRollup,headRefOid   # find "SonarCloud Code Analysis" check + head SHA
gh api repos/techteamer/vuer_css/commits/<sha>/check-runs \
  --jq '.check_runs[] | {id, name, ann: .output.annotations_count}'             # SonarCloud run id + annotation count
gh api repos/techteamer/vuer_css/check-runs/<id>/annotations                    # each issue: path, start_line, level, message + deep-link

Gotchas: (1) a passing Quality Gate ≠ zero issues — the gate only checks new-code threshold metrics (coverage/duplication/rating), so it can be GREEN with many code-smell “New issues”; (2) there is no analyzed devel baseline (only PRs run Sonar), so Sonar diffs against nothing and can attribute pre-existing smells in a touched file to the PR — confirm real authorship with gh pr diff <n>; (3) an annotation’s annotation_level (notice/warning/failure) is the issue severity, NOT the gate verdict. (Technique used in FKITDEV-8887.)

Customization seam is implicit. Routes/queues/services/socket-events are swappable at runtime via serviceContainer.emitter overrides/hooks declared in customization/customizations.js. On a customization/<partner> branch the actual behavior of /, /lobby, /feedback, /good-bye, /we-are-closed, /system-check, /waiting-room, /dch/:token, submit-feedback etc. may be replaced — always check customization/ before assuming core route logic. See customization-architecture.

CSP is hand-rolled and path-dependent. WebServer.cspMiddleware skips CSP entirely for IE/Safari and mutates sandbox/scriptSrc/connectSrc/imgSrc per request path; dev mode adds 'unsafe-eval' and livereload origins. Changing a route path can silently break its CSP. The Web SDK demo server disables CSP completely.

Build reads runtime config. Bundling pulls minify/sourcemaps/istanbul/branding from config/<env>.json at build time. Building under the wrong NODE_ENV produces wrong assets (e.g. dev builds inject istanbul coverage + 'unsafe-eval').

Mixed module systems. Server is CommonJS (require); bin/validate-config.js and bin/*.ts are ESM/TypeScript run via Node strip-types or Deno (see their shebangs). eslint.config.mjs is the flat-config ESLint.

Client RTC peers are a wrapper-in-a-wrapper. SenderPeer.pc/ReceiverPeer.pc is a Peer (a WildEmitter proxy), not an RTCPeerConnection; the real connection is at …pc.pc, and Peer only proxies createOffer/setLocalDescription/setRemoteDescription/createAnswer/addStream/close. Any other RTC API (getSenders, replaceTrack, getStats, …) is a silent no-op unless you add a Peer proxy or reach through pc.pc. Full detail: [[vuer_css#clientfeatureswebrtc--the-peer-wrapper-read-this-before-touching-rtc-apis|client/features/webrtc/ — the Peer wrapper (read this before touching RTC APIs)]]. (Found in FKITDEV-8887.)

A unit test that stubs peer.pc = { … } can MASK an RTC bug. Tests built via Object.create(SenderPeer.prototype) + peer.pc = { getSenders: () => [...] } assert against a shape production never creates (production peer.pc is a Peer, not the mock). Such a test passes while the real method no-ops in prod — exactly what hid the FKITDEV-8887 regression. Tests for these methods must drive the real SenderPeer → Peer → RTCPeerConnection chain: construct a real SenderPeer/Peer with global.RTCPeerConnection mocked to expose the needed API (getSenders, etc.). See test/tests/unit/client/features/webrtc/.


Unverified / gaps

  • Surveyed structurally, not line-by-line: the full client/ tree (25 immediate page dirs under client/ui/pages/ × ~6-10 files each, client/engine/*, client/features/*), the 30 server/web/api/*.js + 35 server/web/routes/*.js endpoint files, all ~18 server/socket/events/*, all ~60 queue client/server classes, the customization/ partner code (only customizations.js, BrandingService inputs, and the customization/server file listing were read), and the 115 test files. I read representative examples of each category (e.g. JwtAuth.js, ping.js, videochat/ page listing) and confirmed the directory maps by listing; individual endpoint/handler internals are not documented here.
  • engines/translator/Dictionary.js read only first ~60 lines (enough for the translation contract); remaining methods not detailed.
  • Customization branches (customization/raiffeisen, customization/instacash, etc.) were not checked out or diffed — this doc describes the devel-line core as present in the working tree (currently on branch bugfix/FKITDEV-8787-..., tip 1.9.11.92). Partner-specific overrides are out of scope here; see customization-branch-catalog.
  • Web SDK demo (web-sdk-demo/web-sdk-server.js) read only first ~20 lines.
  • No Dockerfile and no DB/Redis client config beyond what config/code reference — image-build and infra provisioning live outside this repo.

Sources

  • package.json, README.md, config.js, server.js, docs.json
  • bin/build/build.js, bin/watch/watch.js, bin/validate-config.js, bin/credits, bin/config.getter.ts, bin/doc.gen.ts, bin/script/{script.task.js,script.compiler.js,external.task.js,external.compiler.js}, bin/style/{style.task.js,style.compiler.js}, bin/server/server.task.js
  • engines/build/{build.js,bundle.js,restart.js}, engines/twig/render-server.js, engines/translator/Dictionary.js, engines/translator/config/package.json
  • server/service_container.js, server/bootstrap/connection/rabbitmq.js, server/logger.js, server/web/WebServer.js, server/web/routes.js, server/socket/socket-server.js, server/socket/events/ping.js, server/queue/rpc_client/JwtAuth.js, server/service/BrandingService.js (+ full server/ file listing)
  • config/dev.json, docs/config/main.json, docs/config/schemas/{queue,selfService}.schema.json (+ schema dir listing)
  • customization/customizations.js, customization/server file listing, customization/listeners listing
  • nginx_vuer_css_docker.conf, nginx_vuer_css_dev.conf (grep), supervisor_vuer_css_docker.conf, supervisor_vuer_css_dev.conf (grep)
  • .github/workflows/{pull-request.yaml,audit.yaml}, .github/CODEOWNERS
  • test/jest.config.js, test/travis.sh, test/testconfigs/local.json (+ test/tests/unit listing, 115 .test.js via test/tests/unit/**/*.test.js)
  • .babelrc, .browserslistrc, .yarnrc, sonar-project.properties, .gitignore, PULL_REQUEST_TEMPLATE.md
  • web-sdk-demo/web-sdk-server.js (head), client/ui/readme.md, client/ui/pages/videochat listing
  • client/features/webrtc/{Peer.js,SenderPeer.js,ReceiverPeer.js}, test/tests/unit/client/features/webrtc/ listing (RTC wrapper gotcha, FKITDEV-8887)
  • git -C … log (tip 62dad7f4 1.9.11.92), git branch -a