Key Flows
These sequence diagrams describe current orchestration, cross-checked against the public and
internal contracts in 'services//openapi.yaml'. OpenAPI defines interfaces; the service
implementation defines call order, timeout and fallback behavior.
The diagrams show the accepted consumer flows. The separate event-driven analytics path is
documented in Event Sourcing:
the measurement pipeline aggregates Kafka facts and Brand Analytics serves the resulting
read model.
1. Anonymous Scan
sequenceDiagram
actor Consumer
participant Web as Consumer Web App
participant Gateway as API Gateway
participant Passport as passport-service
participant Catalog as Producer Registry / OFF Cache
participant Journey as Journey Source
participant Recipes as Recipe Source
participant Broker as Kafka
Consumer->>Web: Scan GS1 Digital Link
Web->>Web: Decode GTIN<br/>(or preserve Digital Link qualifiers)
Web->>Gateway: POST /api/v1/scans
Gateway->>Passport: Create anonymous scan with Visitor ID
Passport->>Catalog: Resolve producer projection or OFF cache
Passport->>Passport: Save ScanRecord
Passport-->>Broker: ProductScanned
Passport->>Journey: Resolve journey by GTIN and optional lot
Journey-->>Passport: Loaded or unavailable
Passport->>Recipes: Find recipe suggestions
Recipes-->>Passport: Loaded or unavailable
Passport-->>Gateway: Complete ResolvedPassport<br/>with per-section states
Gateway-->>Web: Base passport + unauthenticated verdict<br/>+ journey/recipe states
Web-->>Consumer: Show result
The in-memory producer registry or persistent Open Food Facts community cache supplies the base
product. Producer synchronization is independent of scans. Verdict, Journey and Recipes are
resolved synchronously and sequentially before the response; a failed optional dependency changes
only its section state. The current implementation does not return pending sections or require
client polling.
When the consumer uses a camera app instead of the in-app scanner, the flow starts
at the Resolver route instead: the browser opens
GET /01/{gtin}/…; the gateway has passport-service parse the path and create the
same scan, then redirects the browser to the result page. Processing from
Resolve producer projection or OFF cache onward is identical.
2. Personalized Scan
sequenceDiagram
actor Consumer
participant Web as Consumer Web App
participant Gateway as API Gateway
participant Passport as passport-service
participant Personalization as personalization-service
participant ProfileDB as Personalization DB
participant Rules as Configured Rule Provider
participant Journey as Journey Source
participant Recipes as Recipe Source
participant Broker as Kafka
Consumer->>Web: Scan GS1 Digital Link
Web->>Gateway: POST /api/v1/scans with bearer token
Gateway->>Passport: Create scan with Account reference
Passport->>Passport: Resolve catalog entry and save ScanRecord
Passport->>Personalization: POST /internal/v1/verdicts<br/>Account ref + Digital Label
Personalization->>ProfileDB: Load HealthProfile
Personalization->>Rules: Load versioned rule set
Personalization->>Personalization: Compute Verdict and goal-fit
Personalization-->>Broker: VerdictComputed
Personalization-->>Passport: Verdict
Passport->>Journey: Resolve Journey
Journey-->>Passport: Loaded or unavailable
Passport->>Recipes: Resolve Recipes
Recipes-->>Passport: Loaded or unavailable
Passport-->>Broker: ProductScanned
Passport-->>Gateway: ResolvedPassport + Verdict
Gateway-->>Web: Scan result
Web-->>Consumer: Show Verdict first
The Health Profile remains inside personalization-service; Passport receives only the
computed Verdict. Journey and Recipe failures remain section-local, and a Personalization timeout
returns a verdict_unavailable section rather than failing the scan.
3. Add to Fridge
sequenceDiagram
actor Consumer
participant Web as Consumer Web App
participant Gateway as API Gateway
participant Fridge as fridge-service
participant Passport as passport-service
participant FridgeStore as Fridge Event Store
participant Broker as Kafka
Consumer->>Web: Add scanned item to Fridge
Web->>Gateway: POST /api/v1/me/fridge/items<br/>{ scanId }
Gateway->>Fridge: Add item for authenticated Account
Fridge->>Passport: GET /internal/v1/scans/{scanId}/item
Passport-->>Fridge: Trusted ScannedItem + passport snapshot
Fridge->>Fridge: Check physical-item uniqueness
Fridge->>FridgeStore: Append ItemAddedToFridge
Fridge-->>Broker: ItemAddedToFridge
Fridge-->>Gateway: Created FridgeItem
Gateway-->>Web: 201 Created
Web-->>Consumer: Show item in Fridge
Only scanId comes from the client. The Fridge obtains trusted GTIN, serial, expiry and
display data from passport-service.