---
id: STATE-MBR-STR-001
title: Organizational unit standing
object: DOM-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
states:
  - name: active
    meaning: 'The unit can receive children and affiliations, move in the tree and participate as a merge survivor.'
  - name: inactive
    meaning: >-
      Closure retains placement, children, history and existing affiliations, permits detail correction, and
      prevents new children, affiliations and moves.
  - name: merged
    meaning: >-
      The source retains its identity, parent and open placement period while recording a survivor; detail
      changes, moves, closure and another merge are refused.
  - name: removed
    meaning: >-
      The current unit record and its owned periods, ancestry pairs, custom values and financial settings are
      absent; retained versions await workspace removal.
transitions:
  - from: active
    to: inactive
    trigger: Staff close the unit.
    guard: The unit exists and is not merged; any supplied version matches.
    side_effects:
      - Standing becomes inactive without changing child standing.
      - New children and affiliations are no longer accepted.
      - The write is captured in unit versions.
    who: Structure administrator
    provenance: test
    source: >-
      services-membership:modules/structure/tests/integration/services/tree/unit-merge.integration.spec.ts#the
      tree edits affiliations bind › delete and deactivate › deactivates it instead
  - from: inactive
    to: inactive
    trigger: Staff repeat closure of an inactive unit.
    guard: The record is not merged and any supplied version matches.
    side_effects:
      - The current record is returned without another write.
    who: Structure administrator
    provenance: observed
    source: 'services-membership:modules/structure/services/tree/tree-edits.ts:deactivateUnit'
  - from: active
    to: merged
    trigger: Staff combine the source into a surviving unit.
    guard: >-
      The survivor is active, outside the source branch and not the source; children pass placement checks,
      the affiliation plan has no refusal, the date is not future and any supplied source version matches.
    side_effects:
      - Children receive the survivor as parent and dated placement periods.
      - Planned affiliations and membership identities move in the same transaction.
      - Ancestry and depths are rebuilt.
      - Each relocated child produces a reparent event.
      - 'The response identifies finance, link and committee follow-up.'
    who: Structure administrator
    provenance: test
    source: >-
      services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
      units in the database › merge › moves the children under the survivor, marks the unit merged and lists
      what it left
  - from: inactive
    to: merged
    trigger: Staff merge an inactive source.
    guard: The active survivor and transaction pass the same merge checks as for an active source.
    side_effects:
      - The source and its children and planned memberships receive the same merge writes.
    who: Structure administrator
    provenance: observed
    source: 'services-membership:modules/structure/services/tree/tree-edits.ts:mergeUnit'
  - from: active
    to: removed
    trigger: Staff remove an unused active unit.
    guard: >-
      No affiliation, current child, retained parent reference, link, dues extension, merged-source pointer or
      protected program, membership or application reference holds the unit.
    side_effects:
      - The unit and its own dependent data are removed; versions remain.
    who: Structure administrator
    provenance: test
    source: >-
      services-membership:modules/structure/tests/unit/services/tree-edits.spec.ts#the tree edits › delete ›
      deletes a unit no affiliation and nothing else names
  - from: inactive
    to: removed
    trigger: Staff remove an unused inactive unit.
    guard: The deletion reference checks pass; deletion does not require a version.
    side_effects:
      - Removal applies the same owned-row cleanup as for an active unit.
    who: Structure administrator
    provenance: observed
    source: 'services-membership:modules/structure/services/tree/tree-edits.ts:deleteUnit'
  - from: merged
    to: removed
    trigger: Staff request deletion of a merged source.
    guard: The same reference checks pass; retained child history and affiliation rows commonly prevent removal.
    side_effects:
      - An unreferenced merged source receives ordinary unit cleanup.
    who: Structure administrator
    provenance: inferred
    source: >-
      services-membership:modules/structure/services/tree/tree-edits.ts:deleteUnit;
      services-membership:modules/structure/services/persistence/organizational-units.ts:unitReferences
invalid:
  - from: inactive
    to: active
    why: No reopening route exists; submitted standing on detail replacement is discarded.
  - from: merged
    to: active
    why: The examined operations cannot restore a merged source to active standing.
  - from: merged
    to: inactive
    why: Closure explicitly rejects a merged source.
  - from: merged
    to: merged
    why: Merge explicitly rejects an already merged source.
concurrency: >-
  Standing changes acquire the workspace tree lock and the unit row lock. Concurrent tree operations therefore
  serialize, and a later merge sees the source already merged. Merge and closure compare a version only when
  one is supplied; deletion has no version check.
invariants:
  - INV-DOM-MBR-STR-002-02
  - INV-DOM-MBR-STR-002-03
  - INV-DOM-MBR-STR-002-07
evidence:
  - >-
    services-membership at 5994c270: modules/structure/services/tree/tree-edits.ts (deactivateUnit, mergeUnit,
    deleteUnit); services/persistence/organizational-units.ts (setUnitStatus, unitReferences,
    updateOrganizationalUnit); aws/api/structure-requests.ts (unitReplaceBody);
    docs/migrations/unit-merge/README.md.
---

# Organizational unit standing

## The Lifecycle

```mermaid
stateDiagram-v2
  [*] --> active: unit created
  active --> inactive: close
  inactive --> inactive: repeat closure
  active --> merged: combine
  inactive --> merged: combine
  active --> removed: unused record deleted
  inactive --> removed: unused record deleted
  merged --> removed: references permit deletion
  removed --> [*]
```

## Transitions Explained

Creation starts an active unit. Closure preserves its retained work, while a merge moves children and eligible memberships together and reports what remains on the source. Deletion is governed by references rather than standing.

## What Cannot Happen

The API offers no reopening or reversal of a merge. Sending an active status in a detail replacement does not reopen a unit. A merged source rejects the dedicated move, closure and merge operations.

## Concurrency and Timing

Tree locks keep standing changes from interleaving with other structural edits. Merge dates can be today or earlier, subject to retained parent periods; they cannot schedule a future change. The source's existing parent period remains open after merging.
