Case study
- My role
- I built the middleware following the architecture and guidelines of Giuseppe Guarino at Ride On, who designed it: export parsing, the queue, delivery to Klaviyo and deployment, plus the data checks with Malo and the tests with Klaviyo support.
- Duration
- June to October 2026
The problem
Malo, the Italian cashmere brand, sells online on Shopify and in 18 boutiques. Online orders already reached Klaviyo through the native integration, in-store ones did not: to the predictive analytics, someone who only shopped in a boutique looked like an inactive customer. The stores' management system exports orders and profiles to a shared folder, most receipts carry no email or phone, and the first run had to load twelve years of history.
What I did and why
- On Giuseppe's architecture, a SQLite queue on a single VM: each file read from the shared folder becomes one row per order or profile, holding keys and state but not the content, which the worker rebuilds from the archived file when it sends. No cloud services to run.
- No duplicates, even on a re-read: deduplication per file and per order, a stable unique_id in Klaviyo, and a customer's orders sent in sequence after their profile. A file read twice or a repeated send never creates anything twice.
- Personal data stays inside the process: emails and phone numbers sit in the queue only as hashes, logs and telemetry carry no customer data, keys and credentials are redacted.
- Online and in-store in the same predictions: an event sent through the API cannot write into Shopify's metric, which I verified with tests on the test account and confirmed with Klaviyo support. The answer is a custom conversion metric that combines both channels and feeds each profile's predictions.
- Consent and collections ready for marketing: consents collected in store reach the profile, a subscription happens only when there is a consent date, with separate lists per language. Each product gets the Shopify collections of its SKU, so segments work the same online and in store.
- A service that runs on its own: a systemd daemon with a watchdog, immutable releases with an installer, an offline preflight, a read-only status command, events and exceptions in PostHog, and sends paced to Klaviyo's rate limit, waiting out 429s.
Results
- 99,386in-store orders since 2014, imported with no errors
- 18boutiques connected
- 8 sto import the full history, 2,069 files
- 0emails or phone numbers in clear in the queue and logs
- 0duplicates when the same file is read again
- 262automated tests
Stack highlights
- Node.js
- Typescript
- SQLite (better-sqlite3)
- Zod
- Klaviyo API
- pino
- systemd
- PostHog
When the boutiques' management system drops new files into the shared folder, the middleware reads them, discards invalid records, queues profiles, orders and refunds, and sends them to Klaviyo at the pace the API allows. The receipt lands on the customer's timeline next to their online orders, with amounts, products, boutique and Shopify collections, and through the combined metric it counts towards their spend and repurchase predictions. The CRM team segments on one whole customer, not two halves.
What I bring to an agency or a small business from this project
- Data integrations that hold up in the awkward cases: files read twice, repeated sends, API limits, incomplete data.
- The data format checked against the real files, record by record, with the inconsistencies taken to whoever produces the export, examples included.
- A backend service delivered with an installer, monitoring and diagnostics, not just the code.