Shashank H RBackend Engineer
all systems operational--:--:-- IST
← Back to workCase study 04 / 04

Engati · Internship · full stack

Abandoned-cart recovery

High-intent shoppers who leave a Shopify store get a personal nudge to come back: a branded link, and a discount if the store offers one. I designed and shipped it end to end as an intern, in one to two sprints.

Role
Built it end to end (intern)
Stack
Shopify Liquid · Spring Boot @Async · Shopify GraphQL · DuckDB · Kafka
Timeline
1–2 sprints
Status
● shipped
1–2 sprintsfrom design to production
3 lookupsour DB → Shopify GraphQL → DuckDB
2 servicesproduct-discovery · shopify-consumer
Full stackstorefront popup to the shopper’s phone

(01) The problem

A store can only win back an abandoned cart if it can reach the shopper. Shopify doesn’t share a customer’s details across stores, so someone new to one store is often unknown there, even if they have ordered elsewhere.

(02) How it works

shopify popuptheme.liquid CTAproduct-discoveryvalidation checks@Async taskstore config checks1 · our databaseshopper by email2 · shopify graphqlcustomer in this store3 · duckdb parquetarchived orders, any store: email → phonekafkakeyed by user_idshopify-consumer-svcpayload · discount · short linkurl shortenerengati-branded linkmessaging pipeline→ the shoppernot foundnot foundshorten1234567
  1. The shopper enters their phone number in a CTA popup on the Shopify store, built with theme.liquid.
  2. The product-discovery-service runs validation checks and hands off to an @Async task.
  3. The async task checks the store’s Shopify integration and configuration, then looks the shopper up by email: our database first, then Shopify’s GraphQL API for that store.
  4. Last fallback: the archived-orders parquet in DuckDB, across every store. It pulls all matching records and extracts the phone number, even when it wasn’t in the shipping details.
  5. The result is pushed to Kafka, keyed by user_id.
  6. The shopify-consumer-service builds the payload, applies any discount configured on the portal, and turns the store link into an Engati-branded short URL with our in-house shortener.
  7. The message goes out through Engati’s existing messaging pipeline.

(03) Key decisions

Three places to look

Shopify can’t see across stores, so the lookup falls back from our database, to Shopify’s GraphQL API, to archived orders in DuckDB that span every store.

Async at every hop

Validation happens up front; store checks and lookups run in an @Async task, and the hand-off to messaging goes through Kafka.

Keyed by user_id

Kafka messages are keyed by user_id, so everything about one shopper lands on the same partition, in order.

(04) Results

  • Designed, built and tested end to end in one to two sprints, as an intern.
  • Shoppers new to a store can still be reached, thanks to the cross-store DuckDB lookup.
  • Learned design patterns like adapter and factory along the way.
I worked days and nights to test it end to end. It was a lot of fun, and I learned a lot.