Problem/Motivation

  • CRM ships Group relation plugins (GroupContact, deriver) in the main crm module while group is not a dependency. That works when Group is enabled, but Group-specific integration cannot grow in crm without either hard-depending on Group or weaker workarounds.
  • We need two distinct Group integration concepts:
    • Existing: CRM contacts as group content via the GroupContact relation (members, roster, group-scoped contact permissions).
    • New: A group represents one canonical CRM contact (principal/workspace) — e.g. organization, household, or custom contact type — with enforced uniqueness, configuration per group type, and access for group members to edit that contact.
  • CRM-only sites (no Group) must remain supported.
  • Sites that already use CRM + Group must keep current behavior after upgrade without manual reconfiguration.

Steps to reproduce

  1. Enable crm and group.
  2. Configure a group type; install “Group contact (Person|Organization|Household)” relations.
  3. Add CRM contacts to a group as content — works today via plugins in crm.
  4. There is no supported way to model “this group represents contact X” with uniqueness, API, or group-scoped edit access for that principal contact.

Proposed resolution

Add submodule crm_group

  • Dependencies: crm:crm, group:group.
  • Move GroupContact and GroupContactDeriver (and related tests) from crm to crm_group; remove Group plugins from crm.
  • Update group integration documentation to require crm_group when using Group with CRM.

Upgrade path (preserve existing users)

  • Ship crm_group in the same project as crm.
  • On crm update: post-update hook and/or hook_modules_installed() in crm — if group is already enabled, install crm_group automatically when the extension is present and not yet enabled.
  • After upgrade, existing “Group contact” relations and adding contacts to groups should behave as before.

New: group represents a contact

  • Add entity crm_group_contact_mapping as source of truth:
    • group (entity reference, required), crm_contact (entity reference, required), denormalized and group_type.
    • Unique: one mapping per group; one group per contact per group_type.
  • GroupContactMappingService and event(s), parallel to crm_user_contact_mapping (ensure, load, validate, delete).
  • Third-party settings on group.type.* (CRM): represent_contact, allowed_contact_bundles (label sync / auto-create may be follow-up issues if deferred).
  • Group permissions for represented contact (view, edit); extend CRM contact access for group members — principal is not required to be group content.
  • Display principal on the group via a computed field (or equivalent) loaded from the mapping, with cache tags cleared when the mapping changes — not a stored synced entity reference on the group.
  • Group edit form: control to assign or change principal contact; writes the mapping only.
  • Admin UI for mappings (list, add, edit, delete), similar to user contact mappings.
  • Member contacts remain GroupContact group content; principal contact remains the mapping entity only.

Remaining tasks

  • Scaffold crm_group (info, services, permissions, routing).
  • Move GroupContact plugin, deriver, and tests from crm to crm_group.
  • Implement crm_group_contact_mapping entity, constraints, and admin UI.
  • Implement mapping service and event(s).
  • Group type CRM third-party settings form and validation against allowed_contact_bundles.
  • Represented-contact group permissions and contact access integration.
  • Computed principal contact on applicable group bundles; group form integration.
  • crm post-update / hook_modules_installed() to install crm_group when group is present; uninstall symmetry.
  • Update docs/integration/group-integration.md (member vs principal, enable crm_group).
  • Tests: plugin availability after move; auto-install on update; mapping uniqueness and bundle rules; represented-contact access; computed field cache invalidation.

User interface changes

  • crm_group on Extend (requires CRM and Group).
  • After upgrade, sites with Group enabled should get crm_group enabled automatically unless opted out.
  • Admin screens for group–contact mappings.
  • Group type edit: CRM settings (represent contact, allowed contact bundles).
  • Group type roles: permissions for represented contact.
  • Group edit/view: principal contact (computed); form to set principal where configured.
  • Existing “Group contact (…)” UI unchanged in behavior; plugins provided from crm_group.

API changes

  • New extension crm_group; crm no longer provides Plugin\Group\Relation\*.
  • New entity type crm_group_contact_mapping and mapping service (machine name TBD).
  • New event(s) for altering mapping on create/update (names TBD).
  • Third-party settings on group.type.* under CRM key.
  • Contact access grants via group membership and represented-contact permissions.
  • crm: hooks/post-update to install crm_group when Group is present.
  • No intentional API changes to crm_contact, crm_relationship, or crm_user_contact_mapping.

Data model changes

  • New table for crm_group_contact_mapping: id, uuid, group, crm_contact, group_type, created, changed.
  • Unique constraints on group and on (crm_contact, group_type).
  • No change to existing contact, relationship, or group content storage for member contacts.
  • No stored principal entity reference field on the group entity.
  • Config: CRM Group third-party settings on group types.

Comments

bluegeek9 created an issue. See original summary.

bluegeek9’s picture

Category: Feature request » Plan