---
id: DOM-MBR-STR-002
title: Organizational Unit
realises: CON-MBR-STR-002
product_area: membership
module: structure
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
owned_by: SVC-MBR-STR-structure
readable_by:
  - SVC-MBR-STR-configuration
  - SVC-PFM-DJE-membership-data-jobs
  - SVC-PFM-TNL-membership-tenant-lifecycle
  - SVC-PFM-QRY-queries
lifecycle: STATE-MBR-STR-001
custom_fields: declared
identity: >-
  A unit keeps its internal identifier throughout its life and has a changeable code unique within the
  workspace. Imports resolve supported identifiers, source keys or codes. Organization links have generated
  identities, dues extensions share their Accounting product identity, and financial settings are keyed by
  unit.
attributes:
  - name: code and name
    kind: text
    required: true
    computed: false
    notes: >-
      Codes follow the readable configuration grammar and are unique per workspace; names contain 1–200
      characters.
  - name: unit kind
    kind: reference
    required: true
    computed: false
    notes: Creation chooses the kind permanently; replacing details cannot select another kind.
  - name: standing
    kind: enum
    required: true
    computed: false
    notes: >-
      Tree operations set active, inactive or merged standing; merged records also retain their survivor
      reference.
  - name: local contact and mailing details
    kind: text
    required: false
    computed: false
    notes: >-
      Optional e-mail is trimmed, lowercased and validated; telephone, website and postal details receive no
      equivalent format check.
  - name: coordinates
    kind: number
    required: false
    computed: false
    notes: Optional latitude stays within −90 to 90 and longitude within −180 to 180.
  - name: member-facing choices
    kind: reference
    required: false
    computed: false
    notes: >-
      Portal visibility and a welcome-template reference are stored; no examined sender uses the welcome
      reference.
  - name: custom values
    kind: collection
    required: false
    computed: false
    notes: >-
      Required custom values are checked at creation against unit definitions. Single-record and query reads
      expose values, while ordinary lists and tree reads omit them.
  - name: external identifier
    kind: text
    required: false
    computed: false
    notes: An optional external reference supports integration and import matching.
  - name: organization links
    kind: collection
    required: false
    computed: false
    notes: >-
      Links record a CRM reference, relationship kind and inclusive dates. The organization reference accepts
      1–100 characters without a CRM existence check.
  - name: relationship kinds
    kind: collection
    required: true
    computed: false
    notes: >-
      Provisioning supplies four standard purposes: legal entity, operating organization, dues beneficiary and
      financial recipient. Staff can add purposes but cannot rename, retire or delete them through these
      routes.
  - name: financial settings
    kind: reference
    required: false
    computed: false
    notes: >-
      An optional ordering-profile reference delegates resolution through the program and application defaults
      to the workspace default. The unused default-dues reference receives only shape validation.
  - name: dues extensions
    kind: collection
    required: false
    computed: false
    notes: >-
      Each chapter-dues product extends one unit, with one extension per package and one catch-all. Accounting
      supplies its display and sale fields.
  - name: 'version, stamps and record versions'
    kind: computed
    required: true
    computed: true
    notes: >-
      Writes advance the record version and stamp actor and time; unit and organization-link changes retain
      attributed versions.
relationships:
  - to: DOM-MBR-STR-001
    cardinality: many units to one kind; each unit to zero or one parent
    ownership: Structure keeps the placement record and the unit's details within the same service.
    cross_service: false
  - to: DOM-MBR-STR-004
    cardinality: 'Each unit has zero or many dues extensions, at most one per package'
    ownership: The unit owns dues extensions; their package pointers are soft references without catalogue validation.
    cross_service: true
  - to: DOM-MBR-STR-003
    cardinality: many programs to zero or one owning unit
    ownership: 'Configuration owns each program''s optional owning-unit pointer, which protects the unit from deletion.'
    cross_service: true
  - to: DOM-CRM-ENT-002
    cardinality: Each unit has many dated organization links
    ownership: Membership owns dated links; CRM owns the organization identity and is not consulted by link creation.
    cross_service: true
  - to: DOM-ACC-PRD-001
    cardinality: 'Each dues extension has exactly one Accounting product, and Each product has at most one unit'
    ownership: Accounting owns products and prices; Membership owns the dues extension keyed by product identity.
    cross_service: true
invariants:
  - id: INV-DOM-MBR-STR-002-01
    statement: 'Within one workspace, two units cannot share a code.'
    enforced_at:
      - api
      - service
      - database
    provenance: test
    source: >-
      services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
      units in the database › the refusals › refuses a code the tenant already has
  - id: INV-DOM-MBR-STR-002-02
    statement: >-
      Detail replacement preserves kind, parent and standing and rejects merged units; placement and standing
      changes use the dedicated operations.
    enforced_at:
      - api
      - service
    provenance: observed
    source: >-
      services-membership:modules/structure/services/persistence/organizational-units.ts:updateOrganizationalUnit
  - id: INV-DOM-MBR-STR-002-03
    statement: At merge time the survivor is active and is neither the source nor one of its descendants.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-membership:modules/structure/tests/unit/services/tree-edits.spec.ts#the tree edits › merge ›
      refuses a survivor below the merged unit
  - id: INV-DOM-MBR-STR-002-04
    statement: 'Legal-entity link periods for a unit do not overlap, and at most one has no last day.'
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-membership:tests/e2e/structure-api.e2e.spec.ts#the structure API, end to end in process ›
      refuses a second open legal entity, 409 legal_entity_already_open
  - id: INV-DOM-MBR-STR-002-05
    statement: >-
      A unit has at most one dues extension for each package and one catch-all, and a product cannot extend
      multiple units' dues.
    enforced_at:
      - service
      - database
    provenance: observed
    source: >-
      services-membership:modules/structure/services/persistence/organizational-unit-dues-products.ts:createDuesProduct
  - id: INV-DOM-MBR-STR-002-06
    statement: Creating a dues extension requires an existing Accounting product of the chapter-dues type.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-membership:tests/e2e/packages-as-products.e2e.spec.ts#packages as products, through the API ›
      extends a product of type chapter_dues as a unit’s dues product, under the product’s id, with the
      product’s name
  - id: INV-DOM-MBR-STR-002-07
    statement: >-
      Any retained affiliation or protected structural or database reference prevents unit deletion; unused
      units lose only their owned rows.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-membership:tests/e2e/database-refusals.e2e.spec.ts#mistakes only the database catches, through
      the API › DEF-MBR-0084: a structure delete a program’s reference blocks › refuses deleting a unit a
      program is owned by 409 unit_in_use, and keeps it
  - id: INV-DOM-MBR-STR-002-08
    statement: Unit custom values must conform to the workspace's unit field definitions.
    enforced_at:
      - service
      - database
    provenance: documented
    source: >-
      services-membership:AGENTS.md#Custom Fields Are Opt-In Per Entity: R2-ARCH-001 (Andrew, 2026-10-19);
      services-membership:modules/structure/metadata/structure.objects.ts:organizationalUnitsObject
  - id: INV-DOM-MBR-STR-002-09
    statement: 'Unit, link, settings and dues reads remain confined to the caller''s workspace.'
    enforced_at:
      - database
    provenance: test
    source: >-
      services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
      units in the database › row-level security › reads nothing of another tenant’s unit by id
physical:
  - organizational_units
  - organizational_units_versions
  - organizational_unit_custom_field_values
  - organizational_unit_relationship_types
  - organizational_unit_organizations
  - organizational_unit_organizations_versions
  - organizational_unit_financial_settings
  - organizational_unit_dues_products
evidence:
  - >-
    services-membership at 5994c270: modules/structure/db/organizational-units.table.ts and the other unit
    tables; aws/api/structure-requests.ts; services/persistence/organizational-units.ts,
    organizational-unit-organizations.ts, organizational-unit-relationship-types.ts,
    organizational-unit-financial-settings.ts, organizational-unit-dues-products.ts;
    ports/accounting-products.ts; metadata/structure.objects.ts;
    docs/migrations/packages-as-products/README.md (ordering profiles; what could not be done here).
  - >-
    rhythm-v2-docs: specs/membership/structure/planning (CAP-MBR-STR-004, 006, 007, 008; FND-MBR-STR-007 to
    010).
---

# Organizational Unit

## What It Models

A unit is a recognizable part of the association, such as a chapter or region. It combines a stable identity with local contact information, placement, organization relationships and the products used to collect dues.

## Identity and Attributes

The permanent record identity survives a code change, closure or merge. Staff can maintain descriptive details and declared custom values independently of placement. Organization relationships carry dates, while financial settings hold pointers to Commerce and Accounting rather than their records.

## Relationships

Each unit has one kind and an optional current parent. Programs may identify their administering unit, packages may be named by local dues extensions, and CRM organizations may be linked for different purposes. Membership owns those links and extensions, while the referenced services retain their own records.

## Invariants

The invariant rows specify which writes validate identity, placement, links and dues references. A closed unit still accepts detail corrections; a merged unit rejects them, although its separate links and financial facets remain writable.

## How It Is Stored and Shared

The structure service owns the unit and its facets. It validates custom values through Platform's shared definitions and includes them in single-record and query results. Unit and link versions retain attributed changes, and the workspace lifecycle exports or removes the corresponding data.

## Open Design Questions

Reopening a closed unit and handling a merged source in current views remain product decisions. The merge returns finance, link and committee leftovers without assigning or tracking that follow-up work.
