The Data Platform
Rebuilt how customer and order data flows through the company โ from data arriving days late to sub-minute freshness, across 200+ merchant stores on five e-commerce platforms. Every downstream product runs on this.
Node.js ยท MySQL ยท Debezium ยท Google Pub/Sub ยท Datastream ยท MongoDB ยท BigQuery ยท ClickHouse ยท Redis ยท GKE
My Role
Context
ConvertCart serves 200+ e-commerce merchants across five platforms (Shopify, BigCommerce, WooCommerce, Magento 1, Magento 2). Customer data, orders, click-tracking, and loyalty data all flow through separate systems with no unified schema. Downstream products (recommendations, segmentation, attribution) need to access this data, but latency and availability are unpredictable.
Problem
Data arrives days late. Commerce webhooks provide near-real-time events, but custom platform integrations require full data downloads every 6 hours. Click-tracking and loyalty data are even slower. Downstream products can't build real-time features. Reporting is expensive because queries have to reprocess data constantly. New products need to build custom integrations instead of tapping a shared stream.
- 6+ hour batch delays
- Custom integrations per product
- Expensive BigQuery reporting
- No unified data model
- Real-time recommendations impossible
- Segmentation used stale data
- Attribution couldn't link orders to blocks
- Every new feature required engineering
Architecture
Consolidates four source systems (commerce, click-tracking, loyalty, CRM) into a raw MySQL landing store, preserving original schema. Debezium streams changes via Google Pub/Sub. Downstream layer fans out to three specialized stores: MongoDB for point lookups (serving), ClickHouse for analytics, BigQuery for historical data.
โ
MYSQL LANDING LAYER (raw, normalized per source)
โ
DEBEZIUM CDC โ PUB/SUB
โ
โโโโโโโโโโโโโโโโโคโโโโโโโโโโโโโโโโคโโโโโโโโโโโโโโโโ
โ MONGODB โ CLICKHOUSE โ BIGQUERY โ
โ (serving) โ (analytics) โ (historical) โ
โ point lookups โ aggregation โ audit trail โ
โโโโโโโโโโโโโโโโโงโโโโโโโโโโโโโโโโงโโโโโโโโโโโโโโโโ
New sources plug into the landing layer. New consumers subscribe to Pub/Sub. No custom integrations required.
Key Decisions
- Landed raw instead of normalizing at ingest
Costs: five schemas instead of one. Benefit: reversibility. Wrong normalization at ingest means multi-service migration. Wrong materialized view is a redefinition away from correction. - CDC from landing store, not sources
Costs: one more moving part. Benefit: single source of truth that can't diverge from actual data. - Two replication paths (Datastream + Debezium)
Started with managed Datastream, gradually earned our way to pure Debezium. Avoided speculative engineering while managing risk. - Table-per-client multiplies operational surface
Thousands of tables, migrations run across all. Accepted because shared-table contention is worse and less visible than operational overhead.
Execution
Migration Strategy
Store-by-store cutover because the data layer sits under every product. Bad cutover breaks all of them simultaneously. Slow but safe.
Backfill & Validation
Dual-write to both old and new landing layer for 2 weeks. Ran hourly checksums across all tables. Validated row counts, key distributions, timestamp ranges. Only switched when checksums matched 100%.
Rollback Strategy
Kept old pipeline running for 30 days after cutover. If anything broke, could revert to old data. Never had to use it, but reduced risk psychologically and operationally.
Monitoring & Alerting
Added metrics for data freshness (time from source to landing to serving), lag per store, checkpoint latency. Alerts on 5-minute latency deviation. Page on-call for >15 min delays.
The 50M-Row Snapshot Problem
When Debezium tried to snapshot the landing store: query hit 60% CPU, blocked production writes, unacceptable. Solution: leveraged existing Datastream snapshot, then switched to CDC incrementally per table. This became the dual-replication strategy above.
Impact
Why It Mattered
- Real-time recommendations became possible. Merchants could see recommendations update within seconds of customer actions.
- Conversion attribution could link orders to specific blocks and email clicks โ what proved to merchants that recommendations were actually working.
- Segmentation worked with fresh data. Audiences updated in minutes, not hours.
- Reporting moved off a cost curve that scaled with query volume onto one the team controlled.
Scale
- 200+ stores ยท 5 platforms ยท 98%+ uptime ยท zero visibility loss during 3-month migration
- New sources (Klaviyo, Zendesk) plugged in as streaming integrations, not custom pipelines
- Complete migration off legacy architecture within 3 months, zero rollbacks
What I'd Change Today
What I'd Preserve
- Raw landing layer (reversibility principle held)
- CDC at the landing store, not sources (single source of truth)
- Table-per-tenant for isolation (multi-tenant contention is worse than ops cost)
What I'd Change
- Datastream โ pure Debezium from day one. Datastream was our transition strategy; we could have earned off it faster. Debezium proved itself in production.
- Consider separate CDC per domain. Commerce CDC vs. click-tracking CDC would reduce blast radius of unplanned events.
- โEvaluate Iceberg for analytics layer. Wasn't production-ready at the time; would simplify the architecture today.