---
id: CAP-MBR-STR-006
title: Maintain a unit’s identity and local details
feature: FEAT-MBR-STR-02
product_area: membership
module: structure
revision: 1
status: draft
product_intent: proposed
implementation_evidence: observed
supersedes:
  - react-console acceptance inventory CAP-MBR-STR-003
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - >-
    services-membership:AGENTS.md#Custom Fields Are Opt-In Per Entity: R2-ARCH-001 (Andrew, 2026-10-19;
    organizational units declare custom fields)
purpose: >-
  Staff maintain the information that identifies and describes an individual chapter, section or regional
  unit.
outcomes:
  - Each unit has its own contact information and customer-specific values.
  - Saved changes retain attribution and version information.
concepts:
  - CON-MBR-STR-002
actors:
  - ACT-MBR-001
  - ACT-MBR-002
surfaces:
  - api
preconditions: []
postconditions: []
permissions:
  - key: membership.structure.read
    where_checked: api
    scope: tenant
  - key: membership.structure.manage
    where_checked: api
    scope: tenant
  - key: membership.application.access
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-MBR-STR-006-01
    proved_by: [ATS-MBR-STR-006-01, TST-MBR-STR-006]
    statement: >-
      A unit code uses lowercase letters, digits and single underscores, is unique within the workspace and
      can change through detail replacement.
    kind: validation
    enforced_at:
      - api
      - service
      - database
    must_prove: true
    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
    origin: none
  - id: BR-CAP-MBR-STR-006-02
    proved_by: [ATS-MBR-STR-002-15, ATS-MBR-STR-006-02, ATS-MBR-STR-006-11, TST-MBR-STR-089]
    statement: >-
      Creation fixes the unit kind and validates placement; detail replacement cannot change kind, parent or
      status, while later tree operations change placement or status.
    kind: invariant
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: observed
    source: >-
      services-membership:modules/structure/services/persistence/organizational-units.ts:updateOrganizationalUnit
    origin: none
  - id: BR-CAP-MBR-STR-006-03
    proved_by: [ATS-MBR-STR-006-03]
    statement: 'Unit e-mail input is trimmed, normalized to lowercase and validated, with blank input stored as empty.'
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'services-membership:modules/structure/services/persistence/organizational-units.ts:attributeValues'
    origin: none
  - id: BR-CAP-MBR-STR-006-04
    proved_by: [ATS-MBR-STR-006-04]
    statement: >-
      Latitude must be between minus 90 and 90 and longitude between minus 180 and 180; other address and
      telephone details have no format validation.
    kind: validation
    enforced_at:
      - database
    must_prove: true
    provenance: observed
    source: >-
      services-membership:modules/structure/db/organizational-units.table.ts:organizational_units_latitude_check
    origin: none
  - id: BR-CAP-MBR-STR-006-05
    proved_by: [ATS-MBR-STR-006-06, TST-MBR-STR-066]
    statement: >-
      Unit detail replacement requires the version read and resets omitted ordinary fields to their defaults,
      while custom values change only for submitted fields.
    kind: validation
    enforced_at:
      - database
    must_prove: true
    provenance: documented
    source: 'services-membership:docs/migrations/structure/README.md#Tables and migrations'
    origin: none
  - id: BR-CAP-MBR-STR-006-06
    proved_by: [ATS-MBR-STR-006-05, TST-MBR-STR-088]
    statement: >-
      Organizational units accept customer-defined fields validated against unit definitions, with required
      values checked on creation.
    kind: validation
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: observed
    source: >-
      services-membership:modules/structure/services/persistence/organizational-units.ts:insertOrganizationalUnit
    origin: >-
      services-membership:AGENTS.md#Custom Fields Are Opt-In Per Entity: R2-ARCH-001 (Andrew, 2026-10-19;
      organizational units declare custom fields)
  - id: BR-CAP-MBR-STR-006-07
    proved_by: [ATS-MBR-STR-006-08]
    statement: 'Single-unit reads include custom values, whereas ordinary unit lists and tree reads omit them.'
    kind: policy
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: observed
    source: >-
      services-membership:modules/structure/services/persistence/organizational-units.ts:updateOrganizationalUnit
    origin: none
  - id: BR-CAP-MBR-STR-006-08
    proved_by: [ATS-MBR-STR-006-07, ATS-MBR-STR-006-10, TST-MBR-STR-006, TST-MBR-STR-087]
    statement: Unit and parent-history changes retain attributed versions for audit and historical reconstruction.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'services-membership:modules/structure/services/persistence/organizational-units.ts:getOrganizationalUnit'
    origin: none
  - id: BR-CAP-MBR-STR-006-09
    proved_by: [ATS-MBR-STR-006-09]
    statement: Welcome-template selection is stored without an implemented sender.
    kind: invariant
    enforced_at:
      - database
    must_prove: true
    provenance: test
    source: >-
      services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
      units in the database › the versions › writes a version of the unit for its creation, its update and its
      move, each with the actor of its context
    origin: none
  - id: BR-CAP-MBR-STR-006-10
    proved_by: []
    statement: Inactive units allow detail replacement; merged units reject it.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: observed
    source: 'services-membership:modules/structure/metadata/structure.objects.ts:organizationalUnitsObject'
    origin: none
scenarios:
  - id: SC-CAP-MBR-STR-006-01
    given: Staff are preparing Atlanta’s local record.
    when: 'They save mailing, geographic, contact and custom details together with visibility.'
    then: A subsequent single-record read returns the saved details.
    provenance: test
    source: >-
      services-membership:tests/acceptance/structure/MBR-ACC-0006.acceptance.ts#MBR-ACC-0006 a complete
      chapter, recorded and read back
edge_cases:
  - id: SC-CAP-MBR-STR-006-02
    given: An integration expects omitted replacement fields to remain unchanged.
    when: 'It submits code, name and version while omitting optional details.'
    then: 'Ordinary details return to defaults, while omitted custom values remain intact.'
    provenance: test
    source: >-
      services-membership:tests/acceptance/structure/MBR-ACC-0032.acceptance.ts#MBR-ACC-0032 a client that
      thinks PUT is a patch, and a unit deleted behind the service
constraints: []
depends_on:
  - CAP-MBR-STR-002
related:
  - CAP-MBR-STR-007
  - CAP-MBR-STR-008
journeys:
  - JNY-MBR-STR-001
open_questions: []
evidence:
  - >-
    services-membership: Examination of unit persistence, request schemas, the units table and metadata
    registration.
  - >-
    services-membership: Examination of unit integration tests and acceptance journeys MBR-ACC-0006 to 0008,
    0030 to 0032.
  - 'services-membership:docs/migrations/structure/README.md'
  - 'services-membership:modules/structure/db/organizational-units.table.ts'
  - 'services-membership:modules/structure/metadata/structure.objects.ts'
  - 'services-membership:modules/structure/services/persistence/organizational-units.ts'
  - >-
    services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts
controls: [TC-AVL-002, TC-AVL-003, 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-007, TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-PI-001, TC-PI-003, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-SEC-001, TC-SEC-004, TC-TEN-001, TC-TEN-002, TC-TEN-003]
exercised_by: [FAS-MBR-STR-02-01, FAS-MBR-STR-02-02, FAS-MBR-STR-02-03, FAS-MBR-STR-02-04, FAS-MBR-STR-02-05]
suites: [TST-MBR-STR-006, TST-MBR-STR-066, TST-MBR-STR-087, TST-MBR-STR-088, TST-MBR-STR-089]
---

# Maintain a unit’s identity and local details

## Purpose

Staff maintain the information that identifies and describes an individual chapter, section or regional unit.

## How It Works

Staff create a unit with a recognizable code and display name. Its local details can describe how to contact it and where correspondence goes. Those details belong to the unit even when a related CRM organization has similar information. Staff can add the customer’s configured unit fields. A single-record read returns those values alongside ordinary details. The replacement operation uses the version staff read, so an intervening edit must be reconciled. Ordinary omitted details return to defaults; custom values use their own submitted-field behavior. Placement and status are managed through structural operations rather than this replacement. The unit’s kind stays fixed after creation. Changes retain attribution and versions. Selecting a welcome template records a choice without establishing that a welcome message is sent.

## Relationships

- Creating a unit invokes structural placement validation.
- Organization links and finance settings refer to the unit’s continuing identity.
