ADR-002: Use PostgreSQL as the product system of record
Product data is stored in a single PostgreSQL database that acts as the authoritative system of record, with derived stores (like the search index) rebuilt from it.
Context
Products are a small-to-medium, strongly relational dataset (products, categories, pricing, lifecycle status) that needs transactional integrity, an enforceable schema, and the ability to write a change and its outbox event atomically. We also want a single, unambiguous source of truth so that derived stores — such as the Search SystemSearch SystemSystemv1.0.0Internal system that keeps product data searchable. Consumes product change events from the Product Catalog System, main...Ownersearch-platformMapView docs‘s index — can be treated as disposable and rebuilt at any time.
Decision
The Product Catalog System uses a single PostgreSQL database, the Product DatabaseProduct DatabaseContainerv1.0.0PostgreSQL database that is the system of record for all product data.MapView docs, as the authoritative system of record. It holds the
products table and the outbox table (see ADR-001: Publish product events via a transactional outboxADR-001: Publish product events via a transactional outboxDecision Recordv1.0.0Product change events are written to an outbox table in the same transaction as the change, then relayed to the broker, ...Ownerproduct-platformView docs). The Product APIProduct APIServicev1.0.0The public-facing API for the product catalog. Handles commands to create, update and delete products, serves product re...Subscribescreate-product, update-product +2APIsOpenAPIOwnerproduct-platformMapRepoView docs is the only writer on the request path; the Product WorkerProduct WorkerServicev1.0.0
Background worker that handles long-running and asynchronous catalog work off the request path, such as enrichment, imag...Ownerproduct-platformMapRepoView docs performs asynchronous enrichment.
Any other representation of product data elsewhere in the business is a derived read model, not a source of truth, and must be rebuildable by replaying product events.
Consequences
- Strong consistency and transactional outbox writes are straightforward with a single relational store.
- The search index and any future read models can be rebuilt from the catalog, keeping them disposable.
- The database is a scaling focal point; heavy read traffic should be served from read replicas or downstream read models rather than the primary.
- Schema changes need migrations and care, since this is the authoritative store.