---
id: DOM-MBR-STR-004
title: Membership Package
realises: CON-MBR-STR-004
product_area: membership
module: structure
revision: 1
status: draft
design_intent: confirmed
origin: >-
  D-1 and D-2 (Andrew, 2026-10-18):
  services-membership:docs/migrations/packages-as-products/README.md#Packages as products: the membership
  package and the unit dues product are extensions of Accounting products
implementation_evidence: observed
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
owned_by: SVC-MBR-STR-configuration
readable_by:
  - SVC-MBR-STR-structure
  - SVC-MBR-STR-terms
  - SVC-PFM-TNL-membership-tenant-lifecycle
custom_fields: none
identity: >-
  A package permanently shares the identifier of its Accounting membership-package product, with one extension
  per product. Grants and policies use generated identifiers; fixed ends use package and position,
  requirements use package and kind, and policy sets use permanent readable identifiers.
attributes:
  - name: shared product fields
    kind: computed
    required: true
    computed: true
    notes: >-
      Accounting supplies name, description, status, visibility, business unit and sale window on reads;
      package requests reject these shared fields.
  - name: activity
    kind: computed
    required: true
    computed: true
    notes: >-
      The product's active status determines package activity. Filtering occurs after each underlying package
      page is read.
  - name: program and membership type
    kind: reference
    required: true
    computed: false
    notes: The selected classification must belong to the selected program.
  - name: term rule
    kind: enum
    required: true
    computed: false
    notes: >-
      Anniversary, calendar and never-ending rules combine length, units, calendar and sale thresholds;
      validation checks the complete rule.
  - name: fixed term ends
    kind: collection
    required: false
    computed: false
    notes: >-
      Ordered month-day windows select a fixed end. Overlap is permitted and the earliest stored matching
      window wins.
  - name: renewal settings
    kind: collection
    required: false
    computed: false
    notes: >-
      Renewal choices cover timing, continuation, automatic renewal, reinstatement and an optional different
      renewal package from the same program.
  - name: seats and pricing hints
    kind: number
    required: false
    computed: false
    notes: >-
      Seat limits and enrolment proration guide organizational memberships and checkout; monetary computation
      belongs to Commerce.
  - name: grants
    kind: collection
    required: false
    computed: false
    notes: >-
      A package can submit up to ten additional program grants, each using its own program's type and either
      primary dates or an independently validated rule.
  - name: unit requirements
    kind: collection
    required: false
    computed: false
    notes: >-
      Up to twenty kind-specific count and dues overrides are allowed, including kinds absent from the
      program's requirement list.
  - name: change policy set
    kind: reference
    required: false
    computed: false
    notes: >-
      A referenced set can hold up to 200 upgrade and downgrade policies; no examined operational consumer
      applies those policies.
  - name: display order
    kind: computed
    required: true
    computed: true
    notes: The port supplies zero until Accounting exposes a shared product display order.
  - name: version and stamps
    kind: computed
    required: true
    computed: true
    notes: >-
      Every package save advances its extension version; Accounting maintains the product version
      independently.
relationships:
  - to: DOM-ACC-PRD-001
    cardinality: Each package has exactly one Accounting product; Each product has at most one package
    ownership: Accounting owns the base product and prices; Membership owns its package extension.
    cross_service: true
  - to: DOM-MBR-STR-003
    cardinality: many packages to one program and one type of it
    ownership: The package stores its program and type references and owns the associated lists.
    cross_service: false
  - to: DOM-MBR-STR-001
    cardinality: Each package has up to twenty unit-kind requirements
    ownership: Configuration owns package requirements while structure owns their referenced kinds.
    cross_service: true
  - to: DOM-MBR-STR-002
    cardinality: Each package has zero or many unit dues extensions that name it
    ownership: Unit dues extensions are owned by structure and can point to a package without verifying its existence.
    cross_service: true
  - to: DOM-MBR-STR-005
    cardinality: Each package has the term-date inputs of every purchase of it
    ownership: The package supplies the rule; the engine computes purchase dates without storing the result itself.
    cross_service: true
invariants:
  - id: INV-DOM-MBR-STR-004-01
    statement: >-
      Creation requires an existing Accounting membership-package product, whose identity can have only one
      package extension.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-membership:tests/e2e/packages-as-products.e2e.spec.ts#packages as products, through the API ›
      refuses a second extension of the same product: the package id is the product id
  - id: INV-DOM-MBR-STR-004-02
    statement: >-
      Membership stores no shared product fields on the package and obtains them from Accounting when reading
      it.
    enforced_at:
      - api
      - service
    provenance: test
    source: >-
      services-membership:tests/e2e/packages-as-products.e2e.spec.ts#packages as products, through the API ›
      refuses the common fields a package no longer carries of its own (they are the product’s)
  - id: INV-DOM-MBR-STR-004-03
    statement: >-
      Package types and renewal targets belong to the package's program, while each grant's type belongs to
      that grant's program.
    enforced_at:
      - database
    provenance: test
    source: >-
      services-membership:tests/e2e/database-refusals.e2e.spec.ts#mistakes only the database catches, through
      the API › DEF-MBR-0086: a configuration write a check, a foreign key or an integer column refuses ›
      refuses a package of a type of another program 400 naming membership_type_id, and writes no package nor
      unit rule
  - id: INV-DOM-MBR-STR-004-04
    statement: >-
      Package updates validate the merged stored and submitted term rule, and submitted grants with
      independent rules receive equivalent validation.
    enforced_at:
      - service
      - database
    provenance: observed
    source: >-
      services-membership:modules/configuration/services/configuration/configuration-records.ts:packageResource
  - id: INV-DOM-MBR-STR-004-05
    statement: >-
      A submitted grant cannot target the package's own program; changing the program without resubmitting
      grants does not revalidate retained grants.
    enforced_at:
      - service
    provenance: observed
    source: >-
      services-membership:modules/configuration/services/configuration/configuration-records.ts:packageResource
  - id: INV-DOM-MBR-STR-004-06
    statement: Neither side of a change policy can specify both a type and a package.
    enforced_at:
      - database
    provenance: observed
    source: 'services-membership:modules/configuration/db/change-policies.table.ts:changePolicies'
  - id: INV-DOM-MBR-STR-004-07
    statement: Package deletion removes the Membership extension and retains the Accounting product.
    enforced_at:
      - service
    provenance: observed
    source: 'services-membership:modules/configuration/services/persistence/configuration-store.ts:configurationStore'
physical:
  - membership_packages
  - package_fixed_term_ends
  - package_grants
  - package_unit_rules
  - change_policy_sets
  - change_policies
evidence:
  - >-
    services-membership at 5994c270: modules/configuration/db/membership-packages.table.ts,
    package-fixed-term-ends.table.ts, package-grants.table.ts, package-unit-rules.table.ts,
    change-policy-sets.table.ts, change-policies.table.ts; services/configuration/configuration-records.ts
    (packageContent, packageResource, policySetResource); services/persistence/membership-packages.ts;
    modules/structure/ports/accounting-products.ts; docs/migrations/packages-as-products/README.md.
  - >-
    rhythm-v2-docs: specs/membership/structure/planning (CAP-MBR-STR-012, 013, 014; FND-MBR-STR-017, 018, 028,
    037).
---

# Membership Package

## What It Models

A package describes the membership effect of buying an Accounting product. Its extension selects the program and classification, term dates, renewal settings, additional grants and structural requirements. Change policies are retained configuration for processing that has not been implemented.

## Identity and Attributes

Product and package share one identity. Accounting supplies the public description, availability and pricing data; Membership supplies the membership effect. Fixed ends and unit rules use composite keys, whereas replacing grants allocates new generated identities.

## Relationships

The extension refers to its Accounting product, program, classification and optional policy set. Requirements name unit kinds, and local dues extensions may refer to the package. The memberships purchase participant reads these settings and asks the term engine for dates.

## Invariants

Invariant rows distinguish product validation at creation from checks performed on later package updates. Database references enforce program compatibility; service validation checks the complete term rule and submitted grants.

## How It Is Stored and Shared

Configuration owns the extension and its lists. A save is atomic within Membership, but the documented offering process saves the Accounting product separately first. History capture records package and policy-set revisions, and lifecycle exports expose both.

## Open Design Questions

Product must settle inactive-product preparation, absent reinstatement allowances and fresh purchases after fixed windows close. Retained-grant revalidation and the future application of change policies also need explicit decisions.
