vuer_css (Client Side Server)
Role
| Property | Value |
|---|---|
| Version | 1.9.11 |
| Runtime | Node.js >= 22.0.0 |
| Framework | Express 5 + Socket.IO 4 + React 18 + custom MVC engine |
| Repo | TechTeamer/vuer_css |
| Path (remote) | /workspace/vuer_css |
| Path (local mount) | /Users/levander/coding/mnt/Facekom/vuer_css |
Architecture Overview
vuer_css is a dual-server architecture: an Express HTTP server and a separate Socket.IO server sharing a common service layer, with all business logic delegated to vuer_oss over RabbitMQ.
graph TB Browser["Customer Browser"] Nginx["Nginx :30080/:20080"] Express["Express HTTP :10083"] SocketIO["Socket.IO :10082"] Services["Shared Services Layer"] RabbitMQ["RabbitMQ"] OSS["[[vuer_oss]]"] Janus["Janus WebRTC Gateway"] Redis["Redis (sessions)"] Browser -->|HTTPS| Nginx Nginx --> Express Nginx --> SocketIO Express --> Services SocketIO --> Services Services -->|RPC + Queue| RabbitMQ RabbitMQ --> OSS Services -->|TransportPool| Janus Express -->|Session store| Redis SocketIO -->|Token verify| Redis
Ports
| Port | Service |
|---|---|
:10083 | Express HTTP (bound to 127.0.0.1, behind Nginx) |
:10082 | Socket.IO |
:10084 | Web SDK demo (optional) |
:30080 | Nginx reverse proxy (dev) |
What It Does NOT Have
Unlike vuer_oss, vuer_css intentionally lacks:
- Database layer (no Sequelize, no direct DB access)
- Authentication strategies (no Passport)
- Document processing (no PDF/DOCX generation)
- Computer vision services
- Cron jobs, background workers, media conversion
- Email/SMS services
All business logic is delegated to vuer_oss via RabbitMQ.
Entry Point: server.js
File: /workspace/vuer_css/server.js (353 lines)
Startup Sequence (strictly ordered promise chain)
graph LR A["config.loaded"] --> B["connectRabbitMQ()"] B --> C["setupQueue()"] C --> D["setupServices()"] D --> E["setupCustomizations()"] E --> F["startWebServer(:10083)"] F --> G["startSocketServer(:10082)"]
Crash = Fast Restart
If any startup step fails, the process calls
process.exit(2). Supervisor restarts it in 1-2 seconds.
Process Setup
- Error handlers:
uncaughtException,unhandledRejection,exit, optionalwarning - Signal handlers: SIGINT → exit 130, SIGTERM → exit 143
- Timezone: Forces
process.env.TZ = 'Etc/UTC' - Self-signed certs:
NODE_TLS_REJECT_UNAUTHORIZED = '0'whensettings.allowSelfSignedCertsis true
Dependencies Registered at Startup
Hacks in server.js
- Lazy logger require: Logger is required inside catch blocks to avoid circular deps
- Mixed config access: Lines 145/150 use
config.deviceChange(direct) vsconfig.get('features.selfService')(safe). Latent bug if config shape changes.- Dead code: Lines 158-159:
customerDocumentsandflowDocumentsRPC clients marked “TODO: remove? Never used…”
Configuration: config.js
File: /workspace/vuer_css/config.js (208 lines)
Loads JSON config via getconfig library, adds safe accessor methods, handles Spring Cloud Config Server integration.
Key Patterns
| Method | Behavior |
|---|---|
config.get(path, default) | Safe dot-path accessor. Returns defaultValue if any segment missing |
config.has(path) | Proper hasOwnProperty check (correctly handles falsy values) |
config.loaded | Promise that resolves after Spring Cloud Config loads |
config.getSecureConfig() | Returns config copy with sensitive fields replaced with 'SECRET'. Supports wildcard paths |
config.get() Bug
config.get()treats0and''(empty string) as missing values due to a!current[path[0]]check. Useconfig.has()for falsy-but-valid values.
Dev Environment Auto-Config
- Reads
/etc/hostnamefor dev domain - Auto-sets
hosts.css,hosts.webSdkDemo,hosts.ossfrom hostname - Adds CORS origin for Web SDK in dev
CORS Security Defaults
- If
web.cors.origin === '*', replaces withconfig.hosts.css - If
web.socket.cors.origin === '*', replaces withconfig.hosts.css + ':443' - Handles backwards compatibility with Socket.IO v2 “origins” config
Service Container & Event Bus
File: /workspace/vuer_css/server/service_container.js (76 lines)
Central dependency injection container and event bus. ServiceBus extends WildEmitter and provides:
| Mechanism | Description | Examples |
|---|---|---|
Hooks (addHook/callHooks) | Named command tags, multiple handlers via Promise.all | 'queue', 'services', 'routes', 'socket', 'pagevisit', 'template:custom-content:*', 'webrtc:media-options' |
Overrides (registerOverride/callOverride) | Customization replaces default behavior. Last arg is always the default fn | 'routes:homepage', 'routes:waiting-room' |
| Events (WildEmitter) | Standard pub/sub | 'videochat:*', 'selfService:*', 'disaster:*', 'waiting-room:*', 'service-bus:*' |
Runtime Properties
The container is a plain object { emitter } that gets properties dynamically added during startup:
serviceContainer.emitter // ServiceBus instance
serviceContainer.socketTokenStorage // JWT token storage
serviceContainer.logger
serviceContainer.serverDiagnostic
serviceContainer.queueConnectionPool
serviceContainer.queue
serviceContainer.rpcServer.* // 3+ RPC server instances
serviceContainer.rpcClient.* // 23+ RPC client instances
serviceContainer.queueServer.* // 5+ queue server instances
serviceContainer.queueClient.* // 9+ queue client instances
serviceContainer.transportPool
serviceContainer.roomTransportStorage
serviceContainer.selfServiceTransportStorage
serviceContainer.service.* // 11+ service instances
serviceContainer.app // Express app
serviceContainer.sessionStore // Redis session store
serviceContainer.io // Socket.IO instance
serviceContainer.customizations // Customer-specific extensions
No Type Safety
Any module can mutate the container.
callOnlyHooksilently ignores additional hooks if multiple were registered (only callsproviders[0]).
Web Server: WebServer.js
File: /workspace/vuer_css/server/web/WebServer.js (553 lines)
Setup Chain (fluent builder)
setupLocale() -> setupRedis() -> setupSaml() -> setupSession() ->
setupTwig() -> setupRoutes() -> setupCSPReportViolation() ->
setup405Handler() -> setup404Handler() -> setupErrorHandler()
Middleware Stack (in order)
CSP Policy
- Default: Strict CSP with nonces, sandbox (allow-forms, allow-scripts, allow-same-origin, allow-modals)
- Dev mode: Adds
'unsafe-eval'for Istanbul coverage - Web SDK page: Adds
'unsafe-inline'to styleSrc - Videochat + presentation: Adds
blob:to imgSrc for PDF.js - Google:
*.google.comand*.gstatic.comalways in defaultSrc and scriptSrc - IE/Safari: CSP middleware completely bypassed (returns
next())
SAML Integration
Clever workaround for cross-domain cookie issues:
sequenceDiagram participant IdP as SAML IdP participant Browser participant CSS as vuer_css participant Redis IdP->>CSS: POST /saml/sso/clientGateLogin (SAMLResponse) Note over CSS: Cross-origin, no session cookie CSS->>Redis: Store SAMLResponse with UUID key (60s TTL) CSS->>Browser: 302 Redirect with ?samlResponseCacheId=UUID Browser->>CSS: GET same URL (same-origin, cookie sent) CSS->>Redis: Retrieve SAML data by UUID CSS->>Browser: Process auth, return page
Session Config
- Regular sessions: Redis-backed, httpOnly, secure, configurable sameSite/maxAge
- Kiosk sessions: Separate session config for kiosk devices
- iOS 12 fix: Overrides sameSite to
falsefor Apple Mobile major version 12 - Session retry: If session fails to initialize, retries up to 3 times
WebServer.js Hacks
- iOS 12 sameSite fix: Monkey-patches
sessionStore.generateto override cookie sameSite- Error handler: Wrong signature (
(err, req, res)— missingnextparam). Express 5 may not call it correctly.- Kiosk info loss:
req.kioskInfois set to!!kioskInfo(boolean), losing the actual info object. Full object is inreq.session.kiosk.kioskInfo.
Routing: routes.js
File: /workspace/vuer_css/server/web/routes.js (295 lines)
Every route is wrapped in serviceContainer.emitter.callOverride('routes:NAME', {...}, defaultFn), allowing the customization layer to completely replace any route handler.
Page Routes (GET, CSRF-protected)
| Route | Handler | Notes |
|---|---|---|
/ | homepage.endpoint | kioskCompatibility + allowIfWeAreOpen |
/404 | 404.endpoint | |
/feedback | feedback.endpoint | |
/good-bye | good-bye.endpoint | |
/lobby | lobby.endpoint | |
/system-check | system-check.endpoint | |
/videochat | videochat.endpoint | |
/waiting-room | waiting-room.endpoint | |
/waiting-room-exit | waiting-room-exit.endpoint | |
/we-are-closed | we-are-closed.endpoint | |
/ui-kit | ui-kit.endpoint | Only if build.uikit |
/web-sdk | web-sdk.endpoint | Only if WebSDK enabled |
/appointment | appointment-page.endpoint | Only if appointment.enabled |
/appointment-waiting | appointment-waiting-page.endpoint | + allowIfWeAreOpen |
Self-Service Routes (conditional: features.selfService && selfService.web)
| Route | Handler | Notes |
|---|---|---|
/self-service/login | self-service-login.endpoint | + phase redirect |
/self-service/auth-2-factor | self-service-auth-2-factor.endpoint | + phase redirect |
/self-service/client-gate | self-service-client-gate.endpoint | + phase redirect |
/self-service/preparation | self-service-preparation.endpoint | + phase redirect |
/self-service/consent-pep | self-service-consent-pep.endpoint | + phase redirect |
/self-service/consent-ttny | self-service-consent-ttny.endpoint | + phase redirect |
/self-service/wrapup | self-service-wrapup.endpoint | |
/self-service/abort | self-service-abort.endpoint | |
/self-service | self-service.endpoint | + phase redirect |
/saml/sso/metadata.xml | saml-metadata.endpoint | |
/saml/sso/clientGateLogin | client-gate-login.endpoint | + SAML middleware |
API Routes (POST, CSRF-protected unless noted)
| Route | Handler | Notes |
|---|---|---|
/api/pre-check | pre-check (GET) | |
/api/sentry | sentry | Client error reporting |
/api/submit-feedback | submit-feedback | |
/api/submit-registration | submit-registration | If features.registration |
/api/device-change/email | device-change-email | + IP filter |
/api/device-change/sms | device-change-sms | + IP filter |
/api/device-summary | device-summary | |
/api/request-callback | request-callback | |
/api/document-upload | document-upload | If documentUpload |
/api/document-delete | document-delete | If documentUpload |
/api/can-identify | can-identify | OpenAPI validated |
/api/mobile/is-compatible | is-compatible | OpenAPI validated |
/api/mobile/settings | mobile-settings | |
/api/presentation-document/:id | presentation-document | If features.presentationMode |
/api/self-service-* | Various | Multiple self-service API endpoints |
/sdk/translations | sdk-translations | WebSDK only, CORS |
/kiosk/ping | kioskPing.endpoint | |
/api/css-ping | css-ping-waiting-room.endpoint |
Disaster Mode
handleDisaster() middleware is applied globally:
/we-are-closedpasses through- HTML requests redirect to
/we-are-closed - API requests get 400 with body
'disaster'
CSRF Bypass
submit-appointmentroute has CSRF protection commented out (routes.js line 254). See security-audit.
CORS Race Condition
WebSDK CORS handler mutates shared
corsOptions.originbased on Referer header. Under concurrent requests, one request’s CORS origin could leak to another.
Socket.IO System
Socket Server Setup
File: /workspace/vuer_css/server/socket/socket-server.js (49 lines)
Loads 14+ event modules plus any custom modules via hook:
client, auth, pagevisit, lobby, waiting-room, echotest, ping,
videochat, videochat.presentation, videochat.customerDataChange,
videochat.validation, webrtclog, mobile, selfservice, selfservice-v2, flow
Socket Authentication
File: /workspace/vuer_css/server/socket/events/auth.js (39 lines)
sequenceDiagram participant Client as Browser participant Socket as Socket.IO Server participant Token as SocketTokenStorage participant Redis as Redis Sessions Client->>Socket: auth:auth (JWT token + socketLabel) Socket->>Token: verifyToken(JWT) Note over Token: JWT has 2-min expiry Token-->>Socket: { sessionId } Socket->>Redis: sessionStore.get(sessionId) Redis-->>Socket: sessionData Note over Socket: Delete cookie from session, attach to client.sessionData Socket-->>Client: auth:ok
On error: returns 'reload' (triggers page reload) or 'disaster' (redirects to /we-are-closed).
Key Socket Events
Videochat Events (638 lines)
Client-initiated (all auth-gated via auth.doIfHasRoom):
| Event | Purpose |
|---|---|
videochat:join | Join room, get room data (operator IDs stripped before sending to client) |
videochat:senderPeer:init/start/candidate | WebRTC peer setup |
videochat:receivingPeer:candidate | Receiving peer ICE candidates |
videochat:chat:message/log | Chat messaging |
videochat:selfMute | Self-mute toggle (blocked in kiosk mode) |
videochat:highContrast | High contrast toggle |
videochat:localVideoTrackStatus | Camera on/off |
videochat:close | Close room |
videochat:check_room_alive | Kiosk alive check |
videochat:screen:resize/deviceorientation | Screen metrics |
videochat:camera:values:complete | Camera capabilities |
Server-initiated (via ServiceBus events):
| Event | Purpose |
|---|---|
videochat:invite | Invites customer from waiting room (with timeout) |
videochat:leave/join/close | Room state changes |
videochat:chat:message/fontSize | Chat from operator |
videochat:flow:change | Flow state changes |
videochat:promptSmsToken | SMS verification prompt |
videochat:selfMute/selfHold/highContrast | Remote state changes |
videochat:receivingPeer:start/stop | Media negotiation |
videochat:screenshot:remote | Remote screenshot capture |
videochat:camera:profile/get:values/set:value | Camera control |
Duplicate Session Prevention
When a videochat pagevisit is detected, the system finds any existing socket clients with the same
customerIdon the videochat page and redirects them away (lines 609-627).
Self-Service Events (371 lines)
Full self-service lifecycle via socket:
| Event | Purpose |
|---|---|
selfService:start | Create self-service room |
selfService:getPhase/getNextPhase/getSteps | Flow navigation |
selfService:getPeerConnectionConfig | WebRTC setup |
selfService:peer:init/start/candidate | WebRTC peer management |
selfService:closeCall | End call |
selfService:screenshot-save/screenshot-recognize | Photo capture + ML recognition |
selfService:sendVerificationSms/verifySmsToken | SMS 2FA |
selfService:authLoginCredentials | Login auth |
selfService:reportConsentResult | Consent tracking |
selfService:reportStepSkip | Step skip reporting |
selfService:emrtd-info | eMRTD (electronic passport) data |
Waiting Room Events (41 lines)
join-waiting-room— Joins queue via RPC, returns queue position. Uses grace period service to handle reconnects.disconnect— Queues leave operation with grace period (allows brief disconnects without losing queue position).
Lobby Events (26 lines)
systemCheck:results— Saves system check results to customer history. Size-limited to 24KB.
RabbitMQ Queue Layer
All queue classes extend @techteamer/mq base classes. See rabbitmq-communication for the full RabbitMQ architecture.
RPC Clients (request-response, to vuer_oss)
| Queue Name | Client Class | Purpose |
|---|---|---|
rpc-create-customer | CreateCustomer | Create customer record |
rpc-customer-portal-data | PortalData | Get portal data |
rpc-jwt-auth | JwtAuth | JWT authentication |
rpc-get-customer | GetCustomer | Retrieve customer |
rpc-waiting-room | WaitingRoom | Join/leave waiting room |
rpc-videochat-oss | VideoChatOss | Videochat room operations |
rpc-callback-request | RequestCallback | Request callback |
rpc-openhours | OpenHours | Get open hours |
rpc-openhours-calendars | OpenHoursCalendars | Calendar management |
rpc-partner-service | PartnerService | Partner data |
rpc-custom-content | CustomContent | Dynamic content |
rpc-selfservice-actions | SelfServiceActions | Self-service operations |
rpc-selfservice-upload | SelfServiceUpload | Screenshot upload/recognize |
client-gate | ClientGate | Client gate auth |
background-room-export | RoomExport | Room data export |
background-self-service-room-export | SelfServiceRoomExport | Self-service export |
rpc-system-check | SystemCheck | System compatibility check |
rpc-jwt-kiosk-auth | JwtKioskAuth | Kiosk JWT auth |
rpc-kiosk-alive-check | KioskAliveCheck | Kiosk heartbeat |
rpc-media-content | MediaContent | Media content (hold screen) |
rpc-identification-router | IdentificationRouter | Route identification |
rpc-device-compatibility-check | DeviceCompatibilityCheck | Device compat |
rpc-appointment | Appointment | Appointment management |
rpc-device-change | DeviceChange | (conditional) |
rpc-document-upload/delete | DocumentUpload/Delete | (conditional) |
rpc-presentation | Presentation | (conditional) |
rpc-selfservice-v2 | SelfServiceV2 | (conditional) |
RPC Servers (receive from vuer_oss)
| Queue Name | Server Class | Purpose |
|---|---|---|
css-ping | Ping | Health check |
rpc-system-oss | SystemOss | System commands from OSS |
kiosk-document-scan | DocumentScanRPCServer | Document scan results |
rpc-transport-css | TransportCss | Transport layer messages |
Queue Servers (fire-and-forget, from vuer_oss)
| Queue Name | Server Class | Purpose |
|---|---|---|
queue-service-bus | ServiceBus | OSS started, disaster on/off |
queue-waiting-room | WaitingRoom | Queue position updates |
queue-videochat-css | VideoChatCss | Videochat events (join/leave/close) |
queue-selfservice-css | SelfServiceCss | Self-service events |
queue-selfservice-v2-css | SelfServiceV2Css | V2 events |
queue-transport-css | TransportCss | Transport messages |
Queue Clients (fire-and-forget, to vuer_oss)
| Queue Name | Client Class | Purpose |
|---|---|---|
queue-feedback | Feedback | Submit feedback |
queue-videochat-oss | VideoChatOss | Join/leave/resize/orientation |
queue-customer-history | CustomerHistory | Log customer events |
queue-webrtc-log | WebRTCLog | WebRTC diagnostics |
queue-clienterror-log | ClientErrorLog | Client error reports |
queue-customer | Customer | Customer updates |
queue-selfservice-events | SelfServiceEvents | Self-service events |
queue-selfservice-v2 | SelfServiceV2 | V2 events |
css-client-ping-result | ClientPingResult | Ping results |
queue-transport-oss | TransportOss | Transport messages |
Transport Layer (Janus/WebRTC Relay)
TransportPool
File: /workspace/vuer_css/server/transport/TransportPool.js (236 lines)
Manages bidirectional communication between CSS and OSS for media transport (Janus WebRTC gateway). Each videochat room gets a TransportSession.
graph LR CSS["vuer_css"] -->|"register/transaction/send/destroy"| Pool["TransportPool"] Pool -->|RPC| OSS["vuer_oss"] Pool -->|Queue| OSS OSS -->|"via Janus"| WebRTC["WebRTC Media"]
| Protocol | Purpose |
|---|---|
register | Register a new session |
transaction | Request-response over RPC |
send | Fire-and-forget over queue |
destroy | Cleanup session |
Auto-registration: If a transaction arrives for an unknown session with autoRegister data, dynamically loads the session class from ./session/ directory. Path traversal protection validates sessionClassPath starts with sessionDirectoryPath.
Session Types
| Type | Purpose |
|---|---|
| RoomTransportSession | Videochat room media transport (sender/receiver peer negotiation, chat, mute, hold, screenshots, camera control) |
| SelfServiceTransportSession | Self-service media transport (peer init/start/candidate, close, Janus info) |
| EchoTransportSession | Echo test for system checks |
Storage
- RoomTransportStorage: Maps
roomId→RoomTransportSession - SelfServiceTransportStorage: Maps
roomId→SelfServiceTransportSession
Server Services
TokenService
File: /workspace/vuer_css/server/service/TokenService.js (31 lines)
- JWE encryption/decryption using
node-jose - Keystore loaded from config at startup
- Uses A256GCM content algorithm, compact format
- Default key ID:
'facekom'
SocketTokenStorage
File: /workspace/vuer_css/server/SocketTokenStorage.js (21 lines)
- Creates JWT tokens with
{ sessionId }payload, 2-minute expiry - Used to authenticate Socket.IO connections
- Tokens created in
Template.render()and passed to client viadata-socketTokenattribute
Shared Secret
Uses
config.get('jwt.secret')for signing — shared secret, not per-session. Compromise of this secret allows forging socket auth tokens.
SocketService
File: /workspace/vuer_css/server/service/SocketService.js (97 lines)
findClient(cb)— Find socket client matching predicatefilterClients(cb)— Filter all connected clientsgetClientForRoom(roomId)— Find client in specific videochat roomgetClientForSelfServiceRoom(roomId)— Find client in self-service roomstartHttpHeartbeat()— Periodic check for stale waiting room customers. IflastPing + forceDisconnectMs < now, forces leave.
BrandingService
File: /workspace/vuer_css/server/service/BrandingService.js (79 lines)
- Loads branding defaults from
customization/branding-options.json - Overrides with config-specified values and resource paths
- Validates branding resource files exist on disk
- Used during both runtime and build-time
CompatibilityService
- Browser compatibility rule checking against config
- Rules define compatible/incompatible browser+OS combinations
- Used in UA parsing middleware
DisasterModeService
File: /workspace/vuer_css/server/service/DisasterModeService.js (48 lines)
- Toggles via ServiceBus events from vuer_oss (
service-bus:disaster:on/off) - When activated, broadcasts
disaster:onto ALL connected socket clients - Client-side redirects to
/we-are-closed - HTTP requests redirected by
handleDisaster()middleware
TurnPasswordService
File: /workspace/vuer_css/server/service/TurnPasswordService.js (131 lines)
- Generates time-limited TURN server credentials using HMAC-SHA1
- Supports per-Janus-server ICE server filtering
- Strips custom keys (
janusServers,secret) before sending to client
IpFilterService
File: /workspace/vuer_css/server/service/IpFilterService.js (151 lines)
- Rate limiting by IP + tag combination
- Configurable:
throttlePeriodMs,suppressAfterAttempts,coolDownPeriodMs - Two modes:
createIpFilter(block if already filtered) andcreateIpMonitorAndFilter(monitor + block)
Stealth Rate Limiting
Returns HTTP 200 with error codes
ERROR_FKIPFT01/ERROR_FKIPFT02instead of 429. This is intentional — avoids exposing rate limiting behavior to attackers.
Other Services
| Service | Purpose |
|---|---|
| WaitingRoomGraceService | Grace period for disconnected waiting room customers (reconnect without losing queue position) |
| PartnerService | Partner-related business logic |
| SelfServiceRoomService | Self-service room management (conditional: selfService.web) |
| DeviceChangeService | Device change flow management (conditional: deviceChange) |
| waiting-room.js | Listens for waiting-room:changed events, broadcasts queue position updates |
| service-bus.js | ServiceBus queue message handling |
Server Middleware
| Middleware | File | Purpose |
|---|---|---|
| we-are-open.js | server/web/middleware/we-are-open.js | Checks open hours via RPC. Redirects to /we-are-closed. Cookie bypass: bypassopenhours=1. Appointments get early access via beforeOpeningWaitingRoomAvailableSec. |
| saml-middleware.js | server/web/middleware/saml-middleware.js | SAML SSO authentication |
| self-service-phase-redirect.js | server/web/middleware/self-service-phase-redirect.js | Ensures customer is in correct self-service phase, redirects if wrong |
| kiosk-compatiblity.js | server/web/middleware/kiosk-compatiblity.js | Kiosk device compatibility check (note: typo in filename — missing ‘i’ in compatibility) |
Server Utilities
| Utility | Purpose |
|---|---|
| magic.js | MIME type detection via wasmagic (WebAssembly libmagic) for screenshot upload validation |
| userAgent.js | UA parsing utilities |
| deviceChangeHandler.js | Device change form processing |
| formatOpenHours.js | Open hours formatting |
| getKioskType.js | Extracts kiosk type from User-Agent string |
| lobbyRoomRedirect.js | Lobby room redirect logic |
| validateFaceKomPontRequest.js | Validates FaceKomPont kiosk auth tokens |
Client Engine (Custom MVC Framework)
Not React
This is a sophisticated custom client-side MVC framework. React is used only for specific newer components. Most of the UI is built with this engine.
View
File: client/engine/view/View.js (751 lines) — The core UI primitive.
| Feature | Description |
|---|---|
| Element-to-instance mapping | Global elementToInstance Map tracks which View manages which DOM element |
| Static factory methods | create(), mount(), mountIn(), mountAll(), mountAllIn() |
| Template rendering | Static render() uses Template class to create HTML |
| CSS class generation | Auto-generates class selectors from prototype chain via fullClassId |
| Lifecycle hooks | onCreate, onAttaching, onAttached, onDetaching, onDetached, onDestroyed |
| DOM manipulation | appendTo, prependTo, detachElement, removeElement |
| Event system | action() creates event listeners, dispatch() fires CustomEvents, relay()/intent() for promise-based request-response |
| Layout system | data-layout attribute management |
| Action proxy | proxyActions() for delegation |
Template (Client-Side)
File: client/engine/view/Template.js (386 lines) — Custom template engine (NOT Twig).
| Feature | Description |
|---|---|
| Custom tags | <block>, <content>, <super>, <parent> |
| Import system | Custom element tags resolved via static get imports() array |
| Attribute extraction | Type-aware parsing (String, Number, Boolean, JSON) |
| Child directive | child="propertyName" auto-assigns rendered elements to view properties |
| Array children | child="items[]" for array-based child directives |
| Inheritance | <super> tag renders parent view’s template with content slots |
| Rendering | element.innerHTML = output — the core rendering mechanism |
Other Engine Components
| Component | File | Purpose |
|---|---|---|
| Controller | client/engine/controller/Controller.js (34 lines) | Minimal MVC controller. static control(view) factory. addModule(controller) for composition |
| Radio | client/engine/radio/Radio.js | Named channel management (create, subscribe, publish, peek, unsubscribe) |
| Channel | client/engine/radio/Channel.js | Subscriber management with Listener wrappers. publish() short-circuits on first non-null return |
| Service | client/engine/service/Service.js | Singleton pattern (constructor returns existing instance) |
| ServiceManager | client/engine/service/ServiceManager.js | Static registry of services by name |
| Action | client/engine/view/Action.js | Event listener management with auto-cleanup |
| AttributeSet | client/engine/view/AttributeSet.js | Reactive attribute management |
| DataSet | client/engine/view/DataSet.js | Dataset attribute management |
| SwitchState | client/engine/view/SwitchState.js | Binary state management |
| ViewState | client/engine/view/ViewState.js | View state management |
Client Features
Authentication (client/features/auth.js, 63 lines)
- Reads
data-socketTokenanddata-page-visit-idfromdocument.body - Connects Socket.IO via
SocketService - Emits
auth:authwith token + socketLabel - On error:
'reload'→location.reload(),'disaster'→ redirect to/we-are-closed - On reconnect: automatic page reload
- Firefox fix: Disables reload during
beforeunloadto prevent stale reload
SocketService (client/features/socket/SocketService.js, 130 lines)
Singleton client-side Socket.IO wrapper:
- Reads
data-socketioSettingsfromdocument.body(JSON) - Lazy connection via
connect() - Handles
disconnect,reload,redirect,disaster:on/off,pingevents - Global exposure:
window.socketio = this.connection(debugging convenience) - Deferred
emit()/on()/once()— queues calls until connection established
WebRTC Module (client/features/webrtc/)
| Component | Purpose |
|---|---|
| Peer.js (214 lines) | Base WebRTC peer connection wrapper using WildEmitter. Firefox 56 SDP fix for VP8/VP9. Stat watcher disabled (“DO NOT START IT, this only works for chrome now”). |
| SenderPeer.js (116 lines) | Sends local media to Janus/remote. Creates offer → sets local desc → sends via socket → sets remote desc |
| ReceiverPeer.js | Receives remote media from Janus |
| SelfServicePeer.js | Self-service specific peer connection |
| DeviceHandler.js | Media device enumeration and management |
| VolumeMeter.js | Audio level monitoring |
| iceTest.js / IceTestResult.js | ICE connectivity testing for system check |
| MediaDeviceInfo.js | Device info abstraction |
VideoChat Module (client/features/videochat/)
| Component | Purpose |
|---|---|
| VideoFeed.js (399 lines) | Video element management View: stream management, screenshot capture (5s timeout), speaker output selection, screenshot guide overlay (portrait, id-card, passport), torch/flashlight control, camera facing mode detection |
| LocalMediaService.js | Local camera/microphone stream management |
| Presentation/ | CertPresentation, ImagePresentation, PDFPresentation (PDF.js), HandlerQueue |
System Check Module (client/features/system-check/)
Comprehensive system compatibility checking:
- SystemCheck.js: Main orchestrator
- CheckList.js / CheckStep.js: Check step management
- Individual checks: BrowserCheck, CameraCheck, MicrophoneCheck, SoundCheck, ConnectionCheck, LocationCheck, PermissionCheck, MediaCheck
- StepBar: Progress indicator
Other Features
| Feature | Purpose |
|---|---|
| DeviceChange/ | Device switching flow with controller, translations |
| RequestCallback/ | Callback request UI |
| selfservice-session-expiration/ | Session timeout handling |
| socket-ping/ | Socket.IO ping measurement |
| time-slot-picker/ | Appointment time slot selection |
Client UI System
Per-Page Architecture
Each page is a separate bundle with its own script, style, template, and translations:
client/ui/pages/{page-name}/
{page-name}.script.js -- Entry point, bundled by esbuild
{page-name}.trans.js -- Translations (EN + HU)
{page-name}.ui.js -- View definitions
{page-name}.style.styl -- Stylus styles
Pages
| Page | Purpose |
|---|---|
404 | Not found page |
appointment | Appointment booking |
appointment-waiting | Appointment waiting screen |
browser-change | Browser switch prompt |
client-gate-demo | Client gate demo page |
device-change | Device change flow |
feedback | Post-call feedback |
good-bye | Session end page |
homepage | Landing page |
kiosk-incompatible | Kiosk incompatibility |
self-service | Main self-service page (largest, most complex) |
self-service-auth-2-factor | 2FA during self-service |
self-service-client-gate | Client gate verification |
self-service-consent-pep | PEP consent form |
self-service-consent-ttny | TTNY consent form (DateHandler, FormHandler, OwnerHandler) |
self-service-login | Self-service login |
self-service-preparation | Pre-service preparation |
sentry | Error reporting (Sentry with CustomTransport) |
system-check | System compatibility check |
ui-kit | UI component showcase (dev only) |
videochat | Main videochat page (Chat, ConfirmDialog, Dialog, LocalUser, Prompt, RemoteUser) |
waiting-room | Waiting room with queue position |
waiting-room-exit | Waiting room exit |
we-are-closed | Closed hours page |
web-sdk | Web SDK integration page |
Reusable UI Elements
| Element | Purpose |
|---|---|
accordion | Expandable sections |
alert | Alert messages |
CodeInput | Code/OTP input |
dropdown | Dropdown select |
Form | Form management with validation |
HighContrast | Accessibility high contrast toggle |
ImageSlideShow | Image carousel |
modal | Generic modal dialog |
Page | Base page component |
PdfView | PDF viewer (pdf.js) |
PdfViewModal | PDF in modal |
RatingList | Star rating |
Screen | Screen component |
SelfServiceSkipStepButton | Skip step button |
SelfServiceStepBar | Self-service progress |
snackBar | Toast notifications |
StepBar | Progress steps |
Layout Modes
| Layout | Use Case |
|---|---|
default | Standard browser (header/footer) |
highcontrast | Accessibility |
kiosk | Physical kiosk terminals (no header/footer) |
videochat | Video session |
videochat-kiosk | Video on kiosk |
View State Classes
UI state management via CSS classes:
ActiveState, ClosedState, ClosingState, CollapsedState, DisabledState, EmptyState, ExpandedState, HiddenState, HighlightedState, InactiveState, LoadedState, LoadingState, OnlineState, OpenClosedState, OpeningState, OpenState, TransparencyState, VisibilityState, VisibleState
React Integration
Bridge Pattern
React is not the primary UI framework. It’s integrated via a bridge that connects it to the legacy MVC engine.
react-loader.js (81 lines)
- Finds
#react-rootDOM element - Optionally loads props from
data-react-main-component-propsattribute - Initializes
ReactPageContextsingleton with translation dictionary - Creates React 18 root via
ReactDOMClient.createRoot() - Renders main component
react-page-context.js (51 lines)
Singleton shared context for React components. Holds translation Dictionary instance. Accessed by hooks.
use-translation.js (11 lines)
React hook that returns dict.t.bind(dict) from page context. Allows React components to use the same translation system as the MVC engine.
React Externals
React and ReactDOM are bundled separately as externals:
client/externals/react/react.dev.ext.js/react.prod.ext.jsclient/externals/react/react-dom.dev.ext.js/react-dom.prod.ext.js
Compiled by bin/script/external.compiler.js (Browserify) separately from page scripts (esbuild).
Build System
Architecture
Three parallel build pipelines:
graph TB subgraph "Script Pipeline (esbuild)" S1["client/ui/pages/**/*.script.js"] --> S2["web/js/{page}/{page}.script.js"] S3["client/ui/layouts/**/*.layout.js"] --> S4["web/js/{layout}/{layout}.layout.js"] end subgraph "External Pipeline (Browserify)" E1["client/externals/react/*.ext.js"] --> E2["web/js/react/*.js"] end subgraph "Style Pipeline (Stylus)" ST1["client/ui/pages/**/*.style.styl"] --> ST2["web/css/{page}/{page}.style.css"] end
Script Compilation
File: bin/script/script.compiler.js (64 lines)
- Uses esbuild (not Browserify)
- Bundles each
*.script.jsintoweb/js/output - Optional Istanbul instrumentation for coverage
- Optional minification and source maps
Hardcoded Path
sourceRoot: '/workspace/vuer_css'is hardcoded — assumes deployment path.
Style Compilation
File: bin/style/style.compiler.js (75 lines)
- Stylus with autoprefixer (via
@techteamer/poststylus) - Injects:
breakpoints,deviceSizes,colorsas Stylus variables - Injects: branding
resourcesandvaluesas Stylus variables - Global import:
client/ui/styles/global.styl - Optional CleanCSS minification
Watch Mode
bin/watch/watch.js:
- Uses
chokidarfor file watching - LiveReload support on port 11080
--restartflag for server auto-restart
Development Commands
yarn dev # Live reload with automatic file rebuilding
yarn build # Production buildi18n / Translation System
Dictionary Engine
File: engines/translator/Dictionary.js (265 lines)
| Feature | Description |
|---|---|
| Module-based | Translation modules are functions that receive a Dictionary and call dict.define(...) |
| Composable | dict.use(transModule) imports translations from another module |
| Namespaces | dict.create(namespace, transModule) for scoped translations |
| Overrides | Config-based translation overrides via dictionaryOverrides |
| Locale fallback | If current locale missing, tries other supported locales |
| Parametric | Translation functions accept arguments for interpolation |
| Caching | Server-side dictionaries cached by file path |
| Isomorphic | Same Dictionary class works on both server (Twig templates) and client (JS bundles) |
Translation Pattern
Every translatable module has a .trans.js file:
module.exports = function (dict) {
dict.use(require('../../resources/translations')) // global translations
dict.define({
greeting: (name) => ({
en: `Hello ${name}`,
hu: `Szia ${name}`
})
})
}Locale Detection (priority order)
req.query.lang(sets cookie)req.cookies.localereq.locale(from Accept-Language vialocalepackage)
Bilingual Mandatory
Every string requires both English (en) and Hungarian (hu) translations. Configured via
locales.supportedandlocales.default.
Customization System
Architecture
customization/ is a parallel directory structure mirroring client/ and server/:
graph TB Entry["customizations.js (entry point)"] Entry --> Hooks["Hook Extensions"] Entry --> Overrides["Route Overrides"] Entry --> Listeners["13 Listener Modules"] Entry --> Content["Template Content Injection"] Hooks --> QueueHooks["Queue: EmailValidation, Customer RPC clients"] Hooks --> ServiceHooks["Service: PortalClient, CustomCompatibilityService"] Hooks --> SocketHooks["Socket: Custom events"] Overrides --> Homepage["Homepage -> nusz-landing.endpoint"] Overrides --> Routes["/registration, /information, /services, /email-*-validation"]
Customization Capabilities
| Capability | Description |
|---|---|
| Route overrides | Replace default route handlers entirely |
| Hook extensions | Add queue clients, services, socket events, routes |
| Listener modules | React to lifecycle events |
| Translation overrides | Replace/extend translations |
| Template overrides | Custom Twig templates |
| Style overrides | Branding-specific Stylus files |
| Custom content | Page-specific content injection |
Listener Modules
| Listener | Purpose |
|---|---|
webrtc-media-options | WebRTC media constraint customization |
route-system-check-done | Post system-check behavior |
system-check-steps | Custom system check steps |
system-check-required-camera-capabilities | Camera requirements |
css-custom-content | Custom content injection |
client-gate | Client gate customization |
self-service-v2 | Self-service V2 behavior |
webrtc-hd-constraints | HD video constraints |
config-socketio-settings | Socket.IO config override |
get-calendar-name | Calendar selection logic |
route-waiting-room-validate | Waiting room validation |
route-feedback-validate | Feedback validation |
home-page | Homepage customization |
Branding System
customization/ui/branding/ provides:
- Colors:
colors.styl,colors.kiosk.styl - Fonts:
font.styl,font.kiosk.styl - Loaders:
loaders.styl,loaders.kiosk.styl - Layout styles: Per-layout branding overrides
- Page styles: Per-page branding overrides (regular + kiosk variants)
- Icons: SVG icon symbols via Twig template
NUSZ Integration
The current customization is for “NUSZ” (likely a Hungarian financial institution):
- Custom landing page, registration, information, services pages
- Email validation flow
- Custom submit-registration API
- Portal client integration
Template Rendering Pipeline
Server-Side: Template.js (69 lines)
The Template class bridges server routes to Twig templates:
- Route handler creates a Template instance with template path
- Template constructor auto-generates:
entryScript:/js/{page}/{page}.script.js?{randomizer}entryStyle:/css/{page}/{page}.style.css?{randomizer}kioskStyle:/css/{page}/{page}.kiosk.style.css?{randomizer}brandingStyle:/branding/pages/{page}.style.branding.css?{randomizer}dictPath: Path to translation module
render(req, res):- Sets locale from request
- Copies browser info
- Creates socket token (JWT) for the session
- Gets CSRF token
- Calls
template:custom-content:{pageName}hook for custom data - Calls
webrtc:hd-constraintshook - Gets Socket.IO settings via hook
- Renders Twig template with all data
Twig Engine
engines/twig/render-server.js sets up Twig with custom filters:
| Filter | Purpose |
|---|---|
documentTypeFilter | Document type formatting |
filesizeFilter | File size formatting |
formatDate | Date formatting |
getSrc | Resource URL generation |
timestampFilter | Timestamp formatting |
zeropad | Zero-padding numbers |
Security Analysis
See security-audit for the full security posture.
Strengths
| # | Control |
|---|---|
| 1 | Helmet.js comprehensive HTTP security headers |
| 2 | CSP with nonces: Per-request nonce for script tags |
| 3 | CSRF protection: csurf middleware on most routes |
| 4 | Host header validation: Blocks unexpected Host headers |
| 5 | JWT socket auth: Short-lived (2-min) tokens for Socket.IO |
| 6 | JWE encryption: node-jose for sensitive token encryption |
| 7 | Redis sessions: Server-side session storage |
| 8 | IP rate limiting: Configurable per-endpoint throttling |
| 9 | MIME type validation: wasmagic for uploaded file validation |
| 10 | Sensitive config masking: getSecureConfig() redacts sensitive fields |
| 11 | Path traversal protection: TransportPool validates session class paths |
| 12 | OpenAPI validation: Input validation on can-identify and is-compatible APIs |
| 13 | Sandbox CSP: Restrictive sandbox on most pages |
Vulnerabilities / Concerns
HIGH: innerHTML XSS Vectors
Multiple
innerHTMLassignments with potentially untrusted data:
- VideoFeed.js:337 —
this.videoMessageContent.innerHTML = content(verify all callers)- VideoFeed.js:374/378 —
holdMediafrom server via socket event. If URL is user-controlled, XSS.- modal.js:168/187 — Modal content injection
- Form.js:87/222 — Translation injection (safe if translations trusted)
- waiting-room.script.js:37/43 — Video/image source injection
- RequestCallback.js:99 — Translation text injection
HIGH: CSRF Bypass
submit-appointmentroute has CSRF protection commented out (routes.js line 254).
MEDIUM: CORS Configuration Mutation
WebSDK CORS handler mutates shared
corsOptions.originbased on Referer header. Under concurrent requests, one request’s origin could leak to another. Race condition.
MEDIUM: Self-Signed Cert Bypass
settings.allowSelfSignedCertsdisables TLS verification globally (NODE_TLS_REJECT_UNAUTHORIZED = '0'). Should be dev-only but controlled by config.
MEDIUM: Socket Token Shared Secret
Single
jwt.secretfor all socket tokens. Compromise allows forging auth tokens.
| Severity | Issue |
|---|---|
| LOW | CSP middleware completely skipped for IE and Safari |
| LOW | Dev mode adds 'unsafe-eval' to CSP for Istanbul |
| LOW | *.google.com and *.gstatic.com always in CSP |
| LOW | config.get() treats 0 and '' as missing values |
Code Smells, Hacks & TODOs
See tech-debt for tracking.
TODOs
| Location | Note |
|---|---|
| server.js:158-159 | customerDocuments and flowDocuments RPC clients: “TODO: remove? Never used…“ |
| feedback.endpoint.js:18 | ”TODO: assert if feedback was already given” |
| DeviceHandler.js:133 | Generic “TODO” without description |
| videochat.services.js:150 | ”TODO: handle when this is called meanwhile a sender peer is trying to reconnect” |
| videochat.services.js:192 | ”TODO: do something with publishers” |
| videochat.script.js:330 | ”TODO: needs server side implementation” |
| self-service.ui.js | Multiple TODOs for “upload task” (lines 163, 238, 525, 587, 733, 783) and “flow action messages” (line 895) |
| self-service.script.js:16 | ”FIXME why is this needed again?” for initial device summary call |
FIXMEs
| Location | Note |
|---|---|
| SelfServiceTransportSession.js:25 | ”FIXME: after socket disconnect this is just noise” |
| SelfServicePeer.js:51 | ”FIXME log order” |
| self-service.script.js:16 | Device summary fetch purpose unclear |
Code Smells
| Issue | Details |
|---|---|
| Mixed config access | config.deviceChange (direct) vs config.get('deviceChange') (safe) |
| Commented-out code | socket/client.js has auth imports commented out, Peer.js has entire stat watcher commented out |
| Inconsistent error handling | Some socket callbacks use cb('error'), others cb(new Error(...)), others cb(err.message) |
| setInterval without cleanup | IpFilterService creates interval in constructor, never cleared |
| Magic strings | Socket event names duplicated across files with no constants |
| Error handler signature | WebServer.js error handler missing next parameter |
| Filename typo | kiosk-compatiblity.js (missing ‘i’ in compatibility) |
Deprecated Patterns
| Pattern | Replacement |
|---|---|
pc.addStream(stream) in Peer.js | Should use addTrack() |
pc.onaddstream in Peer.js | Should use ontrack |
| Browserify for externals | esbuild used for main bundles already |
csurf package | Deprecated with known issues |
Dead Code & Suspicious Patterns
Dead Code
| Location | Description |
|---|---|
Peer.js startWatcher() | Always returns false, entire implementation commented out (lines 133-210) |
| server.js:158-159 | customerDocuments and flowDocuments RPC clients likely unused |
| socket/client.js | Two require lines commented out (auth, serviceContainer) |
| WebServer.js:156 | log4js.connectLogger commented out |
Suspicious Patterns
| Pattern | Concern |
|---|---|
window.socketio = this.connection | Global window assignment in SocketService.js |
| IpFilter HTTP 200 | Rate-limited requests return 200 instead of 429 (intentional stealth) |
Radio.deleteChannel | Calls this._channels.delete(channel) twice (line 51-52) |
| Session cookie deletion | In auth.js socket event, delete sessionData.cookie mutates session data object |
Data Flow Diagrams
Customer Journey: Homepage to Videochat
sequenceDiagram participant B as Browser participant E as vuer_css (Express) participant S as vuer_css (Socket) participant O as vuer_oss (RabbitMQ) participant J as Janus B->>E: GET / E-->>B: HTML + socketToken B->>S: Socket.IO connect B->>S: auth:auth(token) S->>S: verifyToken(jwt) + sessionStore.get() S-->>B: auth:ok B->>E: GET /system-check E-->>B: HTML + socketToken Note over B: Runs browser/cam/mic/connection checks B->>S: systemCheck:results S->>O: queue-customer-history B->>E: GET /waiting-room E-->>B: HTML + socketToken B->>S: join-waiting-room S->>O: rpc-waiting-room.join S-->>B: queueLength Note over B: Waiting... O->>S: queue-videochat-css (invite) S-->>B: videochat:invite B->>E: GET /videochat E-->>B: HTML + socketToken B->>S: videochat:join S->>O: rpc-videochat-oss S-->>B: roomData + peerConfig B->>S: senderPeer:init S->>O: TransportPool -> Janus S-->>B: offer B->>S: senderPeer:start(jsep) S->>O: TransportPool -> Janus S-->>B: answer Note over B,J: WebRTC media flowing via Janus gateway
Self-Service Flow
sequenceDiagram participant B as Browser participant CSS as vuer_css participant OSS as vuer_oss participant CV as vuer_cv B->>CSS: GET /self-service/login CSS-->>B: Login page B->>CSS: POST login auth CSS->>OSS: RPC: login auth CSS-->>B: Redirect to 2FA B->>CSS: GET /self-service/auth-2-factor B->>CSS: POST 2FA send CSS->>OSS: RPC: send SMS B->>CSS: POST 2FA verify CSS->>OSS: RPC: verify token CSS-->>B: Redirect to prep B->>CSS: GET /self-service B->>CSS: socket: selfService:start CSS->>OSS: RPC: startSelfService B->>CSS: socket: peer:init/start/candidate Note over B: WebRTC for photo capture B->>CSS: socket: screenshot-recognize CSS->>OSS: RPC: upload + ML OSS->>CV: CV inference CV-->>OSS: Recognition results OSS-->>CSS: Results CSS-->>B: Recognition results B->>CSS: socket: getNextPhase CSS->>OSS: RPC: getNextPhase Note over B: Consent, wrapup, etc.
Project Structure
server.js Entry point
config.js Configuration
server/
service_container.js DI container + event bus
SocketTokenStorage.js JWT token management
auth.js Socket auth helpers
diagnostic.js Server diagnostics
logger.js Log4js setup
bootstrap/connection/rabbitmq.js RabbitMQ connection
flow/Flow.trans.js Flow translations (EN+HU)
model/DeviceChangeInfo.js Device change model
queue/
rpc_client/*.js 25+ RPC clients
rpc_server/*.js 4 RPC servers
queue_client/*.js 9 queue clients
queue_server/*.js 6 queue servers
service/*.js 11+ services
socket/
socket-server.js Socket.IO setup
client.js Socket client init
events/*.js 15 event modules
models/*.js 3 data models
transport/*.js Transport layer (5 files)
util/*.js 2 utility modules
web/
WebServer.js Express setup (553 lines)
Template.js Template rendering
routes.js Route registration (295 lines)
routes/*.endpoint.js 30+ route handlers
api/*.js 25+ API handlers
helper/*.js 5 helpers
middleware/*.js 4 middleware
client/
engine/ Custom MVC framework
controller/Controller.js MVC Controller
message/Intent.js Message intent
radio/Radio.js, Channel.js Pub/sub messaging
service/Service.js, ServiceManager.js Singleton services
view/View.js Core View (751 lines)
view/Template.js Client template engine (386 lines)
view/Action.js, AttributeSet.js, etc. View supporting classes
features/
auth.js Client auth
compatibility.js Browser compat
socket/SocketService.js Socket.IO wrapper
webrtc/*.js WebRTC (9 files)
videochat/*.js Videochat (7 files)
system-check/**/*.js System check (20+ files)
DeviceChange/, RequestCallback/ Feature modules
react/
react-loader.js React <-> MVC bridge
react-page-context.js Shared context singleton
hooks/use-translation.js Translation hook
ui/
elements/**/*.js 60+ reusable UI elements
layouts/**/*.js 5 layouts
pages/**/*.js 30+ page types (50+ files)
regions/**/*.js 3 regions
states/*.js 19 view state classes
styles/ Stylus CSS
externals/react/*.js React bundles (Browserify)
resources/*.js Colors, breakpoints, translations
customization/
customizations.js Entry point (90 lines)
branding-options.json Branding defaults
listeners/** 13 listener modules
resources/translations.js Translation overrides
server/** Server-side overrides
ui/** UI overrides (styles, templates, scripts)
flow/** Flow overrides
engines/
translator/**/*.js Translation engine (Dictionary)
twig/render-server.js Twig setup + custom filters
build/*.js Build utilities
util/*.js Template filters/utilities
bin/
build/build.js Master build
script/script.compiler.js esbuild compiler
script/external.compiler.js Browserify for externals
style/style.compiler.js Stylus compiler
watch/watch.js File watcher + LiveReload
validate-config.js Config validation (AJV)
config/ Environment configs (dev.json, docker.json)
web/ Compiled static assets (DO NOT edit)
test/tests/unit/ Jest unit tests
Testing
yarn test:unit # Run all unit tests (Jest)
yarn jest test/tests/unit/ # Specific directory
yarn jest sometest.test.js # Single file- Unit tests only (no E2E in this project)
- Tests organized by: api, client, engines, flow, middleware, queue, routes, services, socket, transport
- Shared fixtures:
/workspace/test_resources
Browser Compatibility
Extensive polyfill support:
- html5shiv, js-polyfills, core-js
- regenerator-runtime
- resize-observer-polyfill
Related
- FaceKom - Platform overview
- vuer_oss - Backend server (all business logic lives here)
- vuer_cv - Computer vision service
- rabbitmq-communication - RabbitMQ architecture
- security-audit - Security findings
- tech-debt - Technical debt tracking
- infrastructure - DNS, networking, containers