Why this matters
- VaultCommerce's checkout, search, cache, and analytics layers have incompatible requirements; one database cannot serve them all without painful compromises.
- Production engineers debug consistency boundaries daily — knowing which store is source of truth prevents double-charge bugs.
- Interviews reward coherent multi-store designs with clear sync paths, not buzzword salads.
VaultCommerce data plane
Store map and ownership
- Postgres — users, orders, payments, inventory ledger (source of truth).
- MongoDB — product catalog with nested variants and marketing content.
- Redis — sessions, shopping carts, rate limits, hot product snapshots.
- Elasticsearch — full-text product search, autocomplete, faceted browse.
- Cassandra — clickstream, order-status events, analytics ingestion.
- Neo4j — recommendation graph and fraud relationship queries.
Source of truth and derived views
Every piece of data has one authoritative home. VaultCommerce never treats Elasticsearch as the inventory system — search indexes are rebuildable projections from Postgres and MongoDB.
// Order placement — single transactional boundary
@Transactional
public Order placeOrder(PlaceOrderCommand cmd) {
inventoryService.reserve(cmd.items()); // Postgres
paymentService.charge(cmd.payment()); // Postgres
Order order = orderRepo.save(cmd.toOrder()); // Postgres
eventPublisher.publish(new OrderPlaced(order)); // async fan-out
return order;
}
Downstream consumers update Redis cart eviction, Cassandra event logs, and Elasticsearch "sold count" facets — eventually, and idempotently.
Sync strategies
| Pattern | Mechanism | VaultCommerce use |
|---|---|---|
| Transactional outbox | Same DB transaction as business write | OrderPlaced events |
| CDC (Debezium) | WAL stream to Kafka | Catalog → search index |
| Cache-aside | App populates on miss | Product detail in Redis |
| Batch ETL | Scheduled bulk copy | Nightly graph edge rebuild |
Transactional outbox
MechanismSame DB transaction as business writeVaultCommerce useOrderPlaced eventsCDC (Debezium)
MechanismWAL stream to KafkaVaultCommerce useCatalog → search indexCache-aside
MechanismApp populates on missVaultCommerce useProduct detail in RedisBatch ETL
MechanismScheduled bulk copyVaultCommerce useNightly graph edge rebuild
Choose sync latency based on user-visible impact. Search can lag seconds; available inventory cannot.
Consistency across boundaries
There is no global ACID transaction spanning Postgres and Elasticsearch. VaultCommerce uses sagas, idempotent consumers, and compensating actions:
happy_path:
- reserve_inventory (postgres)
- charge_payment (postgres)
- emit OrderPlaced (outbox)
downstream:
- clear_redis_cart
- append_cassandra_event
- update_search_sold_count
failure_handling:
- payment_failed → release_inventory
- search_lag → serve stale facets with banner
| Aspect | Single database | Polyglot persistence |
|---|---|---|
| Complexity | Lower ops surface | Multiple failure modes |
| Fit | One access pattern dominates | Many specialised hot paths |
| Consistency | Single ACID boundary | Per-store + eventual sync |
| VaultCommerce | Day-one MVP only | Current production architecture |
Complexity
Single databaseLower ops surfacePolyglot persistenceMultiple failure modesFit
Single databaseOne access pattern dominatesPolyglot persistenceMany specialised hot pathsConsistency
Single databaseSingle ACID boundaryPolyglot persistencePer-store + eventual syncVaultCommerce
Single databaseDay-one MVP onlyPolyglot persistenceCurrent production architecture
Quick recall
Everything you need if you only revisit this box.
- Polyglot persistence assigns each access pattern its best engine.
- VaultCommerce: Postgres for money, MongoDB for catalog, Redis for speed, Elasticsearch for search.
- One source of truth per entity; everything else is a derived projection.
- Sync via outbox, CDC, or cache-aside — never fragile dual writes.
- Accept eventual consistency at integration boundaries; keep ACID where money moves.
Test yourself
Answer these before moving on — recall is what makes it stick.