ADR-010: Input/Output Value Object Separation (PricingRule β AppliedCondition) β
Status: β Approved β 2026-04-10 Origin: Kalkulations-Engine ProtocolImpacts:
PRODUCT_domain-model.mdΒ§Embedded Value Objects,schema-backoffice.mdΒ§price_matrices
Context β
The domain model defined a PricingCondition VO embedded in PriceMatrix.variants[]. This VO attempted to serve two incompatible purposes:
- Input β defining what pricing rules exist (demographics, seasons, early-bird tiers)
- Output β recording how the engine applied those rules to produce a specific variant's price
The result was three vague fields (type, value, validity_period) with no enums, no format contract, and no clear semantics. A coding agent reading PricingCondition cannot determine whether they are looking at a rule template or a resolved computation result.
Meanwhile, PricingRule (the input VO on TourTemplate) already had a well-specified design. Season and early-bird rules had no dedicated input VO at all β they implicitly lived in an undefined pricing configuration.
Decision β
1. Retire PricingCondition β
This ADR removes the PricingCondition VO from the domain model and replaces it with AppliedCondition, a pure output VO that records the audit trail of each computation step.
2. Input VOs (templates β what rules exist) β
| VO | Embedded In | Purpose |
|---|---|---|
PricingRule | TourTemplate.pricing_rules[] | Demographic discounts (operator-defined segments with percentage/absolute adjustments). Unchanged. |
SeasonConfig | TourTemplate.pricing_config | Seasonal tier definitions (key, label, date periods, absolute surcharge). New. |
EarlyBirdTier | TourTemplate.pricing_config | Early-bird stepped discount tiers (key, label, day-range boundaries, percentage discount). New. |
PricingConfig | TourTemplate.pricing_config | Container VO: room_surcharge, includes_accommodation, season_config[], early_bird_config[]. New. |
3. Output VO (resolved β what the engine applied) β
| VO | Embedded In | Purpose |
|---|---|---|
AppliedCondition | PriceMatrix.variants[].applied_conditions[] | Per-step audit record: condition type, label, adjustment method, configured value, applied amount, running gross, validity window. |
AppliedCondition uses a fixed enum: DEMOGRAPHIC_DISCOUNT | ROOM_SURCHARGE | SEASON_SURCHARGE | EARLY_BIRD_DISCOUNT, applied in this exact priority order.
4. Naming Convention β
- Input VOs use domain-noun names:
PricingRule,SeasonConfig,EarlyBirdTier,PricingConfig - Output VOs use past-participle names:
AppliedCondition
This convention makes the read direction unambiguous: if it has "Applied" or "Resolved" in the name, it is engine output.
Consequences β
Positive:
- Clean separation of template (mutable, editable) from computation result (immutable, auditable)
- Each VO has a single responsibility β no more overloaded fields
- New input VOs (
SeasonConfig,EarlyBirdTier,PricingConfig) fill specification gaps that blocked implementation AppliedConditionprovides a full derivation chain for dispatcher transparency
Negative:
- Maintainers must update or remove
PricingConditionreferences in any existing documentation - More VOs to maintain (4 input + 1 output vs. the previous 2)
Neutral:
PricingRulestays the same β no migration impact for demographic rules