MIGRATION.md 4.7 KB

Migration: PHP relay → Node.js/TypeScript relay

Status

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.

What changed, and why

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 on handoff unassignConversation() existed but was never called called when CHATWOOT_UNASSIGN_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

What deliberately did not change

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.

Migration order

  1. Deploy the Node relay to its own domain; leave PHP running. Donehttps://eks-relay.easyklima.com, 2026-08-20.
  2. Verify with docs/SMOKE_TEST.md, steps 1–6. Done — see the recorded run at the end of that document.
  3. Point the Chatwoot webhook at the Node relay and run a real e-mail test (step 7). Not done — repointing the webhook changes live behaviour, so it is left as an explicit decision.
  4. Only then consider the production inbox info@easyklima.com.
  5. Retire the PHP deployment once the Node relay has run clean for a while.

Switching the webhook

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.

Fallback

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.