Saltar al contenido principal

Recipient Groups Module

Overview

The Recipient Groups module manages custom groups of recipients for the multi-channel communication system. Businesses create groups to organize contacts (users, emails, phones, WhatsApp numbers) for targeted communications.

Architecture

Follows hexagonal architecture:

recipient-groups/
├── domain/
│ └── recipient-groups-repository.domain.ts # Repository port (interface)
├── application/
│ └── recipient-groups.service.ts # Business logic / use cases
├── infrastructure/
│ └── recipient-groups.repository.ts # Kysely DB adapter
├── interfaces/
│ ├── recipient-groups.controller.ts # HTTP REST controller
│ └── dtos/
│ ├── create-recipient-group.dto.ts
│ ├── update-recipient-group.dto.ts
│ └── add-group-member.dto.ts
├── validators/
│ ├── email.validator.ts # Email validation decorators & utilities
│ └── phone.validator.ts # E.164 phone validation decorators & utilities
└── recipient-groups.module.ts

Domain Concepts

Recipient Group

A named container scoped to a business, used to group communication recipients. Has a unique name per business, optional description, and active/inactive state.

Table: communication_recipient_group

Group Member

A member of a group. Polymorphic by memberType:

Member TypeRequired FieldDescription
business_userbusinessUserIdLinks to an existing business user account
emailemailAddressStandalone email recipient
phonephoneNumberSMS recipient (E.164 format)
whatsappwhatsappNumberWhatsApp recipient (E.164 format)

Table: communication_group_member

Members are soft-deleted (marked isActive = false with removedAt timestamp).

API Endpoints

All endpoints require Bearer token authentication.

MethodPathDescription
POST/recipient-groupsCreate a new group
GET/recipient-groups/business/:businessIdList all active groups for a business
GET/recipient-groups/:idGet a specific group
PATCH/recipient-groups/:idUpdate a group
DELETE/recipient-groups/:idDelete a group (cascades to members)
POST/recipient-groups/:id/membersAdd a member to a group
GET/recipient-groups/:id/membersList all active members of a group
DELETE/recipient-groups/:id/members/:memberIdRemove (soft-delete) a member

Example: Create Group

POST /recipient-groups
{
"businessId": "550e8400-e29b-41d4-a716-446655440000",
"createdBy": "550e8400-e29b-41d4-a716-446655440001",
"name": "VIP Customers",
"description": "High-value customers for special promotions",
"isActive": true
}

Example: Add Email Member

POST /recipient-groups/:id/members
{
"businessId": "550e8400-e29b-41d4-a716-446655440000",
"createdBy": "550e8400-e29b-41d4-a716-446655440001",
"memberType": "email",
"emailAddress": "supplier@example.com",
"displayName": "Supplier Contact"
}

Example: Add Phone Member

POST /recipient-groups/:id/members
{
"businessId": "550e8400-e29b-41d4-a716-446655440000",
"createdBy": "550e8400-e29b-41d4-a716-446655440001",
"memberType": "phone",
"phoneNumber": "+14155552671",
"displayName": "John Doe"
}

Key Business Rules

  1. Group name uniqueness: Enforced at DB level per business (UNIQUE constraint on businessId + name).
  2. Duplicate prevention: A group cannot contain duplicate contacts. Checked via targeted DB queries per member type.
  3. Contact normalization: Emails are lowercased/trimmed. Phone numbers are normalized to E.164 format before storage.
  4. Multi-tenancy: All group queries are scoped by businessId.
  5. Soft deletes: Members are marked inactive rather than hard-deleted, preserving audit trail.

Integration Points

  • Recipient Rules (apps/backend/src/recipient-rules/): Rules reference groups by ID for communication targeting.
  • Communications (apps/backend/src/communications/): The RecipientResolverService resolves group members when sending communications.
  • Frontend PWA (apps/frontend-pwa/): UI for managing groups and members via recipientGroupsService.ts and React hooks.

Error Responses

StatusCondition
400Invalid DTO fields, missing required contact field for member type
401Missing or invalid authentication token
404Group or member not found
409Duplicate member (same email/phone/user already in group)