Audited: 2026-07-06 (bms-1 SSH audit)
W4 persistent-patch state reconfirmed: 2026-08-09 (#5992 — live mount ground-truth on bms-1; the §3.1 / §3.x patch tables below reflect this, not the 2026-07-06 snapshot)
Source:/root/builds/7N4sbbrB/0/pinbox24/p24-back-ts/ (W4 — confirmed p24-back-ts), /root/builds/pn3C9eHo/0/pinbox24/p24-v-3.2/ (W3 — path as read at 2026-07-06 audit; superseded, see build-dir note below)
Server: bms-1 (94.23.26.113) — Ubuntu 20.04 EOL, OVH Kimsufi
⚠️ W3 build-dir correction (#4985). The authoritative, GitLab-runner-owned W3 compose dir is
/home/gitlab-runner/builds/eZQeLfuJe/0/pinbox24/p24-v-3.2/ (per secrets-sync.yml and
docs/bms-1/gitlab-ci-w3.yml → BUILDER_DIR). The root-owned /root/builds/pn3C9eHo/... recorded
above is not the prod serving directory — but an on-server audit (2026-08-01) proved it is not
abandoned either: it is an active W3-staging mount source and must not be deleted wholesale
(see docs/w3-w4-stack-operations.md §3). Confirm the live dir before use:
docker inspect v32-prod --format '{{index .Config.Labels "com.docker.compose.project.working_dir"}}'.
1. Overview
W3 (v3.2)
W4 (v4.2)
Codebase
Node.js legacy + JavaScript
TypeScript 4.x
Backend version
~3.2 (legacy)
4.2.17
Backend container
v32-prod
v42-prod (image: v42-prod:merged-20260706-0512)
File microservice
s3-v32-prod (ECR: old-s3)
s3-v42-prod (ECR: v4-s3)
Build dir
/home/gitlab-runner/builds/eZQeLfuJe/0/pinbox24/p24-v-3.2/ (authoritative for prod; /root/builds/pn3C9eHo/... is not the prod serving copy but is an active W3-staging mount source — do NOT delete — #4985)
/root/builds/7N4sbbrB/0/pinbox24/p24-back-ts/
SOPS file
secrets/pinbox24-w3.env.sops
secrets/pinbox24-w4.env.sops
SOPS deployed to
/opt/p24-infra/bms-1/pinbox24-w3.env
/opt/p24-infra/bms-1/pinbox24-w4.env
Network
test-net (external bridge)
test-net (external bridge)
Restart policy
unless-stopped (via docker update)
unknown — needs verification
Persistent patches
4 files
v42-prod: 5 live mounts (uploadAwsS3.helper.js, socket.middleware.js, app.js, postbookReport.helper.js, ecosystem.config.js) + credentials.json; GUS WSDL mount removed. mailgun-v42-prod: integration.helper.js (git-tracked #5992). See §3.1 / §3.x (reconfirmed 2026-08-09)
w3_app user, authSource=w3_db; Path B — /api/i18n/langs
MongoDB rs0
mongojs
MONGODB_URL
crudService CRUD (~70 controllers); Path A — falls back to PINBOX_PROD_DB in the production block
Wasabi S3
HTTP/AWS SDK
s3Bucket_*
file storage
s3-v32-prod
HTTP
s3ApiUrl
proxied file uploads
Connection-layer deep dive: the two Mongo paths above are independent, cached once at startup
(rotation needs a container restart), and fail silently/independently. Root cause of the
“langs not loading” incident and the V32_PINBOX_PROD_DB rotation gap are documented in
W3 connection handling & rotation (#3564).
Persistent state:
PM2 cluster — persistent processes required
No WebSocket (not found in W3 source)
No message queue (W3 only)
Persistent patches (volume mounts):
File
Patches
filesUpload.js
Fix B1: regId/recId fallback from query params
crudService.js
Fix B2: async.forEach callback on files without bucket
excel_import.js
Not a patch — stock git-tracked file in p24-v-3.2, mounted from the build-dir source tree (not persistent-patches/); byte-identical to the image copy, so the mount is a redundant no-op. Restored by the GitLab checkout, needs no p24-infra source of truth (#4708).
(WSDL resolves from node_modules/@pobidowski/gus-api-regon/dist/wsdl/ — the old persistent-patches/gus-api-regon-wsdl/mount was removed, it never took effect; see §3.1 patch table + v42-prod-gus-wsdl-crash-loop.md)
Polish tax registry
ConvertAPI
HTTPS
CONVERT_API
document conversion
wkhtml-v42-prod
HTTP
WK_HTML_TO_PDF_SERVER_URL
PDF generation (running — wkhtml-v42-prod container)
PM2 Plus
HTTPS
PM2_PUBLIC_KEY, PM2_SECRET_KEY
monitoring
Persistent state (critical — NOT serverless-compatible):
Component
Details
Socket.IO
initSocket(SocketIO(mainServer, options)) — WebSocket + polling at startup
2 instances, pm_id used for single-instance cron guard
Persistent patches (volume mounts) — live state reconfirmed on bms-1 2026-08-09 (#5992):
Git source: infra-src/pinbox24/w4/persistent-patches/ → shipped by secrets-sync.yml
(sync-pinbox24-w4 → “Deploy W4 persistent-patches to bms-1”) to
/root/builds/7N4sbbrB/0/pinbox24/p24-back-ts/persistent-patches/.
Mount source (bms-1)
Container path
Purpose
Still needed?
persistent-patches/uploadAwsS3.helper.js
/app/dist/globalHelpers/uploadAwsS3.helper.js
De-hardcodes Wasabi S3 creds to process.env.s3Bucket_*and adds the multi-region _bucketEndpointMap for s3getSignedUrl
YES. GitLab development src carries the de-hardcode fix (commit 63686ca5), but (a) the deployed ECR image’s baked dist/ still ships the old hardcoded creds and lacks the fix (verified #5992 — image built 2026-08-06 does not reflect merged source), and (b) upstream src has no_bucketEndpointMap (US-region signed URLs would break). Removing the mount would revert the fix and re-expose hardcoded credentials in running code.
persistent-patches/socket.middleware.js
/app/dist/middleware/socket.middleware.js
Wraps Socket.IO onAuth’s verifyAuthToken in try/catch (#3966) so an expired/invalid JWT rejects cleanly via next(err) instead of throwing uncaught
YES. GitLab development src has the equivalent fix (commit 1fba09e5), but the deployed image’s baked dist/ still lacks it (verified #5992). Removing the mount reverts to the uncaught-throw / reconnect-storm behaviour.
persistent-patches/app.js
/app/dist/app.js
Removes dead GUS-API test/debug code that ran on every startup (#3407 follow-up, v42-prod-gus-wsdl-crash-loop.md)
YES
persistent-patches/postbookReport.helper.js
/app/dist/apps/postbook/postbookReport.helper.js
Postbook report fix
YES
ecosystem.config.js
/app/ecosystem.config.js
PM2 cluster config
YES
credentials.json
/app/credentials.json
Google Service Account creds — SOPS-managed (V42_GOOGLE_CREDENTIALS_JSON_B64, #3737), bind-mounted over the baked-in copy
YES
gus-api-regon-wsdl/
/app/dist/wsdl
REMOVED — never took effect (real require() resolves from node_modules/@pobidowski/gus-api-regon/dist/wsdl/); dropped alongside the app.js GUS-code disable
— (removed)
Why the patches can’t be retired yet (#5992). The de-hardcode / try-catch fixes ARE merged into
p24-back-tsdevelopment, but the deployed v42-prod:latest ECR image’s compiled dist/ does not
reflect them — its baked dist/globalHelpers/uploadAwsS3.helper.js still contains hardcoded Wasabi
credentials and its socket.middleware.js still lacks the try/catch. Retiring either mount is blocked
until an image genuinely built from current development is deployed and its baked dist/ verified
fix-complete. Tracked as a follow-up (image-build / at-rest-credential remediation).
3.x mailgun-v42-prod (email relay proxy)
Property
Value
Container
mailgun-v42-prod (compose dir /root/mailgun-prod/, image mailgun-v42-prod:latest, p24-ms-mailgun repo)
Endpoint
mailgun-api.w4.pinbox24.com
Persistent patch (volume mount) — git-tracked as of #5992 (2026-08-09):
Mount source (bms-1)
Container path
Purpose
Git source / deploy
/root/mailgun-prod/patches/integration.helper.js
/app/helper/integration.helper.js
”PATCH v3” — uploads mail attachments via s3-v2 first and unwraps the { success, result } envelope before creating the register record
infra-src/pinbox24/w4/mailgun-patches/integration.helper.js, shipped by secrets-sync.yml (sync-pinbox24-backends → “Deploy mailgun-v42-prod persistent patch to bms-1”). Before #5992 this file lived only on the server with no git source and no deploy step.
Note: If bms-1 is restarted and redis-v42 starts after v42-prod, the RabbitMQ consumer will fail to connect to Redis. Both must start before processing begins. Ensure restart policy is set on both.
nginx-proxy (HTTP entry point), 24+ total containers
W4-exclusive infrastructure on bms-1:
Resource
Detail
redis-v42
redis:7-alpine — local Redis for W4 only; replaces unstable OVH Redis
wkhtml-v42-prod
wkhtmltopdf container for PDF generation
mailgun-prod
Mailgun relay proxy
v42-notify-prod
Push notification microservice
5. Legacy Environments on bms-1
Beyond W3/W4 production, bms-1 runs additional environments from an old private registry (private-registry.dev.pinbox24.com):
Container
Age
Purpose
v32-prod-socket
5 years
W3 socket/realtime testing env
s3-v32-prod-socket
5 years
File service for socket env
cron-v32-prod-socket
5 years
Cron for socket env
v32-prod-reso
5 years
W3 RESO protocol env
s3-v32-prod-reso
5 years
File service for reso env
cron-v32-prod-reso
5 years
Cron for reso env
s3-v32-prod-renamed
4 years
Unknown
cron-v32-prod
4 years
Additional cron instance
v32-prod-socket (v5)
5 years
Second socket env
Status: Not audited for credential exposure. All likely have hardcoded credentials from the old private registry era (pre-SOPS, pre-ECR). See pinbox24-w3-w4-security-policy.md.
6. Vercel Feasibility Assessment
W3 — NOT feasible
Blocker
Severity
PM2 cluster mode
Critical
Persistent patches (4 files, hide code bugs)
Critical
No serverless MongoDB connection
High
File uploads (size + timeout limits)
High
Verdict: Would require full rewrite of upload flow + fixing all patched bugs in source. Estimated 4-8 weeks.
W4 — NOT feasible
Blocker
Severity
Socket.IO (WebSocket + polling)
Critical — Vercel Serverless has no persistent connections
RabbitMQ consumer (persistent AMQP)
Critical — can’t run a persistent consumer
Redis — local container (redis-v42)
Critical — replaced OVH Redis for stability; Vercel migration would require external Redis provider (Upstash/Redis Cloud) + connection changes
Dynamic cron jobs from MongoDB
Critical — in-memory CronJob instances require persistent process
PM2 cluster (pm_id guards)
Critical
7 additional W4 microservices on bms-1
Critical — wkhtml, mailgun-prod, s3-v2, git-deploy, pdf-gen, v42-notify all need separate hosting
GOOGLE_APPLICATION_CREDENTIALS as file path
High — needs refactor to env var
Persistent patches (WSDL + Wasabi fix)
High
Jabber/XMPP persistent connection
High
Verdict: W4 has MORE blockers than W3. Socket.IO + RabbitMQ + Redis (now intentionally local for stability) + dynamic crons + 7 co-located microservices are fundamental architecture choices. Moving Redis from local to an external provider would be a regression in stability. Estimated 8-12 weeks of architectural refactoring to make serverless-compatible.
Summary
W3 → bms-1 (Docker) — Vercel migration: not feasible (4-8 weeks rewrite)
W4 → bms-1 (Docker) — Vercel migration: not feasible (8-12 weeks rewrite)
Both stay on bms-1. CI/CD via extended secrets-sync.yml.
7. Security Status
Item
W3
W4
MongoDB app user (not admin)
✅ w3_app (2026-07-06)
needs audit
Persistent patches in repo
❌ only on disk
❌ only on disk
docker-deploy-prod.sh with hardcoded creds
❌ issue #3063
❌ .bak exists too
PM2 logs MongoDB URI
❌ issue #3066
❌ likely same pattern
Restart policy in docker-compose.yml
❌ needs PR
❌ needs PR
CI/CD auto-deploy on credential rotation
❌ in progress
❌ in progress
8. Env Keys by Service
W3 — secrets/pinbox24-w3.env.sops
SOPS key
Container
Env var
V32_MONGODB_URL
v32-prod
MONGODB_URL
V32_PMONGODB_URL
v32-prod
PMONGODB_URL
V32_PINBOX_PROD_DB
v32-prod
PINBOX_PROD_DB — env.config.jsproduction-block fallback for the mongojs path (/api/i18n/langs); shares the w3_app@w3_db credential and must stay in sync with V32_MONGODB_URL. See W3 connection handling & rotation.
V32_DB_URI
s3-v32-prod
DB_URI
V32_s3ApiUrl
v32-prod
s3ApiUrl
V32_s3Bucket_endpoint
both
s3Bucket_endpoint
V32_s3Bucket_BUCKET_NAME
both
s3Bucket_BUCKET_NAME
V32_s3Bucket_api_accessKeyId
both
s3Bucket_api_accessKeyId
V32_s3Bucket_api_secretAccessKey
both
s3Bucket_api_secretAccessKey
W4 — secrets/pinbox24-w4.env.sops
Keys that should be in SOPS (currently in backend-environment.env directly on bms-1):
Env var
Container
Sensitivity
NEW_MONGODB_URI
v42-prod
Critical
v3MongoUrl
v42-prod
Critical
RABBIT_MQ_URL
v42-prod
Critical
REDIS_HOST
v42-prod
Medium (points to redis-v42 container on test-net)
W3/W4: PM2 logs full MongoDB URI — needs source fix in v32-prod and v42-prod
High
#3564
W3: sops-reset-mongodb.ps1 W3 group omits V32_PINBOX_PROD_DB → each rotation re-breaks /api/i18n/langs; add it to $uriKeyDefs (secret-manager scope). See connection handling & rotation
High
—
W4: CI/CD (secrets-sync → force-recreate) not implemented
High
—
W4: All credentials in env file, not in SOPS
High
—
W4: No restart: unless-stopped in docker-compose.yml
Medium
—
W4: redis-v42 restart order — must start before v42-prod on server reboot