---
id: CAP-MBR-MEM-001
title: Record a membership and its first term without a purchase
feature: FEAT-MBR-MEM-01
product_area: membership
module: memberships
revision: 1
status: draft
product_intent: confirmed
implementation_evidence: partially-observed
supersedes:
  - 'inventory:CAP-MBR-MEM-001'
  - 'inventory:CAP-MBR-MEM-002'
  - 'inventory:CAP-MBR-MEM-013'
  - 'inventory:CAP-MBR-MEM-015'
  - 'inventory:CAP-MBR-MEM-016'
  - 'inventory:CAP-MBR-MEM-018'
  - 'inventory:CAP-MBR-MEM-021'
  - 'inventory:CAP-MBR-DAT-003'
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - 'services-membership:README.md#2026-10-18 — Final acceptance'
  - 'services-membership:docs/migrations/membership-core/README.md#The operations and their keys'
  - 'services-membership:AGENTS.md#Custom Fields Are Opt-In Per Entity: R2-ARCH-001 (Andrew, 2026-10-19)'
purpose: >-
  Staff and migration producers establish membership in a program directly, including the first committed
  period.
outcomes:
  - Comped and migrated owners have a membership record equivalent to one established through purchase.
  - >-
    Principal holdings remain unique within a program and its identity unit, with overlapping exclusive
    programs refused.
  - New staff memberships receive their number and first period together.
concepts:
  - CON-MBR-MEM-001
  - CON-MBR-MEM-002
actors:
  - ACT-MBR-007
  - ACT-MBR-003
surfaces:
  - console
  - api
  - job
preconditions:
  - 'The selected program, type and any selected package are active and compatible.'
postconditions:
  - 'Creation saves the initial committed term, enrolment event and refreshed membership status.'
permissions:
  - key: membership.memberships.create
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-MBR-MEM-001-01
    statement: >-
      Staff creation requires a program, owner category, matching owner reference, a reason between 1 and 500
      characters and an initial term, and refuses an inactive program or an owner category that the program
      excludes.
    kind: validation
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: observed
    source: 'services-membership:modules/memberships/services/operations/staff-operations.ts:createMembership'
    origin: none
    examples:
      positive: >-
        A coordinator records a complimentary Regular term for a person in the national program and explains
        the board’s decision.
      negative: >-
        An organization cannot join a program restricted to individual owners; creation returns a validation
        refusal.
  - id: BR-CAP-MBR-MEM-001-02
    statement: >-
      An owner cannot receive another principal membership in the same program and identity unit; the refusal
      directs staff to extend the existing membership with a term.
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: observed
    source: 'services-membership:modules/memberships/services/operations/staff-operations.ts:createMembership'
    origin: none
  - id: BR-CAP-MBR-MEM-001-03
    statement: >-
      Identity-bound programs require a unit of their configured identity type, while programs without that
      binding refuse an identity unit.
    kind: validation
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: observed
    source: 'services-membership:modules/memberships/services/operations/staff-operations.ts:createMembership'
    origin: 'D-02 (services-membership:README.md, architecture decisions approved 2026-10-17)'
  - id: BR-CAP-MBR-MEM-001-04
    statement: >-
      The chosen type must be active within the program, any package must be active and belong to that type,
      and a term without a package requires explicit starting and ending dates.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'services-membership:modules/memberships/services/operations/staff-operations.ts:requirePackageOf'
    origin: none
  - id: BR-CAP-MBR-MEM-001-05
    statement: >-
      Where dates are omitted, the package rule calculates the period from the supplied effective date or the
      workspace business date; an explicit start without an end uses that rule to calculate the end.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'services-membership:modules/memberships/services/operations/staff-operations.ts:datesOf'
    origin: none
  - id: BR-CAP-MBR-MEM-001-06
    statement: >-
      The service rejects overlap with effective or pending terms and identifies the conflict, while the
      database exclusion independently rejects overlap between effective terms and does not cover pending
      terms.
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/integration/services/term-concurrency.integration.spec.ts#is
      backed by the migration’s exclusion when the persistence check is bypassed
    origin: none
  - id: BR-CAP-MBR-MEM-001-07
    statement: >-
      An owner cannot have overlapping effective or pending periods in different programs belonging to the
      same exclusivity group.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-membership:tests/acceptance/memberships/MBR-ACC-0171.acceptance.ts#step 3: POST
      /memberships/{tenantId}/memberships for c_kim_{run} in premium, term gold/premium_annual…
    origin: none
  - id: BR-CAP-MBR-MEM-001-08
    statement: >-
      Creation allocates the membership number using the workspace sequence, program sequence or owner’s CRM
      number selected by the program, refusing CRM numbering when the owner has no number.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-membership:tests/acceptance/memberships/MBR-ACC-0186.acceptance.ts#MBR-ACC-0186: Membership
      numbers come from the program's numbering scope: one sequence for the workspace, a program's own
      sequence, or the owner's CRM number, which refuses an owner without one and repeats across programs
    origin: 'D-41 (services-membership:modules/memberships/services/membership-numbers.ts header)'
  - id: BR-CAP-MBR-MEM-001-09
    statement: >-
      The enrolment event retains the creation reason, and the original join date uses the first effective
      term’s start unless staff supply a date that is recorded as their choice.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'services-membership:modules/memberships/services/operations/staff-operations.ts:createMembership'
    origin: none
  - id: BR-CAP-MBR-MEM-001-10
    statement: >-
      Imports match records by identity or producer source key and load configuration before memberships
      before terms; inserts record an imported event, all term writes refresh status, and neither grants nor
      flow-down children are generated.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: >-
      services-membership:modules/memberships/services/data-operations/membership-operations.ts:writeImportedTerm
    origin: none
  - id: BR-CAP-MBR-MEM-001-11
    statement: >-
      Prevalidation identifies malformed import fields before writing, and an overlapping imported term is
      classified as a conflict for that item.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/integration/data-operations/membership-data-operations.integration.spec.ts#classifies
      an overlapping term as that item’s conflict, term_overlap
    origin: none
  - id: BR-CAP-MBR-MEM-001-12
    statement: >-
      The product should validate imported owners, programs, types and packages as staff creation does and
      prevent an upsert from changing a term belonging to another membership.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: unknown
    source: FND-MBR-MEM-017
    origin: none
  - id: BR-CAP-MBR-MEM-001-13
    statement: >-
      The product should support staff and import entry of customer-defined membership values under the
      declared custom-field contract.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: unknown
    source: FND-MBR-MEM-016
    origin: 'R2-ARCH-001 (services-membership:AGENTS.md, Andrew 2026-10-19)'
  - id: BR-CAP-MBR-MEM-001-14
    statement: >-
      Staff creation sets renewal, drop, directory and auto-renew choices without offering later staff edits
      to those choices, the join date or owner, although import upserts can replace these values.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: false
    provenance: observed
    source: >-
      services-membership:modules/memberships/services/data-operations/membership-operations.ts:updateImportedMembership
    origin: none
scenarios:
  - id: SC-CAP-MBR-MEM-001-01
    given: A person has no principal membership in the national program.
    when: A coordinator records a complimentary Regular period and supplies the reason.
    then: 'Creation returns the numbered membership, committed period, enrolment event and recalculated standing.'
    provenance: observed
    source: 'services-membership:modules/memberships/services/operations/staff-operations.ts:createMembership'
  - id: SC-CAP-MBR-MEM-001-02
    given: 'Kim belongs to National, and Premium shares National’s exclusivity group.'
    when: A coordinator attempts a Premium membership covering days already held in National.
    then: The request fails and identifies the existing membership and overlapping period.
    provenance: test
    source: >-
      services-membership:tests/acceptance/memberships/MBR-ACC-0171.acceptance.ts#MBR-ACC-0171: An owner never
      holds two tiers at once: overlapping programs of one exclusivity group are refused, adjacent and
      ungrouped ones allowed, pending terms count, and two simultaneous adds probe the lock
edge_cases: []
constraints:
  - 'Term notes allow up to 2,000 characters, and a term request permits up to 20 unit affiliations.'
depends_on: []
related:
  - CAP-MBR-MEM-002
  - CAP-MBR-MEM-006
  - CAP-MBR-MEM-007
journeys:
  - JNY-MBR-MEM-001
open_questions: []
evidence:
  - repository: services-membership
    source_sha: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
    paths:
      - modules/memberships/services/operations/staff-operations.ts
      - modules/memberships/services/operations/term-writes.ts
      - modules/memberships/services/membership-numbers.ts
      - modules/memberships/services/data-operations/membership-operations.ts
      - modules/memberships/aws/api/memberships.routes.ts
      - modules/memberships/db/memberships.table.ts
      - modules/memberships/db/membership-terms.table.ts
      - modules/memberships/db/membership-custom-field-values.table.ts
      - modules/memberships/db/idempotency-keys.table.ts
      - modules/memberships/tests/integration/services/staff-operations.integration.spec.ts
      - modules/memberships/tests/integration/services/term-concurrency.integration.spec.ts
      - modules/memberships/tests/integration/data-operations/membership-data-operations.integration.spec.ts
      - docs/migrations/membership-core/README.md
      - docs/migrations/idempotency-ledger/README.md
      - tests/acceptance/memberships
  - repository: react-console
    source_sha: baf6dae382d6f41dce976c7f848667ccc37e076f
    paths:
      - acceptance/membership/inventory/capabilities.json
      - acceptance/membership/journeys/memberships
      - acceptance/membership/reports/defects/register.json
controls: [TC-AVL-002, TC-AVL-003, TC-AVL-004, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, 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-004, TC-DAT-007, TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-IAM-006, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, 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]
---

# Record a membership and its first term without a purchase

## Purpose

This capability gives staff a direct way to establish membership for complimentary, historical and migrated records. The owner receives a continuing membership with an initial period even when no order is involved.

## How It Works

A coordinator identifies the owner and selects the program, membership type and any package. They explain why the membership is being recorded and either provide the period or use the package’s date calculation. Creation checks the selected configuration and the owner’s existing holdings before saving. A duplicate principal holding is refused with guidance to add a period to the existing membership. An overlap with an exclusive program is also refused. Successful creation allocates the number, saves the initial period and records the enrolment reason together. Unit affiliations and package grants participate through their own capabilities. Migration producers instead load memberships and periods in dependency order through the data job engine. Import insertion records its own event, while an upsert changes existing values without adding another imported event. Imports suppress automatic grants and organizational children because the producer loads those records explicitly. The product should close the import validation and custom-field entry gaps identified in the findings. Staff have no separate editor for the owner, original join date or member choices after creation; import upserts can replace them.

## Relationships

- Membership configuration and the term engine supply eligible programs, types, packages and period calculations.
- Derived membership handles grants and organizational children produced by a committed period.
- Chapter and section affiliation places an affiliation-bound membership in its units.
