You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PostgreSQL schema selection via POSTGRES_SCHEMA. OpenWA's tables and the TypeORM migration ledger can now be placed in a dedicated Postgres schema (default public preserves historical behavior). Set POSTGRES_SCHEMA to isolate OpenWA from other apps sharing a database, or to use a managed-Postgres project schema. The schema must already exist (the built-in container creates it; for external Postgres run CREATE SCHEMA <name>; once). SQLite ignores this setting. The dashboard Infrastructure page exposes the field, and the environment variable is validated as a legal, non-reserved Postgres identifier at boot.
Changed
OpenAPI/Swagger tag hygiene. Every controller tag is now declared in the API document (ten were used but undeclared), the three Integration Fabric controllers gained @ApiTags, and the tag casing is uniform — so /api/docs groups every endpoint under a described tag instead of leaving some ungrouped.
Graceful shutdown now drains on SIGTERM/SIGINT (rolling deploys, docker stop, Ctrl+C), not just on the admin restart endpoint. On a termination signal the app flips readiness to 503 immediately so a load balancer/orchestrator stops routing, keeps serving in-flight requests for a bounded grace window, then tears down and exits deterministically. ⚠️Behavior change: a docker stop / redeploy now takes up to the grace window (SHUTDOWN_DELAY_MS, default 3s in production, 0 in dev) plus teardown instead of tearing down instantly, and the process now exits 0 on a clean signal. In Docker set stop_grace_period ≥ SHUTDOWN_DELAY_MS + your worst-case teardown (the bundled compose now sets 45s); for Kubernetes set terminationGracePeriodSeconds accordingly. A second signal during the drain forces an immediate exit. The whatsapp-web.js engine no longer lets Puppeteer install its own signal handlers (which previously killed Chromium at signal time / exit(130) before the drain could run).
The bundled Docker Compose stack pins its docker-socket-proxy and minio images to explicit tags (they were on :latest) for reproducible, non-drifting deploys, and a Dependabot docker ecosystem was added so base and stack images keep receiving update PRs. A Node >=22engines floor + .nvmrc were declared, and the transitive install-time Scarf telemetry (via swagger-ui-dist) is disabled.
Fixed
The Integration Fabric now works on PostgreSQL.conversation_mappings and integration_delivery_failures declared @PrimaryGeneratedColumn('uuid') ids but their columns were created without a Postgres DEFAULT gen_random_uuid(), so on PostgreSQL every first insert failed with a NOT NULL violation on id — breaking the plugin conversation-mapping upsert (e.g. the Chatwoot handover) and the ingress dead-letter write. SQLite was unaffected because its driver mints the uuid client-side, which is why it went unnoticed. A forward-only migration adds the default (no-op on SQLite). A new CI job now applies the full migration chain against a real PostgreSQL and asserts every generated-uuid primary key has a database default, so this dialect gap can't recur.
Indexed webhooks.sessionId. The webhook dispatch path looks up a session's active webhooks by sessionId on every emitted event, so on a busy session this was a full table scan of the webhooks table per event (the foreign-key column carried no index). A cross-dialect index migration — plus the matching entity index — makes the lookup index-backed.
Boot now rejects a non-canonical boolean feature flag instead of silently disabling the feature.QUEUE_ENABLED, MCP_ENABLED, and SERVE_DASHBOARD are read with an exact === 'true' / !== 'false' comparison, so a typo (True, 1, yes) or a stray trailing space/CR (a Windows-edited env file forwarded verbatim by docker run --env-file) silently (dis)abled the feature with zero diagnostics. These are now validated at startup and boot fails fast naming the offending key. ⚠️Behavior change: a deployment currently booting with such a value (e.g. QUEUE_ENABLED=1) will now refuse to start until corrected to true/false/unset — including SERVE_DASHBOARD=0/no, which was silently serving the dashboard and will now correctly disable it once set to false.
A fatal uncaught exception is now written to the structured log (with its stack and origin) before the process exits, instead of only a raw stack on stderr that the log pipeline missed. This is observe-only: the crash-and-restart posture is unchanged (the container restart policy still fires and the process never continues on corrupted post-exception state).
POST /infra/import-data no longer swallows a genuine database error while clearing tables. The table-clearing step tolerated only a genuinely-absent table but previously used a blanket catch, so an I/O/lock error (or an aborted transaction) could let a restore commit a merged rather than replaced dataset on SQLite. Such errors now surface and roll the whole import back (a real fault returns a 500 carrying the actual cause); the intended tolerance for a missing table is preserved.
A session no longer schedules a reconnect while the process is shutting down — a disconnect during the drain window would otherwise launch a fresh Chromium racing the shutdown teardown. The session is left DISCONNECTED (a later start / auto-restore re-initializes it cleanly).
Documentation & config accuracy..env.example now documents PORT (the port the app binds to on bare metal) distinctly from the Compose-only host-published API_PORT, and adds the QUEUE_ENABLED/CACHE_ENABLED toggles. SECURITY.md's supported-versions table and the Java SDK install snippets are refreshed to the current releases. The unused uuid/@types/uuid dependency was removed, and stale "not yet wired" comments on the plugin ingress-manifest validation (which the loader has called since it shipped) were corrected.
The bundled Docker Compose stack no longer kills Chromium mid-spawn under multi-session whatsapp-web.js workloads (#636). The per-container pids_limit shipped at 512 since the #243 hardening pass — a fork-bomb guard chosen without accounting for Chromium's multi-process model. whatsapp-web.js runs a full Chromium instance per session (browser + renderer + GPU + zygote + utilities), and WhatsApp Web is itself process-heavy, so ~4 concurrent sessions already approached 512 and the next session's Chromium was killed mid-spawn when fork() returned EAGAIN — surfacing in the API as a Failed to launch the browser process: Code: null launch failure with no useful log (the dbus/crashpad noise in the log is non-fatal). The default is now 2048 (fits ~8–10 sessions with startup-spike headroom), exposed as OPENWA_PIDS_LIMIT for larger fleets. The limit is a cgroup pids.max ceiling, not an allocation — raising it is a no-op for light containers, so this is safe for the baileys engine (single-process, no Chromium, a handful of PIDs regardless). The fork-bomb guard stays finite (-1/unlimited is explicitly discouraged). A new troubleshooting entry distinguishes the three causes of Code: null (PID exhaustion vs OOM-kill vs the XDG/crashpad crash already fixed earlier), since the cause isn't visible in the log without docker stats / dmesg.