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 Type | Required Field | Description |
|---|---|---|
business_user | businessUserId | Links to an existing business user account |
email | emailAddress | Standalone email recipient |
phone | phoneNumber | SMS recipient (E.164 format) |
whatsapp | whatsappNumber | WhatsApp 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.
| Method | Path | Description |
|---|---|---|
POST | /recipient-groups | Create a new group |
GET | /recipient-groups/business/:businessId | List all active groups for a business |
GET | /recipient-groups/:id | Get a specific group |
PATCH | /recipient-groups/:id | Update a group |
DELETE | /recipient-groups/:id | Delete a group (cascades to members) |
POST | /recipient-groups/:id/members | Add a member to a group |
GET | /recipient-groups/:id/members | List all active members of a group |
DELETE | /recipient-groups/:id/members/:memberId | Remove (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
- Group name uniqueness: Enforced at DB level per business (UNIQUE constraint on
businessId + name). - Duplicate prevention: A group cannot contain duplicate contacts. Checked via targeted DB queries per member type.
- Contact normalization: Emails are lowercased/trimmed. Phone numbers are normalized to E.164 format before storage.
- Multi-tenancy: All group queries are scoped by
businessId. - 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/): TheRecipientResolverServiceresolves group members when sending communications. - Frontend PWA (
apps/frontend-pwa/): UI for managing groups and members viarecipientGroupsService.tsand React hooks.
Error Responses
| Status | Condition |
|---|---|
| 400 | Invalid DTO fields, missing required contact field for member type |
| 401 | Missing or invalid authentication token |
| 404 | Group or member not found |
| 409 | Duplicate member (same email/phone/user already in group) |