Skip to content

[Design 1] When a Product Changes, Preserve the Patient's Promise: Product Versions and Purchase Snapshots

Small robotic builders connect product v1 and v2 cards, a purchase snapshot, a plan revision, and a confirmed visit promise on one time axis
Publishing a new product and changing a patient’s purchased visit promise are different operations. Protect the purchase-time contract and the facts already confirmed first.

When the product team changes a product, the reservation service has a question to answer before it looks at a calendar:

May the new product definition be applied directly to a patient who already purchased the old one?

Suppose Patient A buys an event product, an N-visit product, and a package product at one clinic. The product team publishes the same product family as v2. New purchases may use the new definition. But if the service expands A’s v1 treatment items and remaining visits from the current catalog, the reservation service has silently changed the patient’s purchase contract.

Idempotency is not this article’s main conflict. The main question is what stays protected, and what may still be negotiated, when a product version changes. A repeated purchase event appears only as a short technical guardrail near the end.

Patient A’s timeline: a purchase is not yet a visit promise

Section titled “Patient A’s timeline: a purchase is not yet a visit promise”

We generalize the product name, price, clinic, and personal information. Only the scheduling meaning remains.

TimePatient A action or eventProduct and purchase meaningWhat the reservation service preserves
T1Buys an event productOne right to use within a validity windowSource purchase ID and the purchase-time catalog v1
T2Adds an N-visit productAn obligation fulfilled across several visitsPer-visit PlannedTreatment and repeat intervals
T3Buys a package productA product BOM with several items, dependencies, and resourcesPer-item version provenance and dependencies
T4Completes some items while others remain future workPast facts split from pending obligationsCompletion facts, remaining items, and the current Plan revision
T5The product team publishes catalog v2The contract for later purchases changesThe v1 snapshot and the v2 projection together
T6A migration mapping and consent arrive for the existing purchaseAn exceptional change to future obligationsA new revision plus mapping and consent evidence
T7The migration would change the schedule, or A declines itA product change and a visit change are separate workThe confirmed visit and an objective CRM/counseling handoff

These purchases must not collapse into one appointment row. One use of an event product, the third visit in an N-visit product, and one package item have different remaining obligations and dependency rules. Items from several purchases may be grouped into one visit, but the agreed AppointmentItems and each purchase’s Plan remain separately traceable.

A purchase is the commercial fact of what the patient bought the right to use. A Plan is the reservation service’s interpretation of that purchase as executable obligations. A confirmed visit is a promise to perform specific items with specific time and resources. Treating all three as one record lets a catalog change overwrite a past promise.

A product version is a purchase-time contract, not sales copy

Section titled “A product version is a purchase-time contract, not sales copy”

The product projection stored by the reservation service is not an arbitrary copy that it is free to rewrite. The current ProductCatalogDefinition treats the source product service’s catalogVersion, BOM items, repeat counts, treatment duration, resource capabilities, and dependencies as one immutable definition. An ACTIVE projection can create a new Plan; a RETIRED projection remains available only for reading historical Plans.

A purchase-completed event does not need to repeat the whole price sheet. The minimum input the reservation service must reproduce includes sourcePurchaseAuthority, sourcePurchaseId, productId, catalogVersion, and bookingPreference from PurchaseCompletedEvent. When it creates the Plan, it joins that purchase source of record and protected patient reference to the purchase-time catalog payload hash.

AppointmentPlanFactory expands each catalog BOM item into PlannedTreatments according to repeatCount and preserves dependencies. It does not confirm a visit time. The absence of a customer preference is not a command to confirm automatically.

A Plan and the visit-promise flow built from it therefore need to retain at least this timeline:

  • Which source purchase ID and source service created it
  • Which product family and catalog version it used
  • Which payload hash, BOM items, repeats, and dependencies were interpreted
  • Which booking preference arrived with the purchase, and which policy snapshot informed a proposal
  • Which Plan owns later revisions and confirmed visits

This snapshot is not a customer-facing copy of a price card. The product team and commerce service own the source product. The reservation service preserves the minimum execution contract needed to reproduce this purchase’s scheduling obligations.

Event, N-visit, and package products become different Plans

Section titled “Event, N-visit, and package products become different Plans”

A product type expressed only as a number of calendar appointments loses the business rule.

Product typeWhat remains in the PlanThe reservation question
Event productOne PlannedTreatment from repeatCount 1, a validity window, and booking rulesWhich date and resources can fulfill this benefit?
N-visit productPer-visit PlannedTreatments with minimum, preferred, and maximum intervalsDoes this visit respect the previous one, and how many remain?
Package productItem-level product BOM, selections, dependencies, and visit groupingWhich items fit this visit, and which must remain future work?

A package is especially difficult to reduce to “one product equals one appointment.” The current PackageExecutionPlanner validates exact component versions, expanded execution items, dependency relations, and visit-grouping constraints provided by the execution source. Missing provenance or a cycle in the dependency graph rejects the whole input rather than silently dropping part of it.

Purchase completed event
└─> One AppointmentPlan per purchase
├─ Event product: one PlannedTreatment
├─ N-visit product: PlannedTreatment 1..N
└─ Package: items + dependency/DAG + visit grouping

This structure also prevents a common overreach: “the patient bought three products, so reserve every possible future slot.” A Plan preserves obligations. It does not mean that the reservation service occupies every future resource. Only the items with an agreed time, resource, and consent become confirmed visits.

When catalog v2 is published, do not re-expand the existing Plan

Section titled “When catalog v2 is published, do not re-expand the existing Plan”

Publishing v2 creates two paths.

TargetDefault treatmentWhy
A customer who has not purchased yetThe new purchase event points to catalog v2v2 is a new commercial contract, so the new Plan snapshots v2
Patient A who already purchased v1The existing Plan and revisions remain v1The purchase-time right and obligation are not reinterpreted from the current catalog
An exceptional change to an existing purchaseA new revision after explicit mapping and consentAn existing-contract change is not the same flow as a new contract

The timeline below makes the split visible. The v1 purchase retains completed and confirmed facts. Publishing v2 separates a new purchase from a proposed migration of the existing purchase. Future items in the existing purchase do not move automatically; they enter a new revision only after approval and consent.

Catalog v1 fixes Patient A's purchase snapshot and v1 Plan while completed and confirmed facts stay protected; catalog v2 branches into a new purchase and explicit migration approval, consent, a new Plan revision, and a CRM handoff
Publishing product v2 does not redeploy the existing Plan. New purchases start on v2, while future items in an existing purchase may move only through explicit mapping and patient consent.

Separate completed facts from work that is still negotiable

Section titled “Separate completed facts from work that is still negotiable”

The most dangerous phrase in a product migration is “convert the remaining product.” Remaining work can include something already performed, something confirmed but not yet visited, and something that has not even been proposed.

The current AppointmentPlanModel distinguishes PLANNED, SCHEDULED, IN_PROGRESS, COMPLETED, CANCELLED, and BLOCKED_REVIEW treatment states. The smaller product-version migration model separately validates PENDING, COMPLETED, and CANCELLED. The names differ because the models serve different decisions; the rule is the same: separate past facts and confirmed promises from future obligations that can still be negotiated.

Plan or visit stateDefault after v2 is publishedWhat it means for Patient A
COMPLETEDRetain the old revision and old version provenanceDo not rewrite an already delivered service under a later definition
IN_PROGRESSProtect the current execution and clinical factDo not undo an action already underway because the product was revised
An item linked to a CONFIRMED visitProtect the promise, policy snapshot, and resource agreementDo not cancel the agreed time and item automatically
PLANNED or PENDING future workCandidate for a new revision only with approved mapping and consentOnly work not yet promised is open to negotiation
CANCELLEDRetain the cancellation or refund factDo not resurrect a cancelled obligation because v2 exists

ProductVersionMigrationPlanner rejects a mapping that includes a completed source, requires every PENDING source to be explained exactly once, and requires unique target treatment keys. Similar names are not evidence that two obligations are the same.

The exceptional path for applying v2 to an existing purchase

Section titled “The exceptional path for applying v2 to an existing purchase”

If the product team must apply v2 to Patient A’s existing purchase, the reservation service does not guess the correspondence. The product team creates the target-version mapping and consent evidence, then sends the approved migration fact to the reservation service.

The current ProductVersionMigration model distinguishes six mapping types:

MappingSource → targetMeaning for Patient A
KEEP1 → 1Retain the same future obligation under a v2 item key
REPLACE1 → 1Replace an unfinished item with another v2 item
SPLIT1 → 2 or moreDivide one future obligation into several execution items
MERGE2 or more → 1Combine several future obligations into one new execution item
REMOVE1 or more → 0Remove an unfinished obligation from the new revision
ADD0 → 1 or moreAdd a new obligation without an existing source

For example, imagine that A’s package contains two items not yet started and one completed item. The product team may SPLIT one future item into two v2 items and KEEP the other. The completed item is left out of the mapping. Putting the completed item under REMOVE would confuse “not shown in the new revision” with “erase the completed fact.”

After approval, ProductVersionMigrationHandler follows this sequence:

  1. Lock the source purchase and its active revision.
  2. Verify that the active revision uses the from product version.
  3. Verify the consent subject and evidence age.
  4. Validate the mapping and the future product BOM.
  5. Keep completed items in the old revision and append a new immutable revision under the same Plan.
  6. Activate the new revision and write the ProductVersionMigrationApplied objective fact to the outbox.

If the mapping, consent, or from version is invalid, the active revision stays unchanged and the handler records a quarantine or rejection result. The reservation service does not decide whether the new product is commercially fair. It verifies that the approved fact fits the current Plan and records the change as a traceable revision.

When a product change reaches the visit schedule

Section titled “When a product change reaches the visit schedule”

A different BOM does not authorize an immediate recalculation of a confirmed visit’s date, doctor, equipment, or room. A visit promise also contains clinic policy, capacity, patient consent, and resource agreement.

The implementation comments in ProductVersionMigrationHandler state that migration does not update the appointment, commitment, or allocation. If the schedule really must change, start a separate flow:

  1. Calculate candidate times for the new items.
  2. Show the existing CONFIRMED promise together with the new proposal.
  3. Store a new proposal and its change evidence; replace the confirmed proposal only after the patient consents.
  4. If the patient declines or no candidate exists, do not delete the existing promise first.
  5. Send the decline or reschedule result as an objective fact that CRM, counseling, and commerce can judge.

This is where policies such as VIP priority or an additional check after repeated no-shows might exist. Scheduling policies are owned and versioned by the reservation service, while CRM and commerce own customer-contact, compensation, and other follow-up facts. The reservation service stores the policy snapshot and calculation result used for this proposal. That is also why internal thresholds and customer tiers do not belong in a public article.

ServiceSource-of-record dataFacts it publishes or consumes for a product changeReservation responsibility
Product management and developmentProduct version, BOM, mappingProductCatalogChanged, ProductVersionMigrationApprovedVerify that version, BOM, and mapping are reproducible
Commerce and purchasingPurchase contract, additional purchase, refundPurchaseCompleted, PurchaseRefundedCreate one Plan per purchase and keep the source link
Reservation serviceScheduling policy, Plan, Plan revision, visit promise, resources, historyProductVersionMigrationApplied and objective schedule factsPreserve snapshot, revision, and confirmed-promise ownership
Clinical deliveryStart, completion, partial completionFulfillment factsSeparate completed work from future work
CRM and counselingCounseling, compensation, consent sourceDecline and operational handoff factsMake the customer decision from objective facts
NotificationContact consent and delivery historyConsumes appointment and migration eventsKeep channels outside the reservation transaction
Statistics and external consumersProjections and metricsConsume Plan, revision, and event dataNever replace the reservation source of truth

Source of record is not only about who can read a field. It is about which service can change its meaning. Product management may publish v2, but it does not directly cancel A’s confirmed visit. CRM may decide counseling and compensation after a decline, but it does not overwrite Plan provenance. The reservation service preserves executable promises and objective history between those boundaries.

Repeated delivery is not an additional purchase

Section titled “Repeated delivery is not an additional purchase”

This article does not use “duplicate” as shorthand for “duplicate purchase.”

A repeated delivery is the same PurchaseCompleted event arriving again after a timeout, retry, or replay. PurchaseCompletedHandler checks for an existing Plan in the sourcePurchaseAuthority, sourcePurchaseId, tenant, and clinic scope. If the immutable ownership matches, it converges to PURCHASE_ALREADY_PLANNED instead of creating a second Plan. If the payload conflicts, it quarantines an ownership conflict rather than guessing that a second purchase occurred.

An additional purchase means that the patient actually paid again and received a new sourcePurchaseId. That new purchase creates a new Plan. Combining items from the two Plans into one visit still needs its own eligibility, proposal, resource, and consent review.

Same sourcePurchaseId + same immutable ownership
└─> converge on the existing Plan
New sourcePurchaseId
└─> create a new purchase Plan
Repeated delivery ≠ additional purchase

The first is delivery safety. The second is a product and commerce fact. Calling both “duplicate” makes the counseling screen and the reservation screen explain different things to the patient.

Read current implementation and future design separately

Section titled “Read current implementation and future design separately”
Evidence labelScope in this articleEvidence
Current implementationVersioned catalog projection, one Plan per purchase, repeat/BOM/dependency snapshot, explicit migration mapping validation, same-Plan revision append/activate, and retained completion provenanceCurrent clinic-appointment develop source and related tests
Approved designProposal, consent, and operating policy when a product change would alter an existing confirmed visit; multi-item commitment expansionVisit commitment design, Plan and capacity design
Awaiting operationsActual broker delivery, outbox canary, backfill, production readiness, and recovery drillsRequires rollout evidence rather than source inspection
RoadmapA public patient channel for reviewing and consenting to a change proposalA later product and channel scope

“Current implementation” here means that the contract is confirmed in source and tests. It does not mean that every clinic can automatically apply every product change, or that the reservation service owns refunds and compensation.

This article fixed the boundary that protects an existing Plan and confirmed visit when a product version changes. The next article follows the first booking rule for an event product: how a purchase becomes candidate times and then a visit promise without confirming a date immediately, while respecting customer preference, validity, and clinic resources.

The existing companions supplement the source Markdown design. Start with product scheduling traits, package composition, and product BOM expansion before returning to this article’s migration timeline.

Comments

Leave a note or reaction with your GitHub account.