Contact Organization Membership
Data Entity
Description
Junction entity tracking which organizations a contact belongs to, supporting contacts who are registered across multiple local associations (up to 5 per NHF requirements). Enables organization-scoped contact visibility, duplicate-registration prevention, and primary-organization designation for routing and reporting.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key, globally unique membership record identifier | PKrequiredunique |
contact_id |
uuid |
Foreign key referencing the contact who is a member of the organization | required |
organization_id |
uuid |
Foreign key referencing the organization this contact belongs to | required |
is_primary |
boolean |
Flags which organization is the contact's primary affiliation. Only one membership record per contact may be true at a time. Used to determine which org's coordinator has primary responsibility. | required |
membership_type |
enum |
Characterizes the nature of the contact's relationship to the organization | required |
status |
enum |
Lifecycle state of this membership record | required |
enrolled_at |
datetime |
Timestamp when the contact was registered with this organization | required |
unenrolled_at |
datetime |
Timestamp when the contact left or was removed from the organization. Null if still active. | - |
enrolled_by |
uuid |
Foreign key to users table — the peer mentor or coordinator who registered this membership | required |
notes |
text |
Optional free-text notes about the membership context (e.g. reason for transfer, cross-association coordination notes) | - |
created_at |
datetime |
Record creation timestamp | required |
updated_at |
datetime |
Record last modification timestamp | required |
Database Indexes
idx_com_contact_id
Columns: contact_id
idx_com_organization_id
Columns: organization_id
idx_com_contact_org_unique
Columns: contact_id, organization_id
idx_com_contact_primary
Columns: contact_id, is_primary
idx_com_org_status
Columns: organization_id, status
idx_com_enrolled_at
Columns: enrolled_at
Validation Rules
valid_contact_reference
error
Validation failed
valid_organization_reference
error
Validation failed
valid_enrolled_by_reference
error
Validation failed
unenrolled_at_after_enrolled_at
error
Validation failed
membership_type_enum_constraint
error
Validation failed
status_enum_constraint
error
Validation failed
notes_max_length
error
Validation failed
Business Rules
max_five_memberships_per_contact
A contact may belong to at most 5 organizations simultaneously. NHF requirement: contacts in multiple local associations must be bounded to prevent unbounded cross-org data sprawl.
single_primary_per_contact
Exactly one membership record per contact may have is_primary=true. Setting a new record as primary automatically demotes the previous primary to false. A contact with any memberships must always have exactly one primary.
org_scoped_read_access
A peer mentor or coordinator may only read membership records where organization_id matches their active organization context. Global Admins require a time-bounded support access flag to access org membership data.
soft_delete_on_transfer
When a contact transfers out of an organization, the membership status is set to transferred_out and unenrolled_at is stamped. The record is retained for audit and Bufdir reporting continuity; it is never hard-deleted.
duplicate_membership_blocked
A contact_id + organization_id pair must be unique among active records. Coordinators attempting to register the same contact for an organization they already belong to are blocked with a clear error — supports NHF duplicate-registration prevention.
coordinator_org_boundary
A coordinator may only create or modify membership records for their own organization_id. Cross-org membership manipulation (e.g. adding a contact to a sibling association) requires Org Admin privileges.