Eviworx
Docs

Architecture Overview

Eviworx consists of 12 containers, each with a dedicated role. Backend and workers can run as multiple instances; see Multi-Instance Setup.

Container Overview

Container Technology Function Ports
traefik Traefik v3 API gateway, TLS termination, routing, rate limiting 80, 443
frontend React 19+ + NGINX Single Page Application (SPA) 80
backend Node.js + Express REST API & business logic 3000
job-worker Node.js + BullMQ CronJobs & scheduled tasks (28 action types) 3001
email-worker Node.js + BullMQ Email queue processing (IMAP/SMTP, Graph API) 3005
notification-worker Node.js + BullMQ Multi-channel notifications (Teams Bot Framework, Webex), attachment support, quiet hours 3006
workflow-engine Node.js Business process management (8 node types) 3003
av-worker Node.js Virus scan orchestrator (zero-trust) 3007
report-generator Node.js + BullMQ Custom reports, CSV/PDF export (read-only DB) 3004
db PostgreSQL 17 Primary database (150+ models) 5432
redis Redis 8 Cache, job queue & distributed locks 6379
clamav ClamAV Virus scanner daemon 3310

Architecture Diagram

                          User (Browser)
                               |
                               | HTTPS (443) / HTTP (80)
                               v
                    +---------------------+
                    |      TRAEFIK        |
                    |  (API Gateway v3)   |
                    |  TLS-Termination    |
                    |  Rate-Limiting      |
                    +---------------------+
                       |             |
          /_app/*      |             |  /api/*
          / (SPA)      |             |
                       v             v
            +-------------+   +-------------+
            |  FRONTEND   |   |   BACKEND   |
            | (React SPA) |   | (Express)   |
            |  NGINX :80  |   |   :3000     |
            +-------------+   +------+------+
                                     |
              +----------+-----------+----------+-----------+
              |          |           |          |           |
              v          v           v          v           v
         +--------+ +--------+ +--------+ +--------+ +----------+
         |  Job   | | Email  | | Notif. | |Workfl. | | Report   |
         | Worker | | Worker | | Worker | | Engine | | Generator|
         | :3001  | | :3005  | | :3006  | | :3003  | | :3004    |
         +--------+ +--------+ +--------+ +--------+ +----------+
              |          |           |          |           |
              v          v           v          v           v
         +--------+ +--------+                        +--------+
         |  AV    | | Redis  |                        |  DB    |
         | Worker | | :6379  |                        | :5432  |
         | :3007  | +--------+                        +--------+
         +---+----+
             |
             v
         +--------+
         | ClamAV |
         | :3310  |
         +--------+

Component Details

Traefik (API-Gateway)

  • Technology: Traefik v3
  • Purpose: API gateway, TLS termination, routing, rate limiting, CSP headers
  • Routing:
    • /api/* → Backend (:3000)
    • Internal interfaces between the services are not reachable from outside (blocked by Traefik)
    • Everything else → Frontend (:80)
  • Health-Check: Ping Entrypoint
  • Database access: None
  • External Reverse Proxy: Configure forwardedHeaders.trustedIPs in traefik.yml + TRUSTED_PROXIES in .env (Details)

Frontend (React 19+ + NGINX)

  • Technology: React 19.2.0, Vite, Tailwind CSS 4, shadcn/ui
  • Purpose: Single Page Application (SPA)
  • NGINX: Static file serving, SPA routing; hashed build files live under /_app/ (cache rules)
  • Communication: REST API → Backend (Port 3000)

Backend (Node.js + Express)

  • Technology: Node.js, Express, Prisma ORM, Zod Validation
  • Purpose: Central business logic & API
  • APIs:
    • REST API (Public) – For frontend & external clients
    • Internal API – For worker communication (API-key protected)
  • Database access: Full access (user: helpdesk_user)

Job-Worker (CronJobs & Automation)

  • Technology: Node.js, BullMQ
  • Purpose: Scheduled jobs & automation actions
  • Action types (28, selection):
    • Webhook (HTTP calls with SSRF protection)
    • Assign Agent/Group
    • Create/Update Ticket
    • Report Schedule Check (scheduled reports)
    • Asset Model Clustering
    • SLA Monitor
    • Attachment Cleanup, Retention Purge
    • Workload Sync
    • and more...
  • Database access: Restricted (only CronJob tables)
  • Communication: Internal API for all domain data
  • Multi-Instance: Redis distributed locks

Email-Worker

  • Technology: Node.js, BullMQ, Nodemailer
  • Purpose: Email queue processing & IMAP polling
  • Incoming emails: IMAP polling / Graph API → create tickets
  • Outgoing emails: SMTP / Graph API sending via queue
  • Database access: None (everything via Internal API)

Notification-Worker

  • Technology: Node.js, BullMQ
  • Purpose: Multi-channel notifications (Teams Bot Framework, Webex)
  • Channels:
    • Microsoft Teams (via Bot Framework)
    • Webex (via REST API)
    • Email (delegates to Email-Worker)
  • Features: Attachment support, quiet hours
  • Two-tier routing: Backend → Notification-Worker → Channel-specific adapter
  • Database access: None (everything via Internal API)

Workflow-Engine

  • Technology: Node.js, BullMQ
  • Purpose: Business process management
  • Node types (8):
    • Manual Task – Manual tasks for users
    • Approval – Approval steps with auto-approval
    • Automated Action – API calls, webhooks
    • Notification – Send notifications
    • Parallel Gateway – Multiple paths in parallel
    • Conditional Branch – If/Else branching
    • Data Collection – Collect data (forms)
    • Timer Event – Delay or deadline
  • Database access: None (everything via Internal API)
  • Multi-Instance: Redis locks for step processing

AV-Worker (Virus-Scan-Orchestrator)

  • Technology: Node.js
  • Purpose: Coordinates virus scans (zero-trust)
  • Zero-Trust: The AV-Worker has no access to the files.
  • Flow:
    1. Backend stores file in /app/uploads
    2. AV-Worker passes only the file path to ClamAV (via TCP)
    3. ClamAV reads file from own volume
    4. AV-Worker updates status via Internal API
  • Quarantine: Infected files automatically to /app/quarantine (7 days retention)

Report-Generator

  • Technology: Node.js, BullMQ
  • Purpose: Custom reports, CSV/PDF export
  • Database access: Read-Only (helpdesk_readonly)
  • Health-Check: GET /health/live (Port 3004)

PostgreSQL (Datenbank)

  • Version: PostgreSQL 17 Alpine
  • Data model: 150+ Prisma-Modelle in ~50 Domains
  • Users:
    • helpdesk_user – Full access (Backend)
    • helpdesk_jobworker – Restricted (only CronJob tables)
    • helpdesk_readonly – Read-only (Report-Generator)
  • Volumes: postgres_data (Persistent data)

Redis (Cache & Queue)

  • Version: Redis 8 Alpine
  • Authentication: Password-protected (--requirepass)
  • Usage:
    • Cache: RBAC permissions, session cache, audit-chain fallback
    • Job-Queue: BullMQ for all workers (Email, Notification, Jobs)
    • Distributed Locks: Coordination between instances
  • Persistence: AOF (Append-Only-File) – Queue data persists across restarts

ClamAV (Virus-Scanner)

  • Version: ClamAV 1.5 (official image)
  • Purpose: Virus scanning daemon
  • Signature updates: 24x/day – hourly (Freshclam, FRESHCLAM_CHECKS=24)
  • Volume access: /app/uploads (read-only)
  • Resources: 2 GB RAM Limit, 2 CPUs

Communication Flows

1. User Request (via Traefik)

User → Traefik (HTTPS :443) → Frontend (React SPA) OR Backend (REST API) → PostgreSQL
                                                                    ↓
                                                                Redis (Cache)

2. Worker Communication (Zero Database Access)

Worker → Backend (Internal API) → PostgreSQL
   ↓
Redis (Job Queue + Locks)

Important: The Email, Notification, Workflow and AV workers have no direct database access; they retrieve all data via the Internal API. The Job-Worker has restricted DB access (only CronJob tables), the Report-Generator read-only access (helpdesk_readonly).

3. Notification Flow (Two-Tier Routing)

Backend → Redis (notification:enqueue Queue)
            ↓
Notification-Worker → fetches User/Template via Internal API
            ↓
  +---------+---------+
  v         v         v
Email    Teams     Webex
Worker   Bot       API
         Framework

4. Virus Scan Flow (Zero-Trust)

Backend → Uploads file to /app/uploads → Creates DB entry (status: PENDING)
            ↓
AV-Worker (polling every 10s) → Fetches pending files via Internal API
            ↓
AV-Worker sends ONLY file path (NOT content!) to ClamAV via TCP
            ↓
ClamAV reads file from shared volume /app/uploads (read-only)
            ↓
ClamAV returns: CLEAN / INFECTED
            ↓
AV-Worker updates status via Internal API
            ↓
If INFECTED: Backend moves file to /app/quarantine

Security Architecture

Principle of Least Privilege

Container Database Access Rationale
Traefik None No DB access; blocks internal interfaces from outside
Backend Full (helpdesk_user) Central business logic requires full access
Job-Worker Restricted (helpdesk_jobworker) Only CronJob tables (CronJob, JobExecution, WorkerInstance)
Report-Generator Read-Only (helpdesk_readonly) Read-only access for reports/analytics
Email-Worker None Data via Internal API – no DB access needed
Notification-Worker None Data via Internal API
Workflow-Engine None Data via Internal API
AV-Worker None Data via Internal API – zero-trust

Network Isolation

  • All containers in same Docker network (isolated)
  • Only Traefik exposed (ports 80/443)
  • Backend/workers/frontend not directly accessible from outside
  • Inter-container communication via DNS (e.g., http://backend:3000)

Multi-Instance Setup (High Availability)

Eviworx is designed for active-active deployments. Multiple instances can run in parallel.

Distributed Locks (Redis-based)

  • Job-Worker: Lock per CronJob (only one instance executes job)
  • Workflow-Engine: Lock per workflow step
  • Implementation: Redlock-Algorithm

Worker Heartbeat Monitoring

  • Each worker instance registers in the Redis health registry via heartbeat
  • Heartbeat every 15 seconds, the entry expires after 30 seconds
  • Instances without a heartbeat count as offline; their execution history stays visible
  • Stuck jobs redistributed (recovery logic)

Load Balancing

  • Traefik: Central load balancer & API gateway
  • Backend: Multiple instances behind Traefik
  • Worker: Automatic via BullMQ (pull-based)

Data Flow Examples

Example 1: Create Ticket

1. User fills out ticket form (Frontend)
2. Frontend → POST /api/tickets (via Traefik → Backend)
3. Backend:
   - Validates input (Zod schema)
   - Checks permissions (RBAC)
   - Creates ticket in PostgreSQL
   - Creates audit-chain event
   - Enqueues notification (Redis)
4. Notification-Worker (async):
   - Fetches User/Template via Internal API
   - Sends email/Teams/Webex
5. Frontend receives response (201 Created)

Example 2: Scheduled Job (CronJob)

1. CronJob defined: "Every day at 9am: Generate Report"
2. Job-Worker (Scheduler):
   - Checks all jobs (via DB)
   - Finds job with cron expression "0 9 * * *"
   - Acquired Distributed Lock (Redis)
3. Job-Worker runs action:
   - Action: GenerateReport
   - Fetches report data via Internal API
   - Generates PDF
   - Stores in /app/uploads
   - Enqueues email notification
4. Email-Worker:
   - Sends report by email
5. Job-Worker updated execution status (SUCCESS)

Example 3: Workflow Execution

1. User starts workflow (e.g. "Onboarding Workflow")
2. Backend:
   - Creates workflow instance
   - Enqueues start event
3. Workflow-Engine:
   - Fetches Instance via Internal API
   - Processes step by step
   - Step 1: Manual Task → assignee notification
   - Step 2: Approval → waits for user input
   - Step 3: Automated Action → webhook call
   - Step 4: Notification → Teams message
4. On each step:
   - Acquired Lock (Redis)
   - Updates step status via Internal API
   - Release Lock
5. Workflow completed → status: COMPLETED

Volumes & Persistence

Volume Used by Purpose
postgres_data db Persistent database data
redis_data redis AOF persistence for job queue
uploads backend, clamav Uploaded files (attachments)
quarantine backend Infected files (7 days retention)
clamav_data clamav Virus signatures
sourcemaps frontend (rw), backend (ro) JS source maps for error tracking, the five newest releases (frontend writes, backend reads)

Resource Requirements

Minimum (Development)

  • CPU: 4 cores
  • RAM: 8 GB
  • Storage: 20 GB

Recommended (Production)

  • CPU: 8 cores
  • RAM: 16 GB
  • Storage: 100 GB (depending on attachments)

Per-Container Limits (Configurable)

Container CPU Limit Memory Limit
traefik1.0256 MB
frontend0.5256 MB
backend2.02 GB
db2.02 GB
redis1.01 GB
job-worker1.01 GB
email-worker1.0512 MB
notification-worker1.0512 MB
workflow-engine1.0512 MB
av-worker1.01.5 GB
report-generator1.01.5 GB
clamav2.02 GB

Monitoring & Observability

Health-Checks

  • Traefik: Ping Entrypoint (built-in health check)
  • Backend: GET /api/health/live (Liveness probe; readiness is checked by /api/health/ready)
  • Workflow-Engine:
    • GET /health/live (Liveness probe)
    • GET /health/ready (Readiness probe, checks Redis)
  • Report-Generator: GET /health/live (Port 3004)
  • Job-Worker: Health-Endpoint (Port 3001)
  • Email-Worker: Health-Endpoint (Port 3005)
  • Notification-Worker: Health-Endpoint (Port 3006)
  • AV-Worker: Health-Endpoint (Port 3007)

System Status (Admin UI + Health API)

The live state of the entire stack is visible in the admin area under Admin Center → System → System-Status (route /admin/system-status). The tab shows each service as an expandable row with its instances — per instance status, version, uptime, time of the last heartbeat, memory usage, port and the individual checks (database, Redis) including response time. Search and a status filter narrow the list. Impaired units — a mailbox without a poll attempt or a cron job in an error state, for example — appear in a separate table, infrastructure and crypto configuration (e.g. FIPS mode) in a detail card. It is backed by the backend Health API:

Endpoint Auth Purpose
GET /api/healthNoneBasic check (200 healthy / 503 unhealthy) — for monitoring systems
GET /api/health/liveNoneLiveness probe (process alive)
GET /api/health/readyNoneReadiness probe (DB + Redis reachable)
GET /api/health/servicessettings.editGeneral (logged-in users only)Status per service and instance (version, uptime, memory usage, port, individual checks), impaired units plus infrastructure and crypto configuration; data source of the System Status tab.

Note: Service health comes from a Redis registry: every instance writes a heartbeat every 15 seconds and the entry expires after 30 seconds. A service without a heartbeat shows as offline. /api/health/services requires settings.editGeneral and is reserved for logged-in users — infrastructure topology, ports, instance IDs and crypto configuration are not available through an API key.

Structured Logging (JSON)

All Eviworx-owned containers (Backend, Job-Worker, Email-Worker, Notification-Worker, Workflow-Engine, AV-Worker, Report-Generator) log in structured JSON format via Pino. External containers (Redis, PostgreSQL, ClamAV) use their native log format.

  • Log library: Pino v10 (all custom containers)
  • Fields per log entry:
    • level, time, service, msg – Standard fields
    • traceId, spanId – Distributed tracing (OpenTelemetry-compatible)
    • correlationId, requestId – Request correlation across container boundaries
    • sourceService – Shows which service triggered the request (e.g. av-worker, traefik)
  • Integration: Directly compatible with Elasticsearch/ELK, Loki, Datadog, Splunk and other JSON log aggregators
  • Traefik access logs: Also in JSON format with X-Request-ID and User-Agent
  • Rotation: max. 10 MB per file, 3 files (ClamAV, AV-Worker)
  • Access: docker compose logs -f [service-name]
// Example: Backend HTTP request log{
  "level": 30,
  "time": 1773740483502,
  "service": "backend",
  "traceId": "c5d1c321ad743f0abd05d55967adf67d",
  "spanId": "3fcb07029f32d740",
  "correlationId": "c5d1c321ad743f0abd05d55967adf67d",
  "requestId": "b36f4176-0e5b-42d7-8e17-772c0929e4d8",
  "sourceService": "traefik",
  "method": "GET",
  "url": "/api/health/live",
  "status": 200,
  "durationMs": 1,
  "msg": "HTTP request"
}
🔐
Security by Design
  • ✓ Principle of Least Privilege (DB access)
  • ✓ Zero-trust virus scan (AV-Worker without file access)
  • ✓ Network isolation (Docker network)
  • ✓ SHA-256 hash-chained audit log (tamper-evident)
  • ✓ Automatic PII scrubbing in audit logs
  • ✓ SSRF-Protection (IP-Range + DNS-Blocking)
  • ✓ Container hardening (read-only filesystems, capabilities drop)
  • ✓ FIPS 140-2 compatible algorithms (PBKDF2-SHA512, AES-256-GCM)
  • ✓ MFA/TOTP authentication
  • ✓ Redis password authentication
  • ✓ Traefik API gateway (rate limiting, CSP)
Next Steps
Container Architecture →

Details about each container

API Reference →

API modules with endpoints & examples

Security Architecture →

Zero-trust, audit chain, RBAC

Scaling & HA →

Multi-instance setup