RLRoman Levchenko
WorkHow it's builtAI workflow
Get in touch
← All work

W03 / Case study

Search you can trust on a live-commerce platform

A lean search index kept consistent by domain events, a Shopify app moved off legacy serverless code, and dead fields removed only after proving they were unused.

Client
A multi-brand live-shopping platform, under NDA
Role
Senior full-stack engineer: platform API, search, event pipeline, Shopify app
Period
2025 — now
Stack
  • NestJS
  • Angular
  • Shopify
copied fields left in the search index to go stale
0
test files I added across the platform
600+
platform API behind the Shopify app, legacy code retired
1

01 / Context

Context

A multi-brand live-shopping platform: brands publish shoppable video content on their own storefronts and run live sessions with chat and an in-session cart. It ships a Shopify app and an embeddable SDK on top of a shared platform API.

02 / Problem

Problem

Search results drifted from the source data. The index carried copies of fields that changed elsewhere, such as display names, so renames left stale results behind. At the same time the Shopify app still ran on legacy serverless functions that duplicated platform logic.

03 / Architecture

Architecture

AppsPlatformWritesProcessingSearchStorefront appsweb app, embeddable SDKShopify appwebhooks, catalog syncPlatform APINestJSDatabasesystem of recordDomain eventsmessage busEvent processorupdates the indexSearch indexranking, facets, totals
  1. Storefront apps — web app, embeddable SDK
  2. Shopify app — webhooks, catalog sync
  3. Platform API — NestJS
  4. Database — system of record
  5. Domain events — message bus
  6. Event processor — updates the index
  7. Search index — ranking, facets, totals

The index ranks and counts; the database holds the bodies. Events keep the two in step.

04 / Key decisions

Key decisions

  • Rank in the index, hydrate from the database

    The search index answers ranking, facets and totals; the item bodies come from the database. The index stays lean and holds nothing that can go stale.

    Trade-off Every search does a second read to hydrate results.

  • Index sync driven by domain events

    I rewrote the sync from the database to the index around domain events and dropped every field that couldn't be kept consistent.

    Trade-off More event traffic: every change that affects search triggers an index update.

  • Shopify app moved onto the platform API

    Install-time catalog sync and product webhooks now go through the platform's own API, with a mapped legacy-versus-current flow so old code could be deleted safely.

    Trade-off A short period of running two backends side by side.

  • A backfill without a new index

    One streamed query with filtering in code, instead of adding a database index for a one-off job.

    Trade-off Some logic is duplicated, guarded by an assert self-check.

  • Delete fields only with proof

    Unused fields were removed only after scanning all production data and finding no writers and no values.

    Trade-off A slower clean-up than deleting on sight.

05 / Hard problems

Hard problems

  1. Two stores, one truth

    Keeping a database and a search index consistent under renames, deletes and re-links, without a nightly rebuild.

  2. Shopify edge cases

    Shops with several domains and URL variants, and a billing change shipped as a one-shot migration with a runbook.

  3. A safe backfill

    Bringing every existing record into a new state model in one pass, without downtime or a temporary index.

06 / How it was built

How it was built

My own agent setup around the repo: an index-only CLAUDE.md that routes to per-area rules, a domain glossary, a legacy-versus-current flow map, custom builder and reviewer subagents, and written specs and plans with session handoffs. I also integrated the platform SDK, live sessions and cart sync into partner storefronts built with Next.js and React Native.

← PreviousA real-money prediction market, built end to endNext →One deployment, many artist storefronts

© 2026 Roman Levchenko · Warsaw, EU

Built with Next.js, NestJS and Postgres on Railway. See how it's built

  • LinkedIn
  • GitHub
  • Upwork