---
id: WF-MBR-MEM-022
title: Change a member's contact for an officer
trigger: An officer submits changes for a person-owned membership.
product_area: membership
module: memberships
revision: 1
status: draft
design_intent: proposed
implementation_evidence: partially-observed
inference: []
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
  - CAP-MBR-MEM-016
moves: []
crosses:
  - SVC-MBR-MEM-memberships
idempotency: >-
  The request expresses replacement field values; a cooperating CRM updater
  determines repeat and version behaviour. The current stub provides no
  successful update guarantee.
concurrency: >-
  Membership does not lock CRM contact records. CRM controls any concurrency
  once the request crosses its port.
hops:
  - 'n': 1
    actor_or_service: Officer through the API
    action: Find the holding and verify the caller’s current unit reach.
    anchor: >-
      services-membership:modules/memberships/services/access/member-contact.ts:updateMemberContact
    seam: sync
    on_failure: Reject an unavailable or out-of-scope holding as not found.
    left_inconsistent: No partial local change remains.
    observer: Caller-visible API result
    provenance: observed
    source: >-
      services-membership:modules/memberships/services/access/member-contact.ts
      (header)
  - 'n': 2
    actor_or_service: Memberships service
    action: >-
      Combine applicable role field allowances and reject every submitted field
      outside them.
    anchor: >-
      services-membership:modules/memberships/services/access/unit-scope.ts:allowedFieldsOf
    seam: sync
    on_failure: Name every disallowed field and send no CRM update.
    left_inconsistent: No partial local change remains.
    observer: Caller-visible API result
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/integration/services/unit-scope.integration.spec.ts#refuses
      a field outside the list, field_not_allowed naming it
  - 'n': 3
    actor_or_service: CRM contacts port
    action: >-
      Delegate the accepted person-contact changes to CRM with the officer’s
      acting identity.
    anchor: 'services-membership:modules/memberships/ports/crm-contacts.ts'
    seam: sync
    on_failure: The default CRM adapter rejects the delegated update.
    left_inconsistent: Only the CRM owner can persist the contact change.
    observer: Caller-visible API result
    provenance: unknown
    source: FND-MBR-MEM-036
branches: []
waits: []
evidence:
  - >-
    services-membership at 5994c270:
    modules/memberships/services/access/member-contact.ts, unit-scope.ts,
    scope-settings.ts; ports/crm-contacts.ts
controls: [TC-AVL-002, TC-AVL-003, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, 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-002, 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, TC-TEN-004]
---

# Change a member's contact for an officer

## What It Does

Officers can request contact changes within their permitted membership scope and role fields. CRM remains responsible for the actual record update.

## The Flow

```mermaid
flowchart TD
  H1["Find the holding and verify the caller’s current unit reach"]
  H2["Combine applicable role field allowances and reject every submitted field outside them"]
  H1 --> H2
  H3["Delegate the accepted person-contact changes to CRM with the officer’s acting identity"]
  H2 --> H3
```

## When Something Fails

Membership rejects disallowed fields before calling CRM. Organization-owned holdings require CRM’s organization work instead. The configured contact port refuses, so no partial contact edit occurs through this wiring.
