Microservices Decomposition¶
1. Purpose¶
The decomposition follows the bounded contexts in the domain model. It maps each bounded context to a service. The services are independent deployables from day one (ADR-007); their technology is recorded in the technology stack.
2. Domain-to-service map¶
The gateway and measurement pipeline are architectural components, not bounded contexts. The other services map directly to one bounded context.
3. Mapping¶
| Domain boundary | Target service | Owns |
|---|---|---|
| Product Passport | passport-service | Resolver, Product Catalog, ScanRecords, Resolved Passport assembly and source adapters |
| Personalization & Verdict ★ | personalization-service | HealthProfile, VerdictService, screening policies and personalized Alerts |
| Fridge | fridge-service | Fridge aggregate, FridgeItems, freshness and waste projections |
| Identity & Consent | identity-service | VisitorIdentity, Account, consent ledger, Brand and BrandUser |
| Brand Analytics | brand-analytics-service | Tenant-scoped aggregate read models and dashboard queries |
| Public edge (not a bounded context) | api-gateway | Routing and access to the services |
| Privacy pipeline (not a bounded context) | measurement-pipeline | Raw consumer-side measurement facts and minimum-group-size aggregation |
Verdict remains inside personalization-service because it is part of the
Personalization & Verdict bounded context.
The measurement pipeline remains separate from brand-analytics-service because raw
consumer facts must be aggregated before crossing the privacy wall.
4. Data ownership¶
Each extracted service owns its data. Other services use IDs, APIs or events; they do not read another service's tables.
| Owner | Private data store | Important records |
|---|---|---|
passport-service |
Passport database | ProductCatalogEntry, ScanRecord, source cache |
personalization-service |
Encrypted personalization database | HealthProfile, rule sets |
fridge-service |
Fridge event store + projections | Fridge event streams, freshness and waste projections |
identity-service |
Identity database / managed auth integration | VisitorIdentity, Account, consent ledger, Brand, BrandUser |
measurement-pipeline |
Short-retention consumer-side measurement store | Raw measurement facts and aggregation windows |
brand-analytics-service |
Analytics read store | Minimum-group-size, tenant-scoped metric batches |
A single PostgreSQL instance hosts these logical stores as one schema per service, but ownership remains exclusive: each service connects with its own database role, GRANT-restricted to its schema, so isolation is enforced by the database rather than by convention (ADR-009).
5. Shared tenant seed (development)¶
The Brand aggregate lives in the identity schema; brand-owned records elsewhere reference it by id only, since cross-schema constraints are impossible by design (ADR-009). Development seeds therefore share one fixed list of demo-Brand UUIDs — any seed that attributes data to a Brand must use these:
| Brand | UUID |
|---|---|
| Bergbauer | b0000000-0000-4000-8000-000000000001 |
| NaturPur | b0000000-0000-4000-8000-000000000002 |
| HavreGård | b0000000-0000-4000-8000-000000000003 |
| Delizia | b0000000-0000-4000-8000-000000000004 |
Used today by services/passport-service/migrations/0002_seed_catalog.sql (13
products, including the web app's three mock GTINs) and by the identity-schema
brands seed in
services/identity-service/src/adapters/postgres/migrations/0004_seed_brands.ts
(the two seeds must agree by convention, since ADR-009 rules out a cross-schema FK).