The repository now contains the Node.js/TypeScript implementation. The PHP code
is preserved in git history at the tag php-legacy and remains deployed and
untouched on the shop's web server at
ubuntu@35.179.18.165:/home/ubuntu/containers/easyklima/apache_data/html/eks_relay
so a rollback is a webhook-URL change in Chatwoot, nothing more.
| Area | PHP relay | Node relay |
|---|---|---|
| Flowise auth | sent a literal Bearer *** placeholder |
sends the real FLOWISE_API_KEY, and only when one is configured |
| Idempotency | none — a webhook retry meant a second answer to the customer | ProcessedMessage unique on (source, messageId), plus a content-hash surrogate id when the payload carries none |
| Webhook timing | synchronous, waited up to 60 s for Flowise | persists a job, answers 202, worker does the work with retry/backoff |
| Spam | not implemented | rule-based gate in front of Flowise (bounces, autoreplies, newsletters, empty/attachment-only mail, automated senders, Auto-Submitted/List-Unsubscribe headers) |
| Ticket number | the bare conversation id | EKS-YYYYMMDD-<conversationId> |
| Ticket idempotency | re-read Chatwoot attributes only | local Ticket table keyed by conversationId and adoption of an existing Chatwoot ticket_number |
| Unassign/open on handoff | unassignConversation() existed but was never called; status was not normalized |
new_ticket now best-effort unassigns and sets the conversation status to open when CHATWOOT_UNASSIGN_ON_TICKET=true and CHATWOOT_OPEN_ON_TICKET=true |
| Ticket-mode check | label or handoff |
label, handoff, or a non-zero ticket_number |
| Health | none | /health and /ready with per-dependency status |
| Logging | wrote request bodies to a file, including PII | structured JSON, secrets always redacted, PII behind LOG_PII |
| Config | ad-hoc getenv |
zod schema; boot fails loudly, naming variables but never values |
| Message body | passed raw | quoted replies, signatures and HTML stripped before the LLM sees them |
| Tests | none | 86 tests: fixtures, spam rules, redaction, idempotency, queue, pipeline |
| Deployment | files in the shop's webroot | own container, own Traefik router, own domain, own logs |
The /tools/* request and response contracts are byte-compatible with the
deployed Flowise custom tools in flowise-tools/:
get_order_data still returns {ok, data, currency, currency_fallback?, currency_note?}
and still answers code: "UNAUTHORIZED" on an e-mail/order mismatch, which is
what drives the tool's [ORDER EMAIL MISMATCH] retry prompt.get_product_data still returns a single object or an array, so the tool's
kit-vs-single filtering and Number→ID mapping keep working.get_shipping_data still returns zones with ISO country codes when called
without zoneId, and {methods: [...]} from the WP endpoint when called with
one.get_payment_methods still degrades to 200 {ok:false, code:"NOT_IMPLEMENTED"}
rather than a 5xx when the Woo key lacks admin scope.get_product_compatibility keeps the WPML pre-resolution of a product name to
an id and the post-hoc title translation.new_ticket still returns {ok, ticketNumber, status}.The WPML/multicurrency behaviour (storeLocales.ts) is a direct port of
StoreLocales.php, including the EUR fallback and the note text.
https://eks-relay.easyklima.com, 2026-08-20.docs/SMOKE_TEST.md, steps 1–6.
Done — see the recorded run at the end of that document.info@easyklima.com.In the Chatwoot panel, change the bot/webhook URL from
https://easyklima.pl/eks_relay/public/index.php?__path=/webhooks/chatwoot
to
https://eks-relay.easyklima.com/webhooks/chatwoot
At the same time, point the Flowise tool variable $vars.relay_base at
https://eks-relay.easyklima.com — otherwise the agent's tools keep calling the
PHP relay while the webhook goes to the Node one. $vars.relay_shared_secret is
unchanged: the deployed .env reuses the PHP relay's RELAY_SHARED_SECRET.
Set the Chatwoot webhook back to:
https://easyklima.pl/eks_relay/public/index.php?__path=/webhooks/chatwoot
Nothing else needs undoing: the two relays share no state, and the Node relay's SQLite database is entirely its own.