For Agents

Living index of themes for the FaceKom KYC platform (vuer_oss / vuer_css / vuer_cv). Each H2 is a topic; bullets are wikilinks to related notes. Updated by obsidian-documenter when documenting work. Read by historian at bootstrap. Topics kept alphabetical.

Build / probe-build workflow (UBI10)

  • FKITDEV-8252 — podman + libkrun on macOS Apple Silicon for emulated linux/amd64 builds; needs 8 GiB RAM minimum (4 GiB OOMs on gcc-c++ family installs), 6 CPUs sufficient; iteration counts as complexity proxy (portal_css 3, vuer_css 3, vuer_oss 5, janus 7, vuer_cv 7); subagent Bash allowlist is more restrictive than main-session shell — plan Phase B with this in mind

CI / build gates

  • depcheck-false-positive-minified-bundledepcheck can report a CI-only false positive because it fails OPEN on unparseable files. vuer_css CI flagged @emotion/is-prop-valid as unused while the identical pinned depcheck@1.4.7 + lockfile was clean locally and in a Linux container. The only reference is a literal require("@emotion/is-prop-valid") in a try/catch at web/sdk/web-sdk.js:205, and web/sdk is not in ignore-patterns — CI’s depcheck evidently can’t parse the 865 KB minified vendor bundle (OOM/timeout on the self-hosted runner) and then treats the file as containing no requires. Do NOT remove the dependency — it flips depcheck to reporting it missing. Fix = add to ignores in .depcheckrc.json. Generalized triage rule: a depcheck diff between CI and local with identical version+lockfile points at a parse failure on a big minified/vendored file, not a real dependency change. First hit on FKITDEV-8387; job introduced by FKITDEV-8239
  • FKITDEV-8239SonarCloud “Security Rating on New Code” gate fix (2026-06-23): after the depcheck PRs opened, the gate FAILED on 4/5 PRs because the new workflow lines tripped SonarCloud’s GHA supply-chain rules — npx (on-demand install; confirmed sole driver on vuer_css), yarn install (lifecycle scripts), unpinned actions/*@v6 (use full commit SHA); the existing jobs use the same patterns but are grandfathered as old code, only the PR’s new lines are gated. Profiles differ per repo (vuer_css=npx only; portal_css=all three). Fix (3 options considered): appended .github/** to sonar.exclusions in each sonar-project.properties (already present in sonar.coverage.exclusions); pushed solo-author andras.lederer (vuer_oss c2b5cfcb3f, vuer_css 93c9d976e, portal_css 7ee62cbd, esign_oss 4e96053, esign_css 9f9b862). gh pr checks: initially 4/5 green (vuer_css #3076, portal_css #703, esign_oss #353, esign_css #253); vuer_oss #8001 was red but NOT sonar/NOT this change — pre-existing self-service-room-archive Unit Tests failure (2 tests, async-leak; 3512 pass/2 fail) that also failed on devel, sonar/build skipped behind the test job. RESOLVED 2026-06-23: colleague merged the test fix to vuer_oss devel in PR #8003 (commit cfdc116543); merged origin/devel into the depcheck branch (clean, no conflicts — devel only touched CODEOWNERS + the test file; merge commit 3717e30b91 solo-author) and #8001 re-ran fully green. All 5 FKITDEV-8239 PRs now green and ready to merge (#8001/#3076/#703/#353/#253). Reusable gotcha → SonarCloud “Security Rating on New Code” can fail on new CI workflow lines
  • FKITDEV-8239adversarial deep-review verdict (2026-06-23): NO bugs, ship as-is. actionlint v1.7.12 clean (exit 0) on all 5 workflows (full Actions schema + expression validation); all 5 diffs purely additive vs origin/devel (31 insertions/0 deletions); ${{ env.NODE_VERSION }}=“24” resolves in all 5; bare npx -y depcheck@1.4.7 auto-discovers .depcheckrc.json; the 5 job blocks byte-identical except the intended install spelling (yarn --frozen-lockfile vuer_oss vs yarn install --frozen-lockfile ×4); depcheck warn-only (exit 255 absorbed by continue-on-error), unused_devDeps=[]; extra finding — portal_css has a genuine missing devDependency istanbul-lib-coverage. Merge-time op rule: do NOT add the Unused Dependencies status check to branch-protection required checks or it stops being warn-only
  • FKITDEV-8239warn-only depcheck CI job across all 5 repos (vuer_oss/vuer_css/portal_css/esign_oss/esign_css); continue-on-error: true, not in any needs: graph → never blocks a PR; tool pinned npx -y depcheck@1.4.7 (correct on both CI and macOS npm v10); .depcheckrc.json ignores build/lint/test tooling + dynamically-loaded runtime deps (pg/pg-hstore via Sequelize dialect, postcss via build pipeline) + vendored asset paths; Yarn Constraints NOT implemented (Yarn Classic v1 — Berry-only feature); candidates surfaced: vuer_oss soap/umzug, vuer_css add, portal_css lodash/tmp/tough-cookie, esign_oss ajv/fast-xml-parser/inquirer/jsdom/protobufjs/umzug, esign_css license-checker/postcss; portal_css over-suppression bug found+fixed (those 3 were genuinely unused — adding to ignores hid the signal the ticket exists to surface); all LOCAL/uncommitted on chore/FKITDEV-8239-depcheck-ci
  • FKITDEV-8887reading SonarCloud PR issues without a Sonar token (reusable, vuer_css projectKey vuer-css, org techteamer): SonarCloud posts every issue as a GitHub check-run annotation on the PR head commit (gh pr view <n> --json statusCheckRollup,headRefOid → find “SonarCloud Code Analysis” + head SHA → gh api repos/o/r/commits/<sha>/check-runs for the run id → gh api repos/o/r/check-runs/<id>/annotations); sonarqubecloud bot also leaves a PR summary comment. Gate gotchas: a passing Quality Gate ≠ zero issues (gate checks only new-code threshold metrics — coverage/duplication/rating — so it’s GREEN with many code-smell “New issues”); no analyzed devel baseline (only pull-request.yaml runs Sonar) → Sonar attributes pre-existing smells in a touched file to the PR, confirm authorship with gh pr diff <n>; annotation_level failure = issue severity, not a gate failure. Full recipe in 10. Verified gotchas
  • SonarCloud “Security Rating on New Code” can fail on new CI workflow linesadding NEW lines to a SonarCloud-scanned GitHub Actions workflow can fail the “Security Rating on New Code” gate via GHA supply-chain rules (npx on-demand install, yarn install/npm install lifecycle scripts, unpinned actions/*@vN SHAs) — even when the rest of the CI already uses those same patterns (grandfathered as old code; only the PR’s new lines are gated). Profiles differ per repo. Resolutions: (a) exclude .github/** via sonar.exclusions (TechTeamer repos already exclude it from sonar.coverage.exclusions); (b) run CLI tools via a pinned devDependency instead of npx + pin actions to full commit SHAs. The issue/rule REST APIs need auth for these private projects, but the per-PR findings are readable via GitHub check-run annotations (gh api repos/<repo>/check-runs/<id>/annotations — full recipe in FKITDEV-8887). First hit on FKITDEV-8239
  • ci-github-branch-audit-chronically-red — the “Github CI - Branch” workflow (.github/workflows/audit.yaml:33 in vuer_oss) is chronically RED on customization branches and is NOT a regression: improved-yarn-audit --min-severity critical --exclude <GHSAs> exits 4 on any critical advisory in a transitive dep not on the --exclude allowlist (as of 2026-06-04: twig>locutus, @techteamer/timestamp>…>basic-ftp, @kafkajs/confluent-schema-registry>protobufjs, request>form-data). Base branch customization/raiffeisen has failed it on every push since ≥April 2026; team merges through it and clears it by appending triaged GHSAs to --exclude (security acceptance) or remediating. Triage rule: commit didn’t touch package.json/yarn.lock + base already red ⇒ not your change. The real per-change gates are lint (yarn lint, --max-warnings 0, ignores customization/test/*) and unit tests (yarn jest <file>)
  • customization-branch-ci-pipeline-inheritancesystemic, will recur: legacy partner branches ran a single CI job (lint-and-build, old .github/workflows/pull-request.yaml blob ec0a1244); devel’s current workflow (blob dda79403) runs lint / test / audit / depcheck / sonar / build. So the first devel→customization merge makes four jobs run on that branch for the very first time, surfacing years of latent breakage in one PR. On cofidis (FKITDEV-9059): 5 failure clusters, only 2 merge-introduced, the rest dating 2017–2024. Two structural amplifiers: partners fork core source files in place (no override layer, e.g. server/service/FlowLiveUpdateService.js → forked file violates the core unit test), and there is no customization-aware unit-test layer (jest.config-unit.js matches only test/tests/unit/**, no per-partner test dir) so fixing a partner-specific test failure means diverging a shared core test file that then conflicts on every subsequent devel merge — a recurring tax, not a one-off
  • cve-2025-7783-form-data-via-requestAudit-job debugging trap: ERROR: Unable to parse yarn audit output: SyntaxError … and Node 24’s DEP0169 url.parse() DeprecationWarning are cosmetic red herringsimproved-yarn-audit merges child stdout+stderr into one NDJSON stream so the deprecation warning corrupts lines, and the tool silently skips unparseable ones. Identical errors appear on green devel runs (proof: vuer_oss PR #8062, job 87891787317, Found 0 vulnerabilities, conclusion success). The exit code comes solely from the genuine advisory count — don’t chase the parse error, find the real advisory
  • nusz-devel-update-2026-06-16-lint-merge-fix — concrete case of the lint gate catching a bad merge: yarn lint (eslint . --max-warnings 0 --ignore-pattern "test/*") failed the NÚSZ devel-update merge with 1 n/no-missing-require error (cron.js:46, extensionless require of a module devel had renamed .js.ts); merge correctly held back uncommitted until fixed
  • FKITDEV-8981move PR checks off ubuntu-latest → self-hosted [self-hosted, node] across 7 repos’ single PR-check workflow .github/workflows/pull-request.yaml: 33 identical runs-on edits (vuer_oss/vuer_css/esign_oss/portal_css/mq 5 each, esign_css/janus-api 4 — they omit the test job; jobs ∈ {lint,test,audit,sonar,build}). Repo resolution: @techteamer/mqTechTeamer/mq default master; janus_apiTechTeamer/janus-api (hyphen) master (TechTeamer/janus_api does not exist); css/oss base origin/devel, mq+janus-api origin/master. Scope: portal_css pr-title-lint.yaml already removed on devel (PR FKITDEV-8976) and push-triggered release-caller.yaml (reusable node-semantic-release.yaml@master, no runs-on) is out of scope ⇒ only pull-request.yaml — re-scope against post-fetch devel. Job NAMES unchanged ⇒ branch-protection required-status-checks stay valid. Worktrees <repo>-FKITDEV-8981 on chore/FKITDEV-8981-self-hosted-runners; verified (numstat 5/5/5/4/5/5/4, zero ubuntu-latest residue, YAML parses) but NOT committed/pushed, NO PRs. Hard dependency/risk: inert + dangerous without online node-labelled (+ implicit self-hosted) runners carrying git + Node/yarn (setup-node@v6 cache: yarn) + SonarSource/sonarqube-scan-action@v6 (sonar = likeliest self-hosted gotcha); if none online at merge, every PR check queues forever and ALL PRs in these repos block. “Build-green ≠ runs” — true validation needs a live PR hitting a node runner. Precedent: vuer-release autobuild.yml already on [self-hosted, docker]. Commit-msg style chore: [fkitdev-8981] run PR checks on self-hosted runners
  • FKITDEV-8533SonarCloud “Maintainability Rating on New Code” gate FAILED on vuer_oss PR #8013 (the Janus CVO un-gate fix, branch fix/FKITDEV-8533-videoorient-ungate; rated C, then D after a refactor) — and it is pre-existing-debt mis-attribution, NOT the fix (2026-06-29). All 20 flagged issues are pre-existing (git blame 2018→Jan 2026; authors Jordán/Bence/jurki/kzsolt/Makkai; SonarCloud issue keys e.g. AZ8A1W4d…/AZ8A1W6o… identical before & after a PR refactor); decisive control = the co-modified server/db/model/customer.js carries zero flags, proving the diff is innocent — the gate counts legacy smells in any touched file, most likely because devel has no SonarCloud baseline analysis (project vuer-oss is private; New Code config unconfirmable without a token). Gotcha: any PR touching videochat.js/RoomTransportSession.js/SelfServiceTransportSession.js/VuerCVListenerSession.js (legacy optional-chain/.find/async smells) re-trips this → waive (mark issues Accept / admin-merge) or fix the baseline (Project Settings → New Code → Reference branch = devel, ensure devel is analyzed); do NOT bloat a targeted PR by “fixing” the unrelated debt — esp. the 2 [failure]-severity VuerCVListenerSession.js items (async-in-constructor + await-non-Promise, behavioural CV refactors). Decision (user, 2026-06-29): waive as pre-existing debt. Fix final state: helper server/transport/videoOrientExt.js refactored into Customer.prototype.videoOrientExtEnabled() called X.customer?.videoOrientExtEnabled() ?? true at the 4 sites; commit 1815f693fe (amended over d27d4cc990), solo-author, force-with-lease pushed; device test still pending
  • mjml-v5-esm-breaks-commonjs-email-templates“green CI, broken runtime”: unit tests never boot EmailService, so the MJML-v5 ESM regression on FKITDEV-9059 cofidis (ReferenceError: require is not defined at EmailService.init; the letter type never registers so its email never sends) passed all CI and only failed when the service actually started on fk-dev. Same class as FKITDEV-8981’s “build-green ≠ runs” and the FKITDEV-9059 innerHTML / web/-404 bugs; detection is runtime-only (deploy + restart, watch letter-registration errors: 3/boot → 0 after the fix)

Container health / images (dev-box)

  • dev-box-esign-container-startup-failures-2026-06-01esign_css/esign_oss came up unhealthy because nginx (non-root techteamer uid 1000) couldn’t write its PID: baked nginx.conf line 6 pid /run/nginx.pid; but /run is root:root[emerg] open("/run/nginx.pid") failed (13: Permission denied) → nginx FATAL → unhealthy (app/redis/cron all RUNNING; image regression, not the InstaCash update); images esign_{css,oss}:2024.4.1-20240614 were rebuilt ~2025-12-08 w/ nginx 1.28 (tag date misleading); ephemeral fix sed PID → /tmp/nginx.pid + supervisorctl restart nginx (lost on recreate, /etc/nginx not bind-mounted) → durable fix = bake the PID path into the images. Healthcheck /usr/local/bin/supervisor-health-check.sh: unhealthy if any supervisord prog ≠ RUNNING or uptime 0:00:[0-5][0-9] (< 60s anti-flap) → ANY supervisorctl restart = ~60s unhealthy then auto-recovers (interval 60s, retries 3, start-period 60s)

Container migration / UBI10

  • FKITDEV-8252 — fleet-wide UBI8/UBI9 → UBI10 migration ahead of RHEL 9 EOL; Phase A.6.1 DONE (all 5 base images probe-build green; 2 new commits f38c8e2 + b984006; branch 17 ahead of origin/main, not pushed); Phase A.6.2 (remaining 3 base/* likely under common/*), Phase B (vuer-release 62 Dockerfiles), Phase C (vuer_docker PR #203) still open; vuer_cv now in-scope (5.93 GB UBI10 base added)
  • FKITDEV-8252RUNTIME fixes (build-green ≠ runs): four ubi10-minimal startup gotchas masking each other (supervisor 4.2.5 pkg_resources on Py3.12 → pin 4.3.0; supervisord logfile hidden by /var/log bind-mount → log to root; rabbitmq needs /bin/sumicrodnf install util-linux; erlang .erlang.cookie eacces — supervisord drops HOME → environment=HOME="/var/lib/rabbitmq"); plus removed wrong USER $DOCKER_USER from vuer_css/portal_css (must run supervisord as ROOT); all 3 rabbitmq images boot healthy; pushed solo-author across vuer_docker/vuer_build/vuer-release

Cron jobs / data retention

  • fk-dev-nusz-deploy-and-8959-verificationFKITDEV-8959 TC-8959-02 verified PASS on fk-dev (2026-07-03): the NÚSZ image-deletion cron RemoveAttachmentDataCronJob (thin wrapper over CustomRemoveOldDataCronService.removeAttachmentData()) → getOldImageAttachments (type LIKE 'image/%' AND isArchived=false AND createdAt<cutoff, batched, excludes the file blob) → removeOldAttachments key-guard (const encryption = encryptionId ? getEncryption() : null; if (encryption?.key) encryptBuffer(empty,{key}) else { file=Buffer.from(''); encryptionId=null; skippedNoKey++ }; isArchived=true; save). Proven the key-offline path: BEFORE {isArchived:false,encryptionId:3,file_bytes:9}{processed:1,archived:1,skippedNoKey:1,errored:0} → AFTER {isArchived:true,encryptionId:null,file_bytes:0} (blanked + archived instead of the old The key options property is required… throw). Retention still OPEN: fk-dev expiryDays=7 (dev.json) / 28 (docker.json) vs ASSNUSZ-117’s 7 — confirm with NÚSZ (one-line config)
  • FKITDEV-8959 — RCA of why NÚSZ image deletion never ran: removeAttachmentData() was gated behind a hanging removeVideoData() step in a strictly-sequential cron (ran only ~17/49 nights), and the old getWhere selected a 1-day band (createdAt ∈ [now-8d, now-7d)) with no catch-up so a skipped night was permanent. Fix = own RemoveAttachmentDataCronJob (decoupled) + self-healing createdAt < cutoff image-scoped query + the key-guard above; verified on fk-dev per the note above

Crypto policy / GPG SHA1

  • FKITDEV-8252decision revised: original per-key rpmkeys --import --allow-sha1-signatures plan did not survive UBI10 reality (flag disappears after microdnf -y update strips it from rpm-libs; DEFAULT:SHA1 sub-policy doesn’t exist — no SHA1.pmod ships); now using update-crypto-policies --set LEGACY in all 7 SHA1-key-importing build stages across portal_css, vuer_css, vuer_oss, janus (×2), vuer_cv; order matters: install crypto-policies-scripts from UBI10 BaseOS BEFORE COPY-ing the CentOS Stream 10 repo

CSP / log noise

  • ASSICASH-71 — InstaCash CSS log noise: WebServer.js setupCSPReportViolation() writes every report unthrottled; amplifies any hosts.portal / portal.url config drift

Customization branches

  • ASSICASH-71customization/instacash (Express 4, HEAD b0a4a37a, deployed) vs devel (Express 5, PR 689 fixes); next core sync needs to carry route-array fix
  • FKITDEV-8787customization/raiffeisen overrides on SelfServiceRoomService.js and SelfServiceV2Service.js; PRDEBUG instrumentation gated by raiffeisen.debug.phantomRoomLog
  • FKITDEV-8533customization/generali-atvilagitas is the base branch for the Generali videoOrientExt tablet fix (PR #7893)
  • FKITDEV-8788customization/raiffeisen ocr.engine selection (warp-first VuerCVOCRRecognition vs no-warp VuerCVMRZDetector) + recognition recipe customization/cv/instruction.index are the suspected override surface for the HU-eID-back MRZ crop bug
  • instacash-update-2026-05-27-status — Periodic devel→instacash sync: branch name update/customization/instacash-2026-05-27 across all three repos (esign_css/vuer_oss/vuer_css); date-only convention; per-repo conflict topology captured
  • esign-css-instacash-orphan-history — esign_css customization/instacash is a single squashed orphan commit with no merge base; structurally distinct from conventional long-running customization branches
  • ci-github-branch-audit-chronically-red — every customization branch inherits a chronically RED “Github CI - Branch” audit gate (improved-yarn-audit exit 4 on un-excluded critical advisories); customization/raiffeisen has been red on it since ≥April 2026 — not a per-branch regression
  • customization-branch-ci-pipeline-inheritance — partner branches fork core source files in place (no override layer) and the repos have no customization-aware unit-test layer, so a partner-specific test failure can only be fixed by diverging a shared core test file — which then conflicts on every subsequent devel merge. Both amplifiers surface at once on a branch’s first devel-merge, when devel’s 6-job pipeline replaces the legacy single lint-and-build job
  • cve-2025-7783-form-data-via-requestCVE-2025-7783 / GHSA-fjxv-7rqg-78g4, critical form-data@2.3.3 (unsafe random multipart boundary, patched >=2.5.4) via EOL request@2.88.2 which hard-pins form-data: ~2.3.2. Absent from devel (its Audit job is green) — present only on the customization line, because request is live partner code: vuer_oss customization/api/sms/SmsCofidis.js, vuer_css customization/server/web/api/{login,register,partner-register}.endpoint.js. Confirmed red on customization/cofidis (#3100/#8040), customization/kh (#3098), customization/raiffeisen (#8055) ⇒ blocks every partner branch adopting the new pipeline. Fix matching house style (repos already pin csurf/cookie, twig/minimatch, ts-jest/handlebars): add "request/form-data": "^2.5.6" to resolutions in package.json + yarn install. Long-term correct fix = drop EOL request (4–5 call sites) = separate ticket
  • FKITDEV-8947customization/unicredit: migrate UniCreditApiService off request-promise-native → fetch; the service does mTLS (cert/key/ca/passphrase from portal.api), so the migration must use undici.fetch+Agent (vuer-oss-global-fetch-ignores-agent-mtls) — Node’s global fetch ignores agent:. Working tree also has a stray }w at ApiService.js:267
  • mjml-v5-esm-breaks-commonjs-email-templates — cofidis forks its own email/letter templates (customization/email/*/*.letter.data.js); the FKITDEV-8727 MJML v4→v5 (ESM-only) upgrade merged via FKITDEV-9059 broke the ones that mix a top-level import with require() (require is not defined at EmailService.init). Per-partner blast radius — every partner forks its own letter files, so the same upgrade can break each on its next devel-merge. Fix 52a0843a1e (require→import in all 6, only e-mail-invite had actually crashed) is unpushed on chore/FKITDEV-9059-cofidis-update-2026-07-13-fixes

Customer data encryption

  • sms-verification-code-dev-testingcustomer.data is an encrypted-at-rest TEXT column (serviceContainer.service.cryptos.data = DataCryptoService, keyed per-row by customer.key), but the Sequelize model’s data get accessor auto-decrypts on read (customer.js:23-51, _getDecrypted :316-318, isEncrypted() = !!this.key) — so reading any portal-data field via the model (e.g. getVerificationCode()videochatToken) returns plaintext, no manual crypto; by contrast smslogs.messageBody/phoneNo are separately encrypted and NOT plaintext-readable
  • fk-dev-nusz-deploy-and-8959-verificationthe encryption.key resolution chain (needed to exercise crypto-dependent code standalone): encryption.key is a Sequelize getter (server/db/model/encryption.js) → serviceContainer.service.cryptos.data.getActualKey(key, customerId) (DataCryptoService) → for a null/absent key it calls serviceContainer.service.customerKeyStorage.getKey(customerId). A standalone harness must therefore init cryptos.{media,data,attachment} + CryptoService + customerKeyStorage; stubbing customerKeyStorage.getKey() => null faithfully models “customer key offline / inaccessible” — the real trigger for the FKITDEV-8959 image-deletion bug. Proven by TC-8959-02: a null-key image is blanked + archived + encryptionId=null (not thrown)

Dev / testing workflow

  • dev-build-hostwhere to build/test: the fk-dev Tailscale VM (command ssh ops@fk-dev.taild4189d.ts.net). The old ssh Facekom box is decommissioned (offline since ~2026-06-27) — every older note saying “build/test on ssh Facekom” now means fk-dev. Still true: native builds on the remote host, never emulated on the Mac; use command ssh (the kaku alias shadows plain ssh non-interactively)
  • instacash-external-api-esign-headless-test-2026-06-01 — how to exercise the InstaCash external API headlessly with bin/instacash-cli.js from the vuer_oss container: SSH via command ssh to the dev host (now fk-dev, dev-build-host); start-server (detached) mocks the bank /auth+/status on 8189; post-application [rt|nrt] [mkb_szemelyi_kolcson|mkb_mszh|mbh_mfl] returns {customerId, customerProfileUrl, inviteUrl}; post-contract <id> [pdf] drives the ic-contract flow → EsignRPC → esign. Caveat: every cmd except start-server boots the full vuer_oss service in-process (needs healthy stack + instacash.external.apiKey Bearer + allowSelfSignedCerts); and the eSign signature itself can’t be automated (interactive video-ID + auth + sign at the inviteUrl)
  • dev-box-esign-container-startup-failures-2026-06-01 — debugging the esign_css/esign_oss unhealthy containers on the dev box (observed on the old lederera box, now decommissioned — same triage applies on fk-dev, dev-build-host): how to triage (docker exec <c> supervisorctl status → nginx FATAL while app/redis/cron RUNNING = the PID-permission bug); the ~60s-unhealthy-after-any-restart healthcheck anti-flap (don’t chase it); post-dep-major-bump lesson — re-yarn install the running container (/workspace/<svc>/node_modules is host-bind-mounted, a baked image install goes stale → RedisStore is not a constructor etc.); command ssh Facekom to reach the box from Claude’s shell (kaku shadows plain ssh), login shell (bash -l) so docker is on PATH; chalk ^5 ESM-only broke yarn trans (bin/test/trans-check.js:6) → dynamic import('chalk')
  • dev-box-cv-photo-processing-failures — “error during photo processing” / “CV server is down” on the lederera dev box has two compounding causes: vuer_cv container stopped (docker start vuer_cv, ~2 min to healthy; nginx 502→404 on loopback curl) and hairpin NAT (vuer_oss host-net /etc/hosts maps *-lederera → own LAN IP 192.168.1.93; remap → 127.0.0.1); the hosts edit is wiped on every docker restart vuer_oss (Docker-regenerated bind mount) so re-apply after any restart, via truncate+write not sed -i
  • sms-verification-code-dev-testing — get/force the SMS (and email) verification code when the customer phone is fake: test.security.tempTokenSms (truthy → fixed code every send; conventional value 123456 in all test/testconfigs/*.json; tempTokenEmail: "mailToken" for email) is read by the customer:verification:sendSms hook (customization/listeners/sms-verification.js); dev box (lederera/NODE_ENV=dev) does NOT ship it — add to config/local.json + restart (node-config caches at startup) + resend (old random code won’t match); alt recovery = read customer.getVerificationCode() via model (auto-decrypts); matchTokens (ContactValidationService.js:16-20) = case-insensitive exact match
  • esign-css-customization-branches — eSign standard dev/test method: test through VÜER CSS with requestFakeCustomer = true and ?esign=1&token=…
  • instacash-esign-dev-box-deploy — testing an InstaCash eSign release on the dev box (now fk-dev — the ssh Facekom box it was written against is decommissioned, see dev-build-host; code bind-mounted from /workspace): the box defaults to Raiffeisen so you must align the whole partner chain to InstaCash (esign_oss/css → tag instacash-1.3.0.11, vuer_oss/css → tag instacash-1.9.11.50 since the eSign ticket pins no vuer version, pdfservice stays main/2.0.12 partner-agnostic). Per repo: git stash WIP → git fetch --tags (clones predate the tag) → git checkout <tag> → rebuild in-container docker exec <c> sh -c 'cd /workspace/<repo> && yarn install && yarn build'supervisorctl restart all. Verify supervisord RUNNING + RabbitMQ connection established + Web server is listening + esign_css :10183 HTTP 200. Gotchas: a “dirty” vuer_css = untracked .claude/ dir; old log ERRORs may be historical from the prior run (check timestamps)
  • fk-dev-nusz-deploy-and-8959-verificationdeploy a branch to the fk-dev GCP dev-mirror VM (tailnet taild4189d.ts.net; NOT the offline on-prem ssh Facekom box) by bind-mount swap, no image rebuild: command ssh ops@fk-dev.taild4189d.ts.net (Tailscale SSH, no keypair; kaku shadows sshcommand ssh/command scp); the box has NO GitHub key so ssh-add ~/.ssh/id_ed25519 + command ssh -A to forward yours; then on /workspace/vuer_oss: git fetch origin <branch> + checkoutdocker exec vuer_oss sh -c 'cd /workspace/vuer_oss && yarn install && yarn build'docker exec vuer_oss supervisorctl restart all; verify supervisorctl RUNNING + Web server is listening on 10081 + operator UI (https://oss-fk-dev.taild4189d.ts.net) HTTP 302. postgresql peer-auth blocks psql -U postgres (use app Sequelize); nginx_proxy crash-loops but sidecars bypass it; restore the box’s original bd8923d69f (InstaCash) when NÚSZ testing done. Also documents a reusable standalone cron test-harness pattern (Node script in bin/process-settings bootstrap + logger Proxy + service/crypto stubs + sequelize authenticate + raw-SQL seed → call the REAL service methods → SELECT before/after; deliver via command scp+docker cp+docker exec+rm)
  • mailtrap-sandbox-inbox-dev-email — FaceKom dev email is not broken: config/dev.json email.transport.SMTP bakes a Mailtrap Sandbox inbox (host smtp.mailtrap.io, port 2525, user 643414e4c00185), so registration/verification mail is delivered into the original-dev/shared inbox you can’t see (symptom reads as “emails don’t send to Mailtrap”). Route to your inbox by overriding hostsandbox.smtp.mailtrap.io + auth.{user,pass} in the bind-mounted vuer_oss-local.json getconfig local layer (config/docker.json is never loaded under NODE_ENV=dev; Sandbox creds don’t auth the legacy smtp.mailtrap.io). Distinguish Sandbox (sandbox.smtp.mailtrap.io, per-inbox user/pass ~14 hex, catches mail) from Email Sending / live (live.smtp.mailtrap.io, api + 32-char token, delivers for real — wrong for testing). Verify with nodemailer.verify() first (require nodemailer by absolute path /workspace/vuer_oss/node_modules/nodemailer). Sibling to sms-verification-code-dev-testing (invisible-delivery-channel dev testing)

Devel update sync workflow

  • instacash-update-2026-05-27-status — Branch naming convention: update/customization/instacash-<date> (date-only, no ticket prefix), applied identically across all three repos (esign_css, vuer_oss, vuer_css); per-repo conflict surfaces vary significantly (esign_css blocked structurally, vuer_oss self-service-v2 listener high-risk, vuer_css modal a11y trio + customizations.js routes high-risk); using a separate worktree to keep parallel feature WIP branches untouched is the pattern (e.g. ~/coding/facekom/vuer_css-instacash-update to protect bugfix/FKITDEV-8787)
  • esign-css-instacash-orphan-history — When the target branch is structurally orphan, the standard git merge devel halts; git rev-list --count A..B is meaningless without a merge base — three viable workflow options to choose between before resuming
  • FKITDEV-8817 — Parallel-strategy sequencing: don’t block the sync on an unmerged adjacent PR; let the second devel→update-branch merge pull it in once the PR lands on devel
  • nusz-devel-update-2026-06-16-lint-merge-fix — NÚSZ update/customization/nusz-2026-06-16 merge of origin/devel failed validation at lint, left mid-merge (uncommitted). Reusable merge gotcha: devel renamed FFmpegService.js.ts; nusz tip had added an extensionless require('./server/service/FFmpegService') to cron.js — conflict-free merge kept both, so it no longer resolves under n/no-missing-require. cron.js:46 was the lone straggler (all other callers already on explicit .ts). Lesson: after a cross-side .js.ts rename merge, grep for extensionless require()s of the renamed modules
  • customization-branch-ci-pipeline-inheritancebudget for the CI pipeline expansion on a partner’s first devel-merge: 1 job (lint-and-build) → 6 (lint/test/audit/depcheck/sonar/build), i.e. 4 jobs run on the branch for the first time ever and most red is pre-existing partner breakage newly enforced, not merge-introduced. Triage every failure by origin (git blame/git log the offending line) before choosing a fix side (partner file vs shared core test). Characterised on FKITDEV-9059 (Cofidis, 2026-07-20)
  • FKITDEV-9059 — Cofidis devel update (vuer_css PR #3100 @ 4dd8a927a, 105 files; vuer_oss PR #8040 @ ad8a318a22, 586 files), both mergeable_state: blocked; full 8-row failure inventory with root cause / origin / fix-side per failure
  • mjml-v5-esm-breaks-commonjs-email-templatesan ESM-only major upgrade of a shared loader, merged via devel → customization/*, silently breaks CommonJS customization files. The FKITDEV-9059 cofidis merge pulled in FKITDEV-8727 MJML v4→v5 (ESM-only, c9602a519e) → EmailService.js await import(...)s letter templates; Node 22 then parses any customization/email/*/*.letter.data.js that mixes a top-level import with require() as ESM → ReferenceError: require is not defined at EmailService.init. Scope trap: NOT “41 of 49 files contain require(” — only the 6 mixed files break, and 5 had a createRequire shim so only e-mail-invite crashed at boot. Reusable rule: after any ESM-loader migration, grep customization/ for mixed import+require. The ESM cousin of the nusz-devel-update-2026-06-16-lint-merge-fix .js.ts rename gotcha

Device detection

  • FKITDEV-8533 — server-side UA parsing cannot detect a modern iPad: iPadOS 13+ Safari sends a Macintosh desktop UA, ua-parser-js v1 returns device.type === undefined; customer.isTablet() (device.type === 'tablet') is a strict logical subset of customer.isMobile() ('mobile' OR 'tablet') so it adds no detection power; customer.userAgent is the only client signal the server has (no Sec-CH-UA hints); reliable detection = client-side navigator.maxTouchPoints > 1 && /Macintosh/.test(navigator.userAgent). Resolution avoided the detection problem entirely (2026-06-23): rather than detect the iPad, gate on the easy-and-reliable negative Customer.isNativeApp() (userAgent.startsWith('mobile/'), single prefix for iOS+Android native SDK) — browsers (incl. spoofing iPads) all fall on the enable side.

Face comparison

  • face-comparison-data-verdict-threshold-modelcanonical model note (FKITDEV-8827 design): faceComparisons rows key by EITHER roomId (videochat/operator) OR selfServiceRoomId (self-service-v2), no mutual-exclusivity constraint (models.js:298-309, model/faceComparison.js); euclideanDistance = cosine distance 0–2 (misnamed). PION = videochat NOT self-service — protos declare videochat, comparisons from videochat:close hook (faceRecognitionHooks.js:26-44) keyed by roomId, gated by config faceRecognition.comparisonPairs (FaceRecognitionService.js:7,20) → self-service-only query returns zero PION rows. Verdict DERIVED by getFaceComparisonResult (SelfServiceCheckerService.js:132-154): SUCCESS≤perfect / PROBABLE≤probable (the match tier collapses, default match:null) / FAILURE>probable, operators <=, defaults {perfect:0.5,match:null,probable:0.6}. Threshold sourcing differs by link type: self-service per-room selfService:v2:config:state (oldest [0], ASC) REPLACES → global Setting key faceComparison (persisted by SettingsService.init()); videochat/operator rows have NO per-room path and are NOT verdict-classified at runtime (room.endpoint.js:144 raw distance only). No createdAt index → date-range exports full-scan; report-bin pattern + latent bug in raiffeisen-selfservice-failed-reports.js:106 (prepareReportData abstract, masked by active:false cron); Postgres but MySQL-portable (LOWER() LIKE not ILIKE)
  • face-comparison-different-face-db-query — face-comparison results are persisted: faceComparisons table (server/db/model/faceComparison.js:18-37) stores status ∈ {created,failed,success} + euclideanDistance (FLOAT nullable, actually cosine distance 0–2 despite the name); euclideanDistance written unconditionally by FaceRecognitionService.createFaceComparisonModel() regardless of threshold; different_face is not stored — it’s the CHECK_FAILURE read-time verdict from SelfServiceCheckerService.getFaceComparisonResult() (:132-153) when distance exceeds all thresholds; thresholds resolve per-room (selfService:v2:config:state activity log) → global Setting key faceComparison → code default probable:0.6; 4 call sites — liveness-V2 (SelfServiceV2Service.js:1390) gated by task.options.recognitionOptions.compareFaceWith (base V2 proto doesn’t set it), portrait/ID-doc (server/flow/FlowService.js:2943), videochat-close hook, V1; faceComparisons has no step column — portrait vs liveness only via joined FaceRecognition.imageCategory; queryable with one read-only SQL, no release

Express 5 migration

  • ASSICASH-71 — PR #666 (closed unmerged) → PR #670 (merged) for _router → router and /password-recovery/:token?/:lang? array rewrite; PR #689 follow-up
  • instacash-update-2026-05-27-statusNo Express 5 risk in vuer_css side of this update wave (contrary to a prior assumption rooted in ASSICASH-71’s vuer_css customization/instacash Express-4-on-devel-Express-5 case); vuer_css server-side merged clean (routes.js, WebServer.js, package.json, yarn.lock)

eSign / esign_css

  • instacash-external-api-esign-headless-test-2026-06-01 — the InstaCash post-contract <customerId> [pdf] external-API call (via bin/instacash-cli.js) is how the eSign contract leg is exercised headlessly: POST /external/contract → creates the “IC - Szerződés ajánlat feltöltése” (ic-contract) flow → EsignRPCClient → esign service. But the signature itself is interactive (video-ID + mock /auth + SMS 123456 + sign in the eSign UI) — the CLI proves the EsignRPC plumbing only, it cannot complete a signature. Requires the esign containers to be healthy first (see the nginx-PID fix note)
  • dev-box-esign-container-startup-failures-2026-06-01esign_css + esign_oss dev-box containers (esign_{css,oss}:2024.4.1-20240614, rebuilt ~2025-12-08, nginx 1.28, run as non-root techteamer uid 1000) come up unhealthy because nginx can’t write pid /run/nginx.pid; (root-owned /run) — image regression, fix belongs in the esign images/Dockerfiles (/etc/nginx not bind-mounted); RedisStore is not a constructor in server/web/web-server.js:24 is a red herring (code is correct connect-redis v9; only an old/stale node_modules bites); chalk ^5 ESM broke bin/test/trans-check.js yarn trans
  • esign-css-customization-branches — Customization branch fleet (only customization/instacash active, all others archived); standard dev/test method (test through VÜER CSS with requestFakeCustomer = true and ?esign=1&token=…)
  • esign-css-instacash-orphan-historycustomization/instacash is a single squashed orphan commit (b7cee2f, 2025-11-20, release 1.3.0.10); zero shared history with devel; 95-path delta; previous releases likely built via squash-rebuild + force-push pattern (confirmation needed)
  • FKITDEV-8817 — esign_css jQuery 2.2.4 vulnerability (CVE-2020-11023 / CVE-2019-11358); fix on bugfix/FKITDEV-8817-jquery-update pushed (b021019); dead-code path (auth.layout.twig) — repoint to existing /libs/jquery/jquery-3.7.1.min.js; PR not yet opened
  • esign — Electronic Signature System overview
  • instacash-esign-1.3.0.11release composition for InstaCash eSign 1.3.0.11 (esign_oss + esign_css only; tag instacash-1.3.0.11, 2026-06-08; Harbor instacash-esign-{oss,css}:1.3.0.11-20260608); changelog = devel update + FKITDEV-8817 vuln fixes (jQuery CVE-2020-11023 / CVE-2019-11358 on esign_css PR #250 + HSTS/nginx/WAF hardening); ASSICASH-92 release, ASSICASH-93 TESZT / ASSICASH-96 PROD (approved 2026-06-26 from 1.3.0.8); no DB migration / no breaking change, rollback = redeploy 1.3.0.8
  • instacash-esign-dev-box-deploydev-box recipe to test an InstaCash eSign release (run it on fk-dev; the old ssh Facekom box is decommissioned — dev-build-host): the box defaults to Raiffeisen so align the WHOLE chain to InstaCash (esign_oss/css → instacash-1.3.0.11, vuer_oss/css → instacash-1.9.11.50, pdfservice stays main/2.0.12); per repo git stashfetch --tags → checkout tag → in-container yarn install && yarn buildsupervisorctl restart all; verify supervisord RUNNING + “RabbitMQ connection established” + “Web server is listening” + esign_css :10183 HTTP 200

GCP dev-box mirror / Tailscale

  • dev-build-hostCANONICAL host reference (2026-07-01): the on-prem box ssh Facekom (= HostName localhost + ProxyJump FKJumpBoxroot@lederera-447-fk-hardver) is DECOMMISSIONED — Tailscale shows it offline since ~2026-06-27 — and must never be used again. All native builds / tests / deploys now run on the fk-dev Tailscale VM (100.91.108.61, command ssh ops@fk-dev.taild4189d.ts.net, Tailscale SSH, no keypair). Unchanged: build native on the remote host, never emulated on the Mac (qemu SIGSEGV exit 139 / overlay-FS I/O exit 125 / repo-metalink 503s) — only the host moved. Agent gotcha: the user’s shell aliases ssh/scp to a _kaku_wrapped_ssh function that is NOT loaded in a non-interactive shell (_kaku_wrapped_ssh: command not found) → use command ssh / command scp. Other tailnet peers are per-service sidecars on fk-dev, not build hosts: oss-fk-dev (100.91.55.42), css-fk-dev, portal-fk-dev, esign-oss-/esign-css-/esign-api-fk-dev, css-sdk-demo-fk-dev
  • fk-dev-nusz-deploy-and-8959-verificationfk-dev is now OPERATIONAL (2026-07-03): the 8b per-service Tailscale-sidecar overlay is pushed + wired + running (closes the “push gated on user go” item) — sidecars oss-/css-/esign-*/portal-fk-dev up, vuer_oss operator UI at https://oss-fk-dev.taild4189d.ts.net (HTTP 302; Express :10081 inside), source bind-mounted /workspace/<repo> + supervisord per container. First real use = deploying the two NÚSZ fixes (FKITDEV-8747 + FKITDEV-8959 on customization/nusz tip d426cc6ae1) and verifying FKITDEV-8959 TC-8959-02. Operational gotchas: command ssh ops@fk-dev.taild4189d.ts.net (Tailscale SSH; kaku shadows ssh); box has no GitHub key (agent-forward with command ssh -A); postgresql peer-auth (no psql -U postgres); nginx_proxy crash-loops (bypassed). Still open: janus/WebRTC media over the tailnet, CV (non-GPU VM). Full deploy runbook + verification in the note; provisioning/overlay design in tailscale-gcp-dev-box-migration
  • tailscale-gcp-dev-box-migrationIN PROGRESS (decisions landed + VM provisioned 2026-06-30 via babylon #facekom_dev): mirror the FaceKom dev box on a GCP VM reachable over tailnet taild4189d.ts.net, replacing DuckDNS / public IP. Decision 1 — hostnames = Tailscale MagicDNS (<name>.taild4189d.ts.net), NOT facekomdev.net subdomains → public-DNS Phase 2a RETIRED. Decision 2 — routing = 8b multi-tailscaled sidecar per service (NOT port-based 8a): each of 9 services gets its own userspace tailscaled sidecar (env TS_AUTHKEY+TS_HOSTNAME, ~30 MB idle), own MagicDNS name, own tailscale cert; no app URL rework IFF sidecars named <prefix>-fk-dev to preserve <prefix>-<DEV_DOMAIN> with DEV_DOMAIN=fk-dev.taild4189d.ts.net (flagged to verify; pattern proven on pmv2-zurich). This reverses the note’s original host-level/sidecar-rejected recommendation. VM fk-dev provisioned by deploy (levandor-infra terraform module "vm"for_each=var.vms; pmv2 14 prod containers untouched): e2-standard-4 (4 vCPU/16 GB), 100 GB pd-balanced, europe-west6-a, VPC fk-dev-net/10.2.0.0/24, SA fk-dev-sa, tailnet IP 100.91.108.61, MagicDNS fk-dev.taild4189d.ts.net, ACL tag:cloud; public IP 34.158.19.122 egress-only, firewall denies all inbound except DERP, no public SSH; Docker 29.6.1 + OTel collector; ssh ops@fk-dev. Open (Andras/user): CV/GPU scope (VM non-GPU), toggle “HTTPS Certificates” ON in Tailscale admin (required before tailscale cert), whether deploy makes a FaceKom Artifact Registry namespace. 8b overlay IMPLEMENTED 2026-06-30 (BUILT + compose config-validated, unpushed, no commit on vuer_docker branch tailscale): tailscale.yml ships 8 userspace tailscale/tailscale:stable sidecars (network_mode host, TS_USERSPACE=true, --advertise-tags=tag:cloud, per-svc TS_HOSTNAME+TS_SERVE_CONFIG, DRY YAML anchors, named ts-state-* vols) + 5 app-svc stubs; tailscale/serve/*.json (8: oss/css/css-sdk-demo/esign-oss/esign-api/esign-css/portal/library, each HTTPS ${TS_CERT_DOMAIN}:443http://127.0.0.1:<port>, ports 20080/30080/30081/20180/20181/30180/30380/50080); tailscale/config/*-local.json (5: vuer_oss/vuer_css/esign_oss/esign_css/portal_css); tailscale/README.md; .gitignore+=tailscale/tailscale.env. KEY CORRECTION — “no app URL rework IFF naming preserved” was FALSE: apps compute separator = DEV_DOMAIN.endsWith('facekomdev.net') ? '-' : '.', so a tailnet DEV_DOMAIN flips to . → invalid dotted names like oss.fk-dev.taild4189d.ts.net (NOT MagicDNS-resolvable, NOT the sidecar name). Fix = zero app-repo edits, entirely in vuer_docker: host derivation guarded if (!config.X) + getconfig deep-merges config/local.json last (both verified empirically) → bind-mount a per-app config/local.json at /workspace/<app>/config/local.json setting hosts.* explicitly to <prefix>-fk-dev.taild4189d.ts.net (vuer_oss hosts.cv=null, +esign portal.url). Validated docker compose -f dev.yml -f vuer-oss.yml -f vuer-css.yml -f esign-oss.yml -f esign-css.yml -f portal-css.yml -f facekom-library.yml -f tailscale.yml config -q → EXIT 0. Networking: each sidecar host-net + userspace tailscaled, tailscale serve127.0.0.1:<app-port>, per-svc MagicDNS name + cert; nginx_proxy no longer the access path (harmless). Open (Andras/user): CV/GPU scope (VM non-GPU; hosts.cv=null), toggle “HTTPS Certificates” ON in Tailscale admin (required before cert issuance), whether deploy makes a FaceKom Artifact Registry namespace (none added — uses existing). Next (on user go): push → deploy wires onto fk-dev. Caveat: vuer_oss hosts.api=api-fk-dev has no sidecar but api- is only used by customization /external/createCustomerToken hostname-gating, not base dev flow. (Original source-verified analysis preserved in the note: dev.yml services network_mode: "host", nginx_proxy routes by subdomain PREFIX with domain-wildcard server_name, single self-signed cert, apps build URLs from DEV_DOMAIN; only literal duckdns = README.md:17.)

Giro / girinfo

  • FKITDEV-8581GiroProcess.handleTask() in customization/server/backgroundProcess/giro.process.js (Raiffeisen, customization/raiffeisen branch only; renamed from giroService.process.js during the “Raiffeisen PIon project clean-up”) now splits the catch-block logging into “No response from girinfo service” (RequestError/ETIMEDOUT|ESOCKETTIMEDOUT|ECONNREFUSED|ECONNRESET|ENOTFOUND|EAI_AGAIN) vs “Bad response from girinfo service” (non-200/StatusCodeError/save failure, incl. statusCode); both add elapsedMs/requestTimeout/code. Log-only — retry (this.retry) unchanged. A heavier “mark bg-process/portal state after final no-response retry” option was DEFERRED (ties to the ambiguous-portal-state RCA — box “request in progress” vs dashboard “data arrived” vs logical-match “not available”). Original RCA fix f830fd8e5a shipped 2025-11-28; YouTrack still Pending

Git / orphan branches

  • esign-css-instacash-orphan-history — An orphan branch (customization/instacash in esign_css) breaks the conventional toolset: git merge halts on refusing to merge unrelated histories, git rev-list --count A..B returns numbers without meaning (no merge base), cherry-pick is fragile (different ancestor than the patch was authored against); the three operational responses are --allow-unrelated-histories (one-shot, recoverable), rebase-replay (matches historical pattern), or cherry-pick-delta-forward (cleanest narrative)

Git / commit + branch rulesets

  • techteamer-commit-message-ruleset — TechTeamer vuer repos enforce a repository ruleset on commit metadata: a push is rejected unless every commit subject matches ^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(!)?(\([^)]+\))?: [^\n]{1,100}. Two traps: a default git revert message (Revert "…") is rejected — use the revert: type (git revert -n <sha> + git commit -m 'revert: …'); and the subject after the type(scope): prefix is capped at 100 characters. A single bad subject anywhere in the pushed range rejects the whole push and the fix is a history rewrite — check the full range, not just HEAD. Same rulesets also enforce ticket-prefixed branch names (chore/FKITDEV-NNNN-…). Hit on FKITDEV-8387; branch-naming half first seen on nusz-1.9.11.47

HTTP client / fetch / mTLS

  • vuer-oss-global-fetch-ignores-agent-mtlsverified (Node v22.22.3 / bundled undici 6.24.1): every fetch() in vuer_oss is Node’s global fetch (no undici/node-fetch dep), which IGNORES the node-fetch-style agent: (honors only dispatcher) → the getHttpsAgent() idiom is a SILENT NO-OP (harmless only because cv.rejectUnauthorized defaults true); agent-based client-cert mTLS / rejectUnauthorized:false is dropped. FIX = undici’s own fetch + Agent (dispatcher: new Agent({ connect: { cert, key, ca, passphrase, rejectUnauthorized } })). CROSS-VERSION TRAP: standalone-undici 8.5.0 Agent into global fetch (undici 6.x) → UND_ERR_INVALID_ARG: invalid onRequestStart method; Facekom runs Node 22 and 24 (different bundled undici majors) so don’t pin standalone-undici to the bundled version. Surfaced scoping FKITDEV-8947 (UniCredit mTLS migration)
  • FKITDEV-8947 — migrate UniCredit customization/server/service/UniCredit/ApiService.js (customization/unicredit, UniCreditApiService) off request-promise-native → fetch; uses mTLS (cert/key/ca/passphrase from portal.api) so the naive agent: migration silently breaks TLS — must use undici.fetch+Agent per the gotcha note

InstaCash

  • instacash-external-api-esign-headless-test-2026-06-01headless test path for the InstaCash external API + eSign via branch-only bin/instacash-cli.js (in the vuer_oss container): start-server mocks the bank /auth+/status (8189); every other cmd (post-application/get-invite/get-customer/post-contract/get-/revoke-contract) boots the full vuer_oss in-process and HTTPS-calls ${hosts.oss}/external/... (NOT a thin HTTP client). post-contract → ic-contract flow → EsignRPC → esign. The actual eSign signature is interactive and cannot be driven headless (manual video-ID + auth + sign at the inviteUrl). 2026-06-01 run: customerId 28, post-contract → HTTP 400 {"error":"Contract flow is in progress"} on a not-yet-identified application — open question vs developer-guide-hu.md (contract upload after identification)
  • dev-box-esign-container-startup-failures-2026-06-01 — surfaced while testing the InstaCash 2026-05-27 devel-update on the dev box: esign_css/esign_oss unhealthy due to the nginx non-root PID image regression (NOT the update code); also the post-dep-bump re-yarn install lesson (RedisStore is not a constructor if node_modules is stale) and a chalk ^5 ESM fix for yarn trans
  • dev-box-cv-photo-processing-failures — discovered testing the nrt self-service identification flow on the dev box: photo step fails (“error during photo processing”) when vuer_cv is stopped or the hairpin-NAT /etc/hosts fix is missing; recipe-oriented runbook (check vuer_cv running + hairpin remap, re-apply after restart)
  • sms-verification-code-dev-testing — discovered testing the NRT self-service identification flow on the dev box: how to get past SMS 2FA when the customer phone is fake (test.security.tempTokenSms fixed code + restart + resend, or read customer.getVerificationCode() via the model)
  • ASSICASH-71 — PROD vuer_css local.json portal.url UAT misconfig (FKITSYS-9486 fix 2026-01-06); pending log-volume confirmation; portal_css hosts.portal parallel risk
  • instacash-update-2026-05-27-status — 2026-05-27 devel→instacash sync wave across esign_css/vuer_oss/vuer_css; high-risk surface: vuer_oss customization/listeners/self-service-v2.js (FKITDEV-7518 id-card + newIdFormatAcceptance), vuer_css customization/customizations.js route reconciliation + modal a11y trio; 50 oss / 57 css commits in, esign_css blocked on orphan history; vuer_css server-side clean (no Express 5 risk here)
  • esign-css-instacash-orphan-history — InstaCash side of esign_css is structurally distinct: single squashed orphan, intentional MBH/MKB asset retention (55 devel-deleted-instacash-keeps), three workflow options for resyncing
  • FKITDEV-8817 — esign_css jQuery vuln fix on bugfix/FKITDEV-8817-jquery-update (commit b021019, pushed, PR not yet opened); flows into InstaCash via second-merge of 2026-05-27 sync once landed on devel
  • youtrack-tesztjegyzokonyv-attachment-recipe — InstaCash (ICASH) historically had NO release/eSign tesztjegyzőkönyv in YouTrack (the first was generated 2026-06-26 — see below; still not attached). In YouTrack today: ASSICASH-65 (FaceKom 1.9.11.50) / ASSICASH-92 (eSign 1.3.0.11) carry only build .logs; install tickets ASSICASH-66/62/67/93 (TESZT) / -96 (PROD) only screenshots. The only attached instacash “teszt jegyzőkönyv” PDFs are OLD compliance/DR docs: BUGICASH-460 (BCP teszt 2023-06) + ISSFK-338 (SaaS DR teszt 2021).
  • instacash-esign-1.3.0.11 — InstaCash eSign 1.3.0.11 release composition (esign_oss + esign_css; tag instacash-1.3.0.11; ASSICASH-92 release / ASSICASH-93 TESZT / ASSICASH-96 PROD approved 2026-06-26 from 1.3.0.8; FKITDEV-8817 jQuery CVEs + hardening; no migration, rollback = redeploy 1.3.0.8). First InstaCash release to get a TJK — generated via fk-tjk (instacash added to partners.json: display “InstaCash”, ASSICASH; 5 test cases → ~/Downloads/tesztjegyzokonyv_instacash_1.3.0.11.docx), not yet attached.
  • instacash-esign-dev-box-deploy — recipe to test InstaCash eSign on the dev box (fk-dev; the ssh Facekom box is decommissioned — dev-build-host): align the whole chain to InstaCash (esign → instacash-1.3.0.11, vuer → instacash-1.9.11.50, pdfservice stays main/2.0.12), git stash/fetch --tags/checkout per repo, rebuild in-container, supervisorctl restart all; verify supervisord RUNNING + the two startup log lines + esign_css :10183 200; gotchas: untracked .claude/ looks “dirty”, old log ERRORs may be historical (check timestamps)

iOS Safari / audio recovery

  • FKITDEV-8887root cause: iOS Safari suspends WebRTC audio on AVAudioSession interruption (lock→unlock / background); the remote <video> is paused and never resumed because there is no visibilitychange/pageshow/focus handler; Socket.IO connectionStateRecovery (30 s) masks brief backgrounds (no reconnect→reload), so only short SMS-code reads produce silence that persists. Fix (UNCOMMITTED, branch fix/FKITDEV-8887-ios-audio-resume): InterruptionRecovery controller wired via visibilitychange/pageshow/focus calls VideoFeed.ensurePlaying() (remote <video>.play() when paused) + VideoChatService.recoverAudioIfNeeded() (LocalMediaService.startLocalMedia({audio:true,video:false}) + replaceTrack). Critical gotcha: SenderPeer.pc is a Peer (WildEmitter) wrapper, NOT an RTCPeerConnection — the real connection is Peer.pc; calling this.pc.getSenders() on SenderPeer is always undefined → mic recovery must proxy through Peer.replaceAudioTrack(). Gate: isSafari (covers iPhone+iPad), not isIOS (iPadOS 13+ sends desktop UA → isIOS=false). 119 suites / 0 failures / lint clean.
  • FKITDEV-8887QA acceptance protocol (device repro): the only definitive acceptance gate (unit tests can’t confirm an iOS-runtime bug). Run baseline on origin/devel first (must stay silent) → then validate fix on fix/FKITDEV-8887-ios-audio-resume: iPhone Safari join → 2FA → lock ~10s to read SMS → unlock, expect audio both directions in ~1s. Evidence via allowlisted webrtclog: interruption:resumesenderPeer:audioRecovered {swapped:true} ({swapped:false}/:error = capture failure). Matrix: iPhone built-in+AirPods, iPad (Macintosh UA, validates non-isIOS gating), >30s background (crosses connectionStateRecovery), non-default mic survival (validates LocalMediaService.startLocalMedia path), Android/desktop regression, both directions. Version-risk settlement: pull userAgent for rooms 10071/10091 (ASSGRALI-63) + 2281 (ASSCIB-161/FKITDEV-8895) — iOS ≥16 weakens only the mic-interruption premise; playback + socket-mask hold regardless.
  • FKITDEV-8887polish pass 2026-06-15: mic recovery rerouted from raw getUserMediaLocalMediaService.startLocalMedia({ audio: true, video: false }) (respects saved device); localMedia wired in videochat.script.js; WebRTC test globals extracted to test/tests/unit/_helpers/webrtc-test-globals.js (must run at module top level, before describe + before require of SUT — config reads document.body.getAttribute at require-time); videochat.services.test.js updated to mock svc.localMedia.startLocalMedia + new undefined-guard case.
  • FKITDEV-8887SonarCloud cleanup 2026-06-18 (PR #3066): Quality Gate PASSED but 18 “New issues” (all code smells; 0 bugs/vulns; 89.2% new-code cov). Fixed the 13 in the PR’s new code (11× prefer-optional-chaining, 1× prefer-globalThis windowglobalThis, 1× cognitive-complexity recoverAudioIfNeeded 19→≤15 via _safeLog/_isAudioTrackDead/_applyRecoveredAudioTrack helpers — behavior-preserving, 119 suites/1045 tests + adversarial APPROVE). Left the 5 PRE-EXISTING promptUpload/validationResult smells (videochat.script.js ~L424–448, untouched per gh pr diff 3066) for a separate chore. See ## CI / build gates for the gh-check-run-annotations technique used to read the issues tokenless.

Networking / dev-box (hairpin NAT)

  • tailscale-gcp-dev-box-migrationDuckDNS → Tailscale GCP dev-box mirror over tailnet taild4189d.ts.net. IN PROGRESS (2026-06-30): MagicDNS hostnames + 8b per-service multi-tailscaled sidecar routing; VM fk-dev provisioned (tailnet 100.91.108.61). 8b overlay now BUILT + compose config-validated on vuer_docker branch tailscale (unpushed); key correction — “no app URL change” was FALSE (apps switch -. separator off tailnet DEV_DOMAIN), fixed entirely in vuer_docker via bind-mounted per-app config/local.json. See the ## GCP dev-box mirror / Tailscale topic for full detail
  • dev-build-hostSSH to the dev box (from Claude’s shell): command ssh ops@fk-dev.taild4189d.ts.net (Tailscale SSH, no keypair, no jump box), with a login shell (command ssh … bash -l -s <<'EOF' … EOF) so docker is on PATH. command ssh/command scp are mandatory — the user’s kaku alias (_kaku_wrapped_ssh) shadows plain ssh and is absent in non-interactive shells. The old two-hop topology (Facekom = lederera@localhost via ProxyJump FKJumpBoxroot@lederera-447-fk-hardver, jump box = bare Alpine, no docker) is DEAD — recorded for history in 5. SSH access to the dev box from Claude Code’s shell
  • dev-box-cv-photo-processing-failures — host-network containers (e.g. vuer_oss) reset at the TLS handshake when connecting to the box’s own public/LAN IP (192.168.1.93) — hairpin NAT; the container’s /etc/hosts maps all *-lederera.facekomdev.net to that LAN IP by default, so inter-service HTTPS (CV ping cv-lederera, bin/instacash-clioss-lederera/external/...) fails with read ECONNRESET / “Connection reset by peer”; fix = remap those names → 127.0.0.1 (loopback hits the same nginx, no hairpin); /etc/hosts is a Docker-regenerated single-file bind mount → edit wiped on every container start, re-apply after any restart via truncate+write (> /etc/hosts / base64 -d > /etc/hosts), NOT sed -i (fails Device or resource busy)
  • fk-dev-nusz-deploy-and-8959-verificationSSH topology of the new fk-dev GCP dev-mirror VM (distinct from the on-prem box’s ProxyJump topology above): reach it at command ssh ops@fk-dev.taild4189d.ts.net — user ops, Tailscale SSH (no keypair), tailnet taild4189d.ts.net / 100.91.108.61; the same kaku wrapper shadows plain ssh/scp in Claude’s shell → use command ssh / command scp. The box has no GitHub deploy key → forward the Mac’s id_ed25519 (ssh-add + command ssh -A) for git fetch. Per-service Tailscale sidecars (oss-/css-/esign-*/portal-fk-dev) are the access path; nginx_proxy crash-loops but is bypassed

NPM registry / package publishing

  • FKITDEV-9022 — publish 7 standalone @techteamer/* library repos (xlsx, timestamp_service, mq, video-processor, archiver-zip-encrypted, janus-api, acl — all on master, NOT the vuer monorepo) to the private registry https://npm.facekom.net/, so the GitHub source can later be made private. Mechanic (only org precedent = TechTeamer/amqplib-asyncapi-template, which declares publishConfig:{registry:"https://npm.facekom.net",access:"restricted"}): per-repo add that publishConfig to package.json + one .github/workflows/publish.yaml (push-to-master; secrets.FACEKOM_NPM_TOKEN~/.npmrc; npm view <name>@<version> --registry … guard = idempotent, publishes only new versions). publishConfig.registry only moves the publish target — the default registry stays npmjs, so installs/consumers are unaffected; no package renames. Decision (user, 2026-07-08): keep @techteamer/*, do NOT rename to @facekom/*timestamp_service is the sole special-case rename: @techteamer/timestamp-service + drop "private": true (both block publish). Correction: the “janus-sdk publish.yaml reference impl” was WRONG — TechTeamer/janus-sdk = 404; only the amqplib template references the registry. mq special case (release.config.mjs/semantic-release honors publishConfig.registry, but no release workflow wired yet). Phase 2 = take repos private / stop public publish — must come AFTER consumers (vuer_oss/vuer_css/portal_css, Yarn-Classic v1 + offline mirror) are repointed, or their CI/Docker installs break. Blocked on VPN: registry docs, CI token, org secret FACEKOM_NPM_TOKEN, real publish test. acl reference done + validated locally (branch chore/FKITDEV-9022-npm-facekom-publish off origin/master), uncommitted; other 6 pending go; solo-author, no auto-PR

OCR / MRZ

  • FKITDEV-8788 — HU eID back side (MRZ TD1, classId 5, HUN-BO-06001_BACK_PO): FULL image scores MRZ valid_score:100 but the warped/cropped image of the same capture scores 2; prod rejects on the crop because getMrzRecognitionAttempts (SelfServiceV2Service.js:673-712) can feed the warped-document attempt to getMrzCheckResult (SelfServiceCheckerService.js:219-246); two CV paths — warp-first VuerCVOCRRecognition.js:45-99 (/api/v2/document-warp/api/v1/mrz on crop) vs no-warp MRZDetectionApi.js:22-38; validScoreValidator (:48-63) forces score 0 when detections.length !== 1; valid_score/mrzData only persist when ocr.useCVMRZData=true; CV 4.9.0 fix likely only validated on FULL image (triage open)

Oracle Instant Client

  • FKITDEV-8252 — Oracle has not published OL10 yum repos (404 across yum.oracle.com/repo/OracleLinux/OL10/); decision to use OL9 .el9 instantclient RPMs on UBI10 base for kh and bb partner Dockerfiles (Option 1 ship-it); memo at /Users/levander/coding/facekom/FKITDEV-8252-oracle-ol10-memo.md awaiting Bence sign-off and partner-contract escalation

Package renames / repo drift (UBI10)

  • FKITDEV-8252 — already-applied renames: pcre-devel→pcre2-devel, zlib-devel→zlib-ng-compat-devel, redis→valkey (with compat symlinks), coturn .el8 pin dropped → plain EPEL10 4.10.0-1.el10_3, rabbitmq /el/10/ empty → fallback /el/9/ 3.13.7 .el8.noarch, shadow-utils for groupadd/useradd, x86_64→$basearch in OL10 repos; A.6.1 additions: libopusopus/opus-devel, libmicrohttpd lives in EPEL10 not BaseOS, gzip missing from UBI10 minimal, GitHub archive URL strips v prefix (cd ${VAR#v}), git-lfs install --system must run before clone; on-probe-build watchlist for Phase B: ffmpeg-devel, libogg-devel, libconfig-devel, gtk-doc, jansson-devel, pkgconf, gengetopt, libsrtp2

Phantom room

  • FKITDEV-8787 — Raiffeisen Myra mobile self-service rooms with vestigial duplicates; SDK-local Already authorized / Already has some kind of room guards; OSS V2 SelfServiceV2Service.start() silently resumes any non-closed room; partial-unique-index gap
  • FKITDEV-8787FIX (2026-06-02, vuer_css fix/FKITDEV-8787-...): server-side self-heal in selfService:v2:start — if stale selfServiceRoomData, call OSS getRemainingSeconds(roomId) and delete only when < 1 (room positively expired); abort handler now clears state too. Design learning: FAIL CLOSED on ambiguity — first cut deleted state on ANY RPC error (fail-open), which would let a transient error on a LIVE room spawn a 2nd live room (the very duplicate bug, inverted); verified OSS returns 0 for timed-out rooms so the catch only sees truly-absent rooms → preserve state + log error there. RULE: for a duplicate/phantom-room-prevention guard, “RPC threw” ≠ “resource dead”

portal_css

  • portal_css — slim portal sister of vuer_css: registration, login, SCA, password recovery, JWT handoff (no Janus, no waiting-room)
  • ASSICASH-71hosts.portal config feeds CSP connect-src and PortalService.js:48 password-recovery email URL; empty default is a silent foot-gun
  • FKITDEV-8239 — first repo in the dependency-reduction initiative to get a depcheck CI job; branch chore/FKITDEV-8239-depcheck-ci (based on origin/devel), not yet committed

Queues / RabbitMQ (app-side)

  • vuer-oss-optional-queue-connectionvuer_oss supports multiple named MQ connections through @techteamer/mq’s ConnectionPool (named-map config shape); server.ts:465, background.ts:197 and bin/attachment.js:52 all read config.get('esign.queueConnection') then connectionPool.hasConnection(). So the optional-queue ECONNREFUSED swallow in server.ts (from FKITDEV-3191) is NOT dead code — it covers a supported partner setup where an external eSign RabbitMQ may be down at boot (without it, supervisord crash-loops a healthy service). It looks unreachable because no in-repo config sets optional — partner runtime configs live outside the repo tree. An attempt to delete it as dead code was reverted. Rule: when auditing “unused” config keys, grep the readers, not the setters

Raiffeisen

  • face-comparison-data-verdict-threshold-model — FKITDEV-8827 (PION) face-comparison export design: PION is a videochat flow (comparisons keyed by roomId, produced by videochat:close hook, gated by faceRecognition.comparisonPairs), so the tool is a general both-paths export (raiffeisen-facecomparison-export.js + FaceComparisonExportService), not self-service-only; videochat rows get a report-computed verdict (no runtime classification) carrying raw distance + applied thresholds for audit; spec at .worktrees/vuer_oss-FKITDEV-8827/docs/superpowers/specs/2026-06-03-raiffeisen-facecomparison-export-design.md
  • FKITDEV-8581 — girinfo no-response observability change on customization/raiffeisen: GiroProcess.handleTask() catch block split into distinct “no response” (timeout/network) vs “bad response” (non-200/save) logger.errors with elapsedMs/requestTimeout/code/statusCode; log-only (retry unchanged); heavier portal-state-marking option DEFERRED; SLARAFIPI-53 root cause = ambiguous portal states; original fix f830fd8e5a shipped 2025-11-28 but ticket still Pending
  • FKITDEV-8787 — Myra mobile KYC; customization/raiffeisen overrides; resolveExternalToken() reuses customer.id per offerId (mechanism for csökevény szoba); flow handler myra-self-service-v2-phase-1; m3szi owns prior fix (FKITDEV-7667 / SLARAFIPI-53)
  • FKITDEV-8788 — Raiffeisen PION HU-eID-back MRZ crop bug (SLARAFIPI-61, marked “Solved” prematurely on a CV 4.9.0 full-image test); CV/ML owner Zsolt Mészáros, coordinator Bence László, reporter Bihari Péter; mitigation ships on customization/raiffeisen
  • youtrack-tesztjegyzokonyv-attachment-recipe — Raiffeisen is the only client with an eSign-tied test record: BUGRAFIPI-512 “eSign 1.3.0.22 release” → …Raiffeisen esign - Tesztjegyzőkönyv - 22 Facekom Release v1.1.2.pdf (2024-10-24; 2/2 dev cases passed, executed Nagy Balázs 2024-10-16, components vuer_css/vuer_oss/esign_queue) + sibling BUGRAFIPI-516 (esign bizalmi szolgáltatás DR recovery TJK). The recent Tesztelési jegyzőkönyv PDFs (ASSRAFIPI-117 r1.9.11.94, -113 r93, -102 r92, 2026) are FaceKom/VUER OSS+CSS releases, NOT eSign. BUGRAFIPI-514 (FaceKom 1.9.11.61) has both .pdf + .docx variants.

Reports / SL export

  • FKITDEV-8639SL discrepancy between report UI and Excel export (NÚSZ). Two SL formulas coexist BY DESIGN: naive per-period round (CallsReportService.js:669-670) vs volume-weighted overall (:558-559, Simpson’s-paradox gap). PR #7862 (543f293c38, tag nusz-1.9.11.45) made the Excel report self-consistent/auditable (Sum value on every row) but did NOT make UI per-period == Excel weighted-overall; team standardised on the weighted overall as the headline SL. Per nusz-1.9.11.47 (ASSNUSZ-58 UAT), the client STILL reported the SL discrepancy after the fix (“Az SL eltérés itt is jelentkezett”) while the daily-stat discrepancy resolved. OPEN PRODUCT DECISION: UI == Excel exactly requires picking ONE formula everywhere — a product call, not a further bug fix; likely the live topic. Bug C (ReportsService.js:63 truelocale swallow) is DISTINCT from FKITDEV-8747 (forward locale through RPC queue boundary + empty SL when no calls, PR #7929, new for 1.9.11.48) — two locale bugs at two layers. Also Bug B (Excel column misalignment), Bug D (counting gap waiting_calls > calls + exits).
  • FKITDEV-8747the follow-up fix that shipped (PR #7929, squash 5099b8ad8b, merged 2026-05-28, nusz 1.9.11.48; parent ASSNUSZ-58). NOT a call-count bug — the raw counting logic is unchanged; all changed files are CORE (video-calls report / daily statistics), surfaced by NÚSZ. Three squashed fixes: (1) empty-period SL → null not 0 (CallsReportService.js ~L562: SL = calls>0 ? round((calls-lateAnswers)/calls*100) : null) on per-bucket and Sum/aggregate; client reportCalls.js renders null- (was always + '%', so 0% showed); (2) Sum-column SL aligned to the per-bucket rule — that mismatch was the reported “eltérés”; (3) locale plumbed end-to-end through the RPC queue (rpc_client/rpc_server Reports.js) + the new reporterDownload.process.js BackgroundProcess (a boolean true was passed instead of the locale string) → xlsx exports now use the user’s UI language, reviving the FKITDEV-8639 locale fix that was dead on the download path. Test cases: /Users/levander/coding/facekom/FKITDEV-8959-8747-test-cases.md (also covers FKITDEV-8959).

Security / dependency CVEs

  • cve-2025-7783-form-data-via-requestCVE-2025-7783 / GHSA-fjxv-7rqg-78g4: critical form-data@2.3.3 (unsafe random multipart boundary; patched >=2.5.4) pulled in by EOL request@2.88.2 whose form-data: ~2.3.2 hard-pin will never move. Not on devel — customization-line only, because request is live partner code (vuer_oss customization/api/sms/SmsCofidis.js; vuer_css customization/server/web/api/{login,register,partner-register}.endpoint.js). Red on cofidis/kh/raiffeisen branches. Interim fix = resolutions override "request/form-data": "^2.5.6" + yarn install (house-style precedent: csurf/cookie, twig/minimatch, ts-jest/handlebars); real fix = drop request, separate ticket
  • security-audit — consolidated FaceKom vulnerability findings across vuer_oss / vuer_css / vuer_cv / esign / pdfservice / nyilvantarto-scraper (2 CRITICAL, 6 HIGH, 5 MEDIUM, 6 LOW + positive findings)

Self-service v2

  • face-comparison-data-verdict-threshold-model — self-service liveness-v2 face comparison (SelfServiceV2Service.js:1418) is gated by task.options.recognitionOptions.compareFaceWith (base V2 proto doesn’t set it → no row); self-service rows key by selfServiceRoomId, get per-room thresholds from the oldest selfService:v2:config:state activity (getActivityLog ASC [0], REPLACES the set) falling back to global Setting; verdict mirrors runtime getFaceComparisonResult (unlike videochat rows which have no runtime verdict)
  • dev-box-cv-photo-processing-failuresSelfServiceV2Service.photoCandidate (:1043) calls submitTaskRecognition unconditionallyFlowService.submitTaskRecognitionRecognitionService.runRecognitionsCVRecipe (server/cv/CVRecipe.js:88 throws “Recipe missing no CV Service!” when CV health-check marked the host down); there is no dev flag that skips face-detection recognition (selfService.ui.disabledChecks only covers girinfo/emrtd/kau), so an unreachable CV service hard-fails the nrt photo step
  • sms-verification-code-dev-testing — dev/testing: the self-service 2FA SMS code is set by the customer:verification:sendSms hook; force it with test.security.tempTokenSms (+restart+resend) or read customer.getVerificationCode() (stored as videochatToken)
  • FKITDEV-8787SelfServiceV2Service.start() silently resumes; _findOpenRoomForCustomer race; status enum ['waiting','incall','left','closed','deleted','archived'] — only last three treated as not-open; V1 throw at SelfServiceRoomService.js:217 swallowed by SelfServiceActions.js:27-34
  • FKITDEV-8787socket-layer fix (vuer_css server/socket/events/selfservice-v2.js): selfService:v2:start self-heals stale selfServiceRoomData via OSS getRemainingSeconds (delete iff < 1), selfService:v2:abort clears state after the OSS abort RPC; tests use REAL server/auth.js predicates via jest.requireActual (hand-rolled fakes had diverged — dropped the isAuthorized/customerId conjunct + collapsed the hasAnyRoom roomData branch)
  • FKITDEV-8788getMrzRecognitionAttempts (SelfServiceV2Service.js:673-712) selects between full-photo attempt (mrzTask.data.attachmentId) and warped-document attempt (candidate.document.attachmentId); getMrzCheckResult (SelfServiceCheckerService.js:219-246) turns recognitionAttempts[0].mrz.valid into accept/reject — fallback-to-full here is a candidate mitigation

Supervisor / process config

  • unversioned-partner-supervisor-overlaysRELEASE BLOCKER pattern: partner supervisor overlays are NOT version-pinned to the app. vuer_build/partner/<client>/vuer_oss/Dockerfile does FROM harbor…/vuer_oss:${VUER_VERSION}… (version-pinned app image) then COPY supervisor_vuer_oss_docker.conf (unversioned, taken from main at build time) → conf and app version are decoupled, so a rebuild of an old release tag gets the old app with today’s conf. Consequences of changing a command= line: (a) older release tags stop rebuilding (MODULE_NOT_FOUND → supervisord crash-loop), (b) ~94 origin/customization/* branches still carry the old spelling so each partner breaks on its next build until it merges devel (time-staggered, looks like a random partner regression). Not fixable by merge ordering — it’s a versioning mismatch. Mitigations: hold the vuer_build/vuer-release merges until the first release tag containing the change is cut; or delete redundant overlay confs so partners inherit the base image’s symlink to the app’s own conf (decision rule in FKITDEV-8354-mvm-supervisor-config-dedup); or make overlays release-aware. Merge hazards: customization/kh edits both confs (conflicts), customization/nusz edits server.js+cron.js (rename+modify). Surfaced by FKITDEV-8387
  • FKITDEV-8354-mvm-supervisor-config-deduphow supervisor configs reach /etc/supervisor/conf.d/ in vuer-release component images (reusable): TWO paths — (a) base install/configure-app.sh:16-21 symlinks the source package’s supervisor*.conf, (b) the partner component Dockerfile COPYs a partner override on top (last-write-wins by filename); supervisord.conf includes files = …/conf.d/*.conf. Decision rule: a partner override is a deletable duplicate only if byte-identical to the repo’s conf, else it’s intentional customization. Applied to PR #28 (MVM): vuer_css override = byte-identical ⇒ deleted; vuer_oss override = kept (supervisor-stdout eventlistener logging stdout_events_enabled=true/stdout_logfile=NONE, 8 programs, omits [program:vuer_oss_storage] — consistent across all vuer-release partners: equilor/nusz/polgaribank-facekom/unicredit/unicredit-srb/mvm). The eventlistener apparatus (supervisor_stdout.py+supervisor_stdout_eventlistener.conf+pip install supervisor-stdout) lives ONLY in vuer-release and is the consumer of the supervisor-stdout plugin restored in PR #28 round-1 (07db225)
  • FKITDEV-8252supervisord runtime gotchas on ubi10-minimal (build-green ≠ runs): supervisor 4.2.5 crashes on Py3.12 (pkg_resources gone) → pin 4.3.0; supervisord logfile path hidden by a /var/log bind-mount → log to /var/log root; supervisord (PID1) does NOT propagate a program’s HOME nor does USER set it (erlang .erlang.cookie eacces → set environment=HOME=… per program); must run supervisord as ROOT (removed wrong USER $DOCKER_USER from vuer_css/portal_css)
  • entrypoint-rename-blast-radius — renaming any vuer entrypoint (server.js/cron.js/background.js/…) is a 4-repo coordinated release, not a single-repo edit: 95 supervisor conf files hard-code command=node <entry>.js75 in vuer_build/partner/* (35 partners), 11 in vuer-release/projects/*/components/*, 2 in vuer_docker/workspace/devtools/files/, only 7 in the three code repos (vuer_oss/vuer_css/portal_css). Two SILENT traps beyond the confs: vuer_oss/server/logger.js:102–114 picks the log4js channel by sniffing process.argv[1].endsWith('server.js')/etc. (rename → every process logs to the unknown channel, no crash), and an 8th entrypoint soap_server.js exists ONLY on bb/kh customization branches (…/{bb,kh}/vuer_oss/supervisor_vuer_oss_docker.conf:137, not on devel). A missed conf = supervisord crash-loop (exit 2, restart 1–2 s; a March-2026 attempt did exactly this). Motivates FKITDEV-8387’s .ts-module + one-line .js-shim approach (keeps every conf/logger.js/.nycrc filename literal untouched)

TypeScript

  • FKITDEV-8387SUPERSEDES the shim plan: the entrypoint migration landed as a DIRECT RENAME (2026-07-22). After reviewer feedback on vuer_oss PR #8059 the .js-shim strategy was dropped — entrypoints are real .ts files invoked as command=node server.ts, no shims: vuer_oss 7 entrypoints, vuer_css + portal_css 1 each, 75 supervisor confs in vuer_build, 12 in vuer-release; all three code PRs CI-green 8/8. Two gotchas worth remembering: the soap_server.js suffix trap ('soap_server.js'.endsWith('server.js') === true, so bb/kh’s SOAP entrypoint was silently inheriting the vuer log4js channel; the rename dropped it to unknown with no error → endsWith('server.ts') || endsWith('soap_server.js'); lesson: suffix-matching entrypoint dispatch is fragile under rename), and the still-open release blocker in unversioned-partner-supervisor-overlays
  • typescript-in-vuer-reposCORRECTION (2026-07-22): the unflagged type-stripping floor is Node 22.18, NOT 22.6 — 22.6 required --experimental-strip-types, and no supervisor command= passes node flags. Verified empirically: node:22.6 on a .ts entrypoint → SyntaxError: Missing initializer in const declaration (parsing TS as JS); node:22.18 runs it. Version surface: engines >=22.18.0 in all three repos, images/CI (vuer_build, vuer_docker) install 24.x, but vuer-release pins a floating NODE_VERSION: 22 — above the floor today, not pinned there
  • typescript-in-vuer-reposhow TypeScript actually works in vuer_oss/vuer_css/portal_css (established by FKITDEV-8246 “TS Magic”, vuer_oss PR #7645 55035572bb; foundation for the FKITDEV-8251 epic): NO build step (tsconfig noEmit:true+erasableSyntaxOnly:true, nothing runs tsc, no typecheck job in CI in any of the three repos — TS is editor/ESLint-only, type errors don’t fail CI), Node ≥ 22.18 strips types natively at runtime, files stay CommonJS (no "type":"module" anywhere), a cross-module require of a .ts module needs an explicit .ts extension (require('../util/magic.ts'); extensionless → MODULE_NOT_FOUND), root-level *.ts is SILENTLY UNLINTED (ESLint TS block files:['server/**/*.ts','customization/**/*.ts','client/**/*.ts'] → a root server.ts gets “File ignored because no matching configuration was supplied”; tsconfig include has the same blind spot), Jest transforms .ts via @swc/jest (vuer_oss) / ts-jest (vuer_css, portal_css), @typescript-eslint/no-explicit-any is an ERROR (never fix a type error with any), and require('node:module').stripTypeScriptTypes(src) cheaply asserts a file is erasable-syntax clean
  • nyc-cannot-load-typescriptGOTCHA: nyc (v18) cannot load .ts at all — it hijacks the .ts extension handler (append-transformdefault-require-extensions/js.js) and compiles TypeScript as raw JavaScript → SyntaxError: Unexpected token ':'; neither --extension=.ts nor --include '**/*.ts' helps (Node’s runtime type-stripping is bypassed by nyc’s require hook). Consequence: vuer_oss/supervisor_vuer_oss_e2e_test.conf runs npx nyc node <entry>.js for all 7 entrypoints and server.js already requires six .ts services at boot (server.js:48,83,99,108,109,110) → the conf has been broken since FKITDEV-8246 “TS Magic” landed (Jan 2026); nothing outside the git index references it (no CI job, no Docker repo) so it went unnoticed. Fix = swap nycc8 (V8 coverage, no require hook) or retire the conf; warrants its own YouTrack ticket. First hit on FKITDEV-8387
  • FKITDEV-8387 — Task 6 implementation, vuer_css server.js shim: second repo in the multi-repo .ts-shim rollout, single entrypoint. vuer_css/server/logger.js uses a static log channel list, unlike vuer_oss’s process.argv[1]-sniffing logger — no logger change needed, a repo-to-repo gotcha worth checking per repo. 4 files (eslint.config.mjs/tsconfig.json glob widen, server.ts <void> Promise-type fix, bin/server/server.task.js watch list); tsc/eslint/yarn lint exit 0, 115/115 suites (1064 tests) pass; commit b6513dc0 on chore/FKITDEV-8387-ts-entrypoints, local-only

Validation / log analysis

  • ASSICASH-71 — 2026-05-18 validation: PROD + 2 UAT log pulls (~1.1M lines total) confirm CSP-channel flood is gone; FKITSYS-9486 holding (0 ohp-uat.mbhbank.hu refs in PROD); both UATs silent for 12-19 months; status moved to validated

vuer_cv

  • dev-box-cv-photo-processing-failures — CV runs in its own container vuer_cv (image harbor.techteamer.com/facekom-devel/vuer_cv:4.6.2.DEV-...); when stopped, nginx returns 502 for https://cv-lederera.facekomdev.net and vuer_oss logs CV server is down; docker start vuer_cv boots it under supervisord (nginx/redis/CV proc/~10 workers) to Up (healthy) in ~2 min (loopback curl flips 502→404); but it can still be unreachable from vuer_oss due to hairpin NAT (see topic above)
  • FKITDEV-8252in scope for FKITDEV-8252 (Q3 resolved by execution); new base/vuer_cv/Dockerfile UBI10 base, probe-builds green at 5.93 GB (iter 7); needs EPEL10 for libmicrohttpd, git-lfs install --system before clone, ENV_VERSION=8 matching config/docker.json requiredEnvVersion; size-reduction (multi-stage drop of git-lfs/gcc-c++/python3-devel) flagged as follow-up; cleanup microdnf remove --allowerasing cascade through git-core deps worth a sanity audit

WebRTC / video orientation

  • FKITDEV-8533videoOrientExt (the urn:3gpp:video-orientation RTP header extension) lets the receiver correct rotated video; gated at 4 sites — server/cv/VuerCVListenerSession.js, server/socket/events/videochat.js, server/transport/session/RoomTransportSession.js, server/transport/session/SelfServiceTransportSession.js (keep in sync). RESOLVED 2026-06-23 via “Option A — un-gate CVO for browsers” (branch fix/FKITDEV-8533-videoorient-ungate, commit d27d4cc990): restored the gate’s 2017 intent — shared helper server/transport/videoOrientExt.js videoOrientExtEnabled(customer) = !customer.isNativeApp() (null→true) enables CVO for ALL browsers, disables it ONLY for the native SDK (userAgent.startsWith('mobile/')). Supersedes the iPad-detection PRs 7945 (no detection needed — the iPad is a browser). The customer’s own ID photo is captured from the LOCAL preview, which CVO can’t touch → client-canvas rotation (PR #3043) is orthogonal and still needed.
  • FKITDEV-8887 — iOS Safari audio interruption recovery; InterruptionRecovery controller + VideoFeed.ensurePlaying() + Peer.replaceAudioTrack() proxy chain; see also ## iOS Safari / audio recovery topic for full detail

RTK / tooling gotchas

  • rtk-mangles-curl-and-pipesRTK (the token-proxy that auto-rewrites shell commands) MUTATES some commands, not just their output → silently wrong results. curl <url> fails with curl error (3) “Malformed input to a URL function” (Rust proxy corrupts the URL; wget also unreliable); ls | sort returns empty; find|wc -l / |grep -c get zeroed (dangerous — reads like a legit “no results”). Bypass via python3: download with urllib.request.urlretrieve (not curl/wget); run multi-step CLI checks via subprocess.run([...]) argv list (no shell=True, not a shell pipeline); for counts cross-check two independent methods. rtk proxy <cmd> is a raw escape hatch but prefer the python bypass. Hit while fetching the actionlint binary for the FKITDEV-8239 review
  • rtk-git-log-hides-merge-commits — sibling RTK gotcha: output-filtering drops merge commits from git log --oneline --graph, producing a deceptively linear DAG → squash/rebase/reset can operate on the wrong range and lose a parent’s history. Use parent-aware plumbing instead (git log --pretty='%h | %p | %s', git rev-list --parents -n 1 <sha>, git rev-list --count A..B); verify a squash preserved content by comparing HEAD^{tree} hashes before/after; non-interactive squash via backup-ref + reset --soft + tree-hash equality gate (git rebase -i unavailable in this harness)

Release management / YouTrack

  • vuer-release-build-flowhow the vuer-release build/release flow actually works, read from the TechTeamer/vuer-release-cli Python source (2026-07-22) — the release_tool binary is NOT a black box. Flow: release-tool release create project <p> (interactive VERSION/BUILD_NUMBER/TAG) → projects/<p>/release/<N>/release.json + tag <p>@<N>autobuild.yml on a self-hosted runner (RELEASE_PAT~/.git-credentials HTTPS x-access-token, download release_tool asset, genbuildpublish to Harbor with HARBOR_USER/HARBOR_SECRET). Corrections to previously-guessed assumptions: (1) component source is cloned from TAG, not VERSION (gen.py::download_sourcegit clone --branch <TAG> --single-branch --depth 1); VERSION only feeds the image tag {registry}/{PROJECT_NAME}/{NAME}:{VERSION}.{BUILD_NUMBER}-{SECURITY_NUMBER} + the generated .env. (2) a new base component needs no base@N release firstBASE_/PROJECT_/RELEASE_COMPONENT_IMAGE_TAG are the same locally-computed string, never resolved against the registry; build.py builds the base stage then the project stage against the just-built local image. (3) component NAME == GitHub repo name (repo_name = component["NAME"] under GIT_REMOTE_ORG), no override key; JANUS_REPOSITORY is only used by install-janus-build-env.sh. (4) release create writes COMPONENT_LIST, gen only reads itcomponent_env_values.json (base then project, project wins) supplies interactive prompt defaults at release create (release.py:239-259/269-297, written at :356); gen.py:76 reads release_json["COMPONENT_LIST"] and never re-reads the component env files. This corrects the old “gen snapshots component config” gotcha in vuer-release-cut-recipe (now fixed there): janus pins are the effective default but overridable at release time, not immutable. (5) TAG is NOT in REQUIRED_ENV_VALUES (release.py:49 = VERSION + BUILD_NUMBER only) — it is prompted only if already present in the merged env values; janus deliberately has no TAGhas_source() false → never cloned by the CLI (fetched by install-janus-build-env.sh via JANUS_REPOSITORY/JANUS_VERSION_COMMIT); trap: a new base component missing TAG is silently never cloned. Plus gen.py::rm_always sanitization (strips .yarnrc, config/dev.json, .git, any supervisor_*/nginx_* without docker in the name), tarball top-level dir == NAME, component availability = directory existence (release/.gitkeep required; component_env_values.json + Dockerfile optional), do not use release-tool component create (stale component.j2), and the FKITDEV-8349/DÁP application (forced dap-demo-partner hyphen naming → Harbor image rename; TAG 1.0.7.1 not 1.0.7)
  • youtrack-ready-for-release-nusz-queryYouTrack access + the NÚSZ “Ready for release” release-scope query. Tracker = YouTrack at https://youtrack.techteamer.com (REST /api/issues; MCP server at /mcp in ~/.claude.json, scoped to claude_orchestrator). Auth = Bearer token from ~/.config/facekom/youtrack.token (chmod 600, never on argv); the /fk-ticket command (.claude/commands/fk-ticket.md) + client.py extractor read the same file. “Ready for release” is a TAG (exact string Ready for release; search tag: {Ready for release} — braces for the spaces); it is tracker-wide (57 issues across clients), so the project: filter is what scopes it. The four NÚSZ projects: CRNUSZ (Business Requests), BUGNUSZ (Support Issues), SLANUSZ (SLA), ASSNUSZ (Assist). Verified scope query project: CRNUSZ, BUGNUSZ, SLANUSZ, ASSNUSZ tag: {Ready for release} returned 3 on 2026-06-15 (CRNUSZ-102, ASSNUSZ-58, SLANUSZ-28; BUGNUSZ 0); read-only curl -G --data-urlencode recipe included. CRNUSZ-102 verified example shows State Pending yet tag-flagged → the tag (not State) is the readiness signal. Don’t confuse with the distinct Upcoming Release tag. GET/read-only only.
  • nusz-1.9.11.47 — per-release tracking hub for nusz @13 / 1.9.11.47 (release issue ASSNUSZ-116 / FKITDEV-8938). Scope mechanism, dual-publish 🅼 Harbor / 🅻 vuer_build checklist, manual post-release YouTrack transitions, and a per-ticket payload detail section: CRNUSZ-102 (impl FKITDEV-8794/8801 — no code/PR found, business-accepted, UAT 06.18), SLANUSZ-28 (impl FKITDEV-8639 → PR #7862, NOT yet in customization/nusz, may be in .45/.46), ASSNUSZ-58 (stat-export, UAT/PROD gate, targeted .46.1). Merge-status warning: payload code not yet confirmed in customization/nusz; version target (.45/.46/.46.1/.47) needs confirming.
  • instacash-esign-1.3.0.11 — per-release hub for the InstaCash eSign 1.3.0.11 release (eSign pipeline, not vuer-release): esign_oss + esign_css only, tag instacash-1.3.0.11 / Harbor instacash-esign-{oss,css}:1.3.0.11-20260608; ASSICASH-92 release + ASSICASH-93 TESZT / ASSICASH-96 PROD (approved 2026-06-26 from 1.3.0.8); changelog = devel update + FKITDEV-8817 vuln fixes; no DB migration / no breaking change; rollback = redeploy 1.3.0.8. First InstaCash release to ship with a TJK.
  • client-registry — cross-system name glue for /fk-release: YouTrack suffix ≠ repo name (RAFIPI=raiffeisen, MNET=magnet, PB=polgaribank, GRALI/GRALIA=generali, etc.). 22 clients mapped with build-path (modern vuer-release/projects/<client> / legacy vuer_build/partner/<client> / eSign instacash) + resolution rules (YouTrack projects CR/BUG/SLA/ASS<suffix>, version from open ASS<suffix> Release issue, customization branch customization/<repo> incl. -instant/-v2/-f1 variants).
  • release-automation-design — reusable prepare-and-gate /fk-release <client> design. Now also covers client generalization (path auto-detection, universal ASS<CLIENT> Release-issue convention proven by CIB .101), PR fetch without YouTrack VCS (VcsChangeCategory empty → resolve via git log --all --grep=FKITDEV-NNNN merge-commit + comment-scan for pasted PR URLs), and comment extraction ranking (has-attachment > Hungarian QA keywords > embedded issue links; attachment URLs are signed/expiring).
  • FKITDEV-8354-mvm-supervisor-config-dedupvuer-release Gen2 partner-migration mechanics (FKITDEV-8354, MVM project, vuer_buildvuer-release lean format, PR #28 base master): partner component images layer overrides via projects/<client>/components/<svc>/Dockerfile COPY on top of the source-package files symlinked by base install/configure-app.sh; supervisor-config dedup decision rule (byte-identical ⇒ delete, else keep). Do not conflate with FKITDEV-8252 PR #31 feat: ubi10 (different ticket/branch). Reviewer bencelaszlo; round-1 set janus pins 1.4.1/cc0fdca8 + restored supervisor-stdout.
  • youtrack-tesztjegyzokonyv-attachment-recipewhere FaceKom test records (“tesztjegyzőkönyv” / “Tesztelési jegyzőkönyv”) live + a read-only REST attachment recipe. TJKs are PDF/DOCX attachments on per-client ASS<CLIENT> release / BUG<CLIENT> tickets, NOT standalone issues; 8-section branded template (Cél / háttér / teszttípus-összegzés / tesztesetek / jegyzőkönyv+evidencia / értékelés / hibák / mellékletek); canonical templates = FKITDEV-8329 (unified format) + FKITDEV-8330 (release/install template). Recipe (python urllib, same base + ~/.config/facekom/youtrack.token as youtrack-ready-for-release-nusz-query): GET /api/issues?query=…&fields=…,attachments(name,mimeType,created,url),comments(text,attachments(…)), Hungarian full-text works, scope by project:; download = prepend base to the attachment’s relative signed url, GET w/ Bearer, write bytes; timestamps epoch-ms. GET/read-only.
  • tesztjegyzokonyv-generation-flowproducing companion to the attachment-recipe note: a /fk-tjk flow to GENERATE per-partner Tesztelési jegyzőkönyv .docx for a release (built 2026-06-26). Practice: one TJK per AFFECTED partner per 1.9.11.NN (not all 39), attached to that partner’s release ticket; shortName usually ASS<PARTNER>/BUG<PARTNER> but VARIES (MicroSec=MF, DÁP=DAP/ASSDAP) so partners.json pins ytProject; a core change reuses byte-identical body text across partners (MKB ASSMKB-90 == BB ASSBB-82). New std template tesztjegyzokonyv_sablon.docx (authored 2026-05-29, replaces 3 inconsistent legacy formats) = 19 <…> placeholders each intact in a single <w:t> run, all in word/document.xml → plain string substitution preserves styling (no docxtemplater/pandoc). Tool = Claude command .claude/commands/fk-tjk.md (pulls dev ticket via fkticket + 1 past report/partner for house style → draft → render) + stdlib renderer .claude/scripts/tjk/render_tjk.py (clones test-case block document.xml paras 27–36 per case w/ 1.k., \n<w:br/>, verbatim zip-repackage swapping ONLY document.xml, self-check) + partners.json (13 seededinstacash/ASSICASH added 2026-06-26) + pinned sablon. v1 leaves screenshots / pass-fail underline / PDF export / YouTrack-attach MANUAL (no write-back). Self-check + tests pass; design spec /Users/levander/coding/facekom/docs/superpowers/specs/2026-06-26-teszt-jegyzokonyv-flow-design.md. First real use (2026-06-26): generated the first-ever InstaCash eSign TJK (5 cases) for eSign 1.3.0.11~/Downloads/tesztjegyzokonyv_instacash_1.3.0.11.docx.