Skip to content

CAP-MBR-MEM-009Sell membership through the Commerce checkout

Markdown

CAP-MBR-MEM-009

Sell membership through the Commerce checkout

Markdown
  • DocumentDraft
  • Product intentConfirmed
  • ImplementationPartially observed

KindCapabilityProduct areaMembershipModuleMemberships, Applications and Membership BillingRevision1

Read atservices-membership 5994c270react-console baf6dae3

The Formal Contract

The narrative above explains; the sections below are authoritative — the rules, scenarios and tests this document binds.

Outcomes
The checkout never sells a membership operation the member is not eligible for.A paid order becomes exactly one committed term, with its chapters, dues and grants.Commerce prices each line without Membership ever computing an amount.
Surfaces
api
Constraints
A package line names at most 20 chapters.
Intent sources
services-membership:README.md#2026-10-18 — Final acceptanceservices-membership:docs/migrations/participant/README.md (Andrew, 2026-10-17: build against contracts)services-membership:docs/migrations/packages-as-products/README.md (D-1, D-2, D-5 of 2026-10-18)

Controls

36 controls apply, from the corpus control catalogue.

TC-AVL-002 TC-AVL-003 TC-AVL-004 TC-AZ-001 TC-AZ-003 TC-AZ-004 TC-CHG-001 TC-CHG-002 TC-CHG-003 TC-CHG-004 TC-CRY-001 TC-CRY-002 TC-CRY-003 TC-DAT-001 TC-DAT-002 TC-DAT-003 TC-DAT-007 TC-IAM-006 TC-LOG-002 TC-LOG-003 TC-LOG-005 TC-MON-001 TC-MON-002 TC-MON-004 TC-PI-001 TC-PI-002 TC-PI-003 TC-PI-004 TC-PI-005 TC-PRV-001 TC-PRV-002 TC-SEC-001 TC-SEC-004 TC-TEN-001 TC-TEN-002 TC-TEN-003

Business Rules

15 rules, 15 to be proved before approval. A rule's product intent is derived from its origin: 15 confirmed by a product decision, the rest inheriting this capability's confirmed.

IdRuleKindEnforced atProvenance
01must prove
Confirmed
Membership answers Commerce's request to prepare every membership item of a checkout in one call, writes nothing while preparing, and never computes or returns an amount.
policyservicetest
02must prove
Confirmed
A package line's product must be the package itself, and the program, type and package must be active and belong to one another.
origin: D-1 of 2026-10-18 (services-membership:docs/migrations/packages-as-products/README.md)
validationservicetest
services-membership:modules/commerce-participant/tests/integration/participant.integration.spec.ts#refuses a package line whose product is not the package: the package is its product (D-1)
03must prove
Confirmed
The member's state on the business date decides the operation: no membership allows enrolment; a current term or grace allows renewal; after grace and within the package's reinstatement window, reinstatement; beyond it, rejoining; a request for another operation is refused naming the one the state supports.
policyservicetest
services-membership:modules/commerce-participant/tests/unit/eligibility.spec.ts#refuses a renewal of a lapsed membership, naming rejoin (07 §2)
04must prove
Confirmed
A renewal is refused before the package's renewal window opens, for a membership marked do-not-renew, and for a renewal on a chosen date; an enrolment cannot start in the past.
validationservicetest
services-membership:modules/commerce-participant/tests/unit/eligibility.spec.ts#refuses a renewal before the package’s renewal window opens
05must prove
Confirmed
A suspended membership is refused, and a membership with a cancellation pending, a renewal already pending or a first term already pending is unavailable until that settles.
policyservicetest
services-membership:modules/commerce-participant/tests/unit/eligibility.spec.ts#answers a renewal while one is pending unavailable: renewal_in_progress
06must prove
Confirmed
An immediate change of type, a transfer and a change of chapters mid-term need an amendment and are refused; an upgrade at term end is sold as a renewal into the other type.
policyservicetest
services-membership:modules/commerce-participant/tests/unit/eligibility.spec.ts#takes an upgrade at term end as a renewal into the other type
07must prove
Confirmed
The plan names the term's period from the package's term rule, each chosen unit with its dues product, the grants, and the one pending term it claims; a unit whose dues are planned must have its dues line in the same checkout.
calculationservicetest
services-membership:modules/commerce-participant/tests/integration/participant.integration.spec.ts#refuses a package line whose dues chapter has no dues line beside it
08must prove
Confirmed
Each line is priced for the operation's audience (new for enrolment, renewing for renewal, the package's choice for reinstatement, rejoining for a rejoin), falling back to new when the product's price list has no row for it; a first term with an end is prorated by the package's method on the original price, and a renewal never is.
origin: D-5 of 2026-10-18 and D-24 (services-membership:docs/migrations/participant/README.md#The pricing-policy field mapping)
calculationservicetest
services-membership:modules/commerce-participant/tests/unit/pricing-policy.spec.ts#falls back to new when the grid has no row for the operation’s audience (D-5: a blank rejoining inherits new)
09must prove
Confirmed
Each line says through whom it is sold: the package through its program and the program's ordering profile, chapter dues through the chapter's own profile, locked, or the program's when the chapter has none.
origin: ordering profiles, Andrew-approved 2026-10-18 (services-membership:docs/migrations/packages-as-products/README.md#Ordering profiles)
policyservicetest
services-membership:modules/commerce-participant/tests/unit/selling-context.spec.ts#inherits the program’s profile for a chapter without one, naming the program as where it came from
10must prove
Confirmed
At placement, inside Commerce's own transaction, Membership reserves the purchase as a pending term, creating an unnumbered pending membership when the owner has none; of two checkouts placing for one person at once, one wins and the other is refused as pending.
invariantdatabasetest
services-membership:modules/commerce-participant/tests/integration/participant.integration.spec.ts#lets one of two concurrent checkouts for the same person win and refuses the other with term_pending
11must prove
Confirmed
A line needs approval when an active application process of its operation offers the package and reviews its applications, unless the line names the application that process approved.
policyservicetest
services-membership:modules/applications/tests/integration/decision-handler.integration.spec.ts#answers requires_approval for the package the process reviews when no decided application is named
12must prove
Confirmed
Fulfilment commits the reserved term once per payment authorization: it numbers a new membership, records the enrolment, renewal, reinstatement or rejoin with the order, writes the frozen chapters with their dues products and the grants, and answers a redelivery with the same records.
lifecycleservice, databasetest
services-membership:modules/commerce-participant/tests/integration/participant.integration.spec.ts#answers a redelivered authorization with the same records and writes nothing again
13must prove
Confirmed
A chapter dues line is stamped on the chapter's affiliation once the package line is fulfilled; until then it asks Commerce to deliver it again.
lifecycleservicetest
services-membership:modules/commerce-participant/tests/integration/participant.integration.spec.ts#stamps the dues line on the affiliation once the package line is fulfilled, and asks for a redelivery before
14must prove
Confirmed
A placement made in Commerce's transaction commits with Membership's change history recorded, so a purchase is never refused at commit because of how its writer is identified.
no proof recorded yet
invariantdatabaseunknown
15must prove
Confirmed
A renewal bought without naming chapters carries the previous term's chapters marked as inherited, as a staff renewal does, and the same chapter cannot be bought twice on one line.
no proof recorded yet
validationserviceunknown

Scenarios

IdGivenWhenThenProvenance
01A new Associate with no membership adds the Associate package to her cart.Commerce asks, places the order and later fulfils it.Asking writes nothing, placement reserves a pending unnumbered membership, and fulfilment commits the numbered membership once.test
services-membership:tests/e2e/commerce-purchase.e2e.spec.ts#fulfils into a numbered membership holding the authorization id
02A Regular applicant chooses Atlanta, which sells dues.The cart lacks Atlanta's dues line, then includes it.The package line is refused without the dues line, and planned with Atlanta and its dues product with it.test
services-membership:tests/e2e/commerce-purchase.e2e.spec.ts#plans the chapter with its dues product when its dues line is in the checkout
03Two browser tabs buy the same person's first membership.Both orders are placed at once.One reserves the term and the other is refused as pending.test
services-membership:tests/e2e/commerce-purchase.e2e.spec.ts#lets one of two concurrent placements claim the person’s term and refuses the other term_pending

The Markdown files under specs/ in rhythmsoftware/rhythm-v2-docs are the canonical source of truth. This reader is a generated, read-only projection of them.