Recipient Targeting System - Entity Relationship Diagram
High-Level Architectureβ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β COMMUNICATION CONFIGURATION β
β β
β business_communication_config β
β ββββββββββββββββββββββββββββββββββββββββββββββ β
β β Controls: WHAT + HOW + WHEN β β
β β β’ communication_type (low_stock_alert) β β
β β β’ channel (email, sms, whatsapp) β β
β β β’ timing, rate limits, etc. β β
β βββββββββββββββββββββ¬βββββββββββββββββββββββββ β
β β β
β β Extended by β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββ β
β β business_communication_recipient_rule β β
β β Controls: WHO receives β β
β β β’ targeting_type (role/group/ad_hoc) β β
β β β’ role_name OR group_id OR ad_hoc_* β β
β ββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Detailed Entity Relationship Diagramβ
ββββββββββββββββ
β business β
ββββββββββββββββ
β id (PK) β
β name β
ββββββββ¬ββββββββ
β
ββββββββββββββββββββΌβββββββββββββββββββ
β β β
β 1:N β 1:N β 1:N
βΌ βΌ βΌ
βββββββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββββββ
β business_user β β business_ β β communication_ β
βββββββββββββββββββββββ β communication_ β β recipient_group β
β id (PK) β β config β βββββββββββββββββββββββ
β business_id (FK) β βββββββββββββββββββ β id (PK) β
β user_id (FK) β β id (PK) β β business_id (FK) β
β unique_role_name β β business_id (FK)β β name β
β is_active β β comm_type β β description β
ββββββββββββ¬βββββββββββ β channel β β is_active β
β β is_enabled β ββββββββββββ¬βββββββββββ
β β is_automatic β β
β ββββββββββ¬βββββββββ β 1:N
β β β
β β 1:N βΌ
β βΌ ββββββββββββββββββββββββ
β ββββββββββββββββββββββββ β group_member β
β β business_ β ββββββββββββββββββββββββ
β β communication_ β β id (PK) β
β β recipient_rule β β group_id (FK) β
β ββββββββββββββββββββββββ β member_type [ENUM] β
β β id (PK) β β β’ business_user β
β β business_id (FK) β β β’ email β
β β communication_type β β β’ phone β
β β channel β β β’ whatsapp β
β β targeting_type [ENUM]β β β
β β β’ role β β Polymorphic: β
β β β’ group β β business_user_id (FK)ββββββ
β β β’ ad_hoc_email β β email_address β
β β β’ ad_hoc_phone β β phone_number β
β β β’ ad_hoc_whatsapp β β display_name β
β β β β is_active β
β β Polymorphic: β ββββββββββββββββββββββββ
β β role_name β
β β group_id (FK) βββββββββ
β β ad_hoc_email β
β β ad_hoc_phone β
β β ad_hoc_whatsapp β
β β priority β
β β is_active β
β ββββββββββββββββββββββββ
β
β
ββββββββββββββββ΄ββββββββββββββββ
β β
β RecipientResolverService β
β βββββββββββββββββββββββββ β
β Resolves rules to actual β
β recipients: β
β β
β 1. Query active rules β
β 2. For each rule: β
β β’ role β get users β
β β’ group β get members β
β β’ ad_hoc β use directly β
β 3. Deduplicate β
β 4. Return final list β
ββββββββββββββββ¬ββββββββββββββββ
β
β Returns list of
βΌ
ββββββββββββββββββββββββ
β ResolvedRecipient[] β
ββββββββββββββββββββββββ
β type β
β userId β
β contact (email/phone)β
β name β
β source (how selected)β
ββββββββββββ¬ββββββββββββ
β
β Used by
βΌ
ββββββββββββββββββββββββ
β CommunicationsServiceβ
β (Send messages) β
ββββββββββββ¬ββββββββββββ
β
β Creates
βΌ
ββββββββββββββββββββββββ ββββββββββββββββββββββββ
β communication β β communication_ β
ββββββββββββββββββββββββ 1:N β recipient_log β
β id (PK) βββββββββΊββββββββββββββββββββββββ
β business_id β β id (PK) β
β type β β communication_id (FK)β
β channel β β recipient_contact β
β recipient_contact β β recipient_name β
β status β β selection_method β
β ... β β selection_source_id β
ββββββββββββββββββββββββ β selected_at β
ββββββββββββββββββββββββ
(Audit Trail)
Table Relationships Explainedβ
1. business β communication_recipient_group (1:N)β
Each business can create multiple recipient groups.
Example:
- Business A has: "Finance Team", "Purchasing Team", "Emergency Team"
2. communication_recipient_group β communication_group_member (1:N)β
Each group has multiple members (polymorphic).
Example: "Finance Team" group contains:
- Member 1:
business_userβ John Doe (internal) - Member 2:
business_userβ Jane Smith (internal) - Member 3:
emailβ cpa@firm.com (external) - Member 4:
phoneβ +1234567890 (external)
3. business_user β communication_group_member (Optional FK)β
Group members can reference business users.
When to use:
member_type = 'business_user'β Setbusiness_user_idmember_type = 'email'β Setemail_addressmember_type = 'phone'β Setphone_number
4. business_communication_config β business_communication_recipient_ruleβ
Rules extend configs to specify recipients.
Relationship:
- Config says: "Low stock alerts via email are enabled"
- Rules say: "Send to inventory_manager role + Purchasing Team group"
Note: communication_config_id is optional. If null, rules apply to all channels for that type.
5. communication_recipient_group β business_communication_recipient_ruleβ
Rules can target groups.
Example:
-- Rule targeting a group
{
targeting_type: 'group',
group_id: 'purchasing-team-uuid'
}
6. communication β communication_recipient_log (1:N)β
Each communication logs all recipients selected.
Example:
For communication ID abc-123, log entries:
- john@company.com (selected via role: inventory_manager)
- jane@company.com (selected via role: inventory_manager)
- supplier@vendor.com (selected via group: Purchasing Team)
Data Flow Example: Low Stock Alertβ
1. Event: Low Stock Alert Created
ββ Alert ID: alert-123
Business ID: business-456
2. Handler: OnCreateLowStockAlertHandler
ββ Calls: RecipientResolverService.resolveRecipients(
business-456,
'low_stock_alert',
'email'
)
3. RecipientResolverService queries recipient rules:
Query: SELECT * FROM business_communication_recipient_rule
WHERE business_id = 'business-456'
AND communication_type = 'low_stock_alert'
AND channel = 'email'
AND is_active = true
Results:
ββββββββββ¬βββββββββββββββββββ¬ββββββββββββββββββ¬βββββββββββββββββ
β Rule 1 β targeting_type β role β β
β β role_name β inventory_mgr β β
ββββββββββΌβββββββββββββββββββΌββββββββββββββββββΌβββββββββββββββββ€
β Rule 2 β targeting_type β group β β
β β group_id β purchase-team β β
ββββββββββΌβββββββββββββββββββΌββββββββββββββββββΌβββββββββββββββββ€
β Rule 3 β targeting_type β ad_hoc_email β β
β β ad_hoc_email β supplier@... β β
ββββββββββ΄βββββββββββββββββββ΄ββββββββββββββββββ΄βββββββββββββββββ
4. Resolve Rule 1 (role = 'inventory_manager'):
Query: SELECT u.id, u.email, u.full_name
FROM business_user bu
JOIN user u ON u.id = bu.user_id
WHERE bu.business_id = 'business-456'
AND bu.unique_role_name = 'inventory_manager'
AND bu.is_active = true
Results:
- john@company.com (John Doe)
- jane@company.com (Jane Smith)
5. Resolve Rule 2 (group = 'purchase-team'):
Query: SELECT gm.*, u.email, u.full_name
FROM communication_group_member gm
LEFT JOIN business_user bu ON bu.id = gm.business_user_id
LEFT JOIN user u ON u.id = bu.user_id
WHERE gm.group_id = 'purchase-team'
AND gm.is_active = true
Results:
- staff1@company.com (Staff One) [business_user]
- staff2@company.com (Staff Two) [business_user]
- supplier@vendor.com (Main Supplier) [email]
6. Resolve Rule 3 (ad_hoc_email):
Direct use:
- supplier2@vendor.com (Backup Supplier)
7. Deduplicate recipients:
Combined list (6 total):
β john@company.com
β jane@company.com
β staff1@company.com
β staff2@company.com
β supplier@vendor.com
β supplier2@vendor.com
8. Send communications:
FOR EACH recipient:
- Create communication record
- Queue for sending
- Log recipient selection
9. Log recipient selections:
INSERT INTO communication_recipient_log:
- john@company.com (method: role, source: rule-1)
- jane@company.com (method: role, source: rule-1)
- staff1@company.com (method: group, source: rule-2)
- staff2@company.com (method: group, source: rule-2)
- supplier@vendor.com (method: group, source: rule-2)
- supplier2@vendor.com (method: ad_hoc, source: rule-3)
10. Result: 6 emails sent β
Polymorphic Relationshipsβ
Group Members (Polymorphic by Type)β
member_type = 'business_user'
ββ business_user_id β NOT NULL
ββ email_address β NULL
ββ phone_number β NULL
member_type = 'email'
ββ business_user_id β NULL
ββ email_address β NOT NULL
ββ phone_number β NULL
member_type = 'phone'
ββ business_user_id β NULL
ββ email_address β NULL
ββ phone_number β NOT NULL
Recipient Rules (Polymorphic by Targeting Type)β
targeting_type = 'role'
ββ role_name β NOT NULL
ββ group_id β NULL
ββ ad_hoc_* β NULL
targeting_type = 'group'
ββ role_name β NULL
ββ group_id β NOT NULL
ββ ad_hoc_* β NULL
targeting_type = 'ad_hoc_email'
ββ role_name β NULL
ββ group_id β NULL
ββ ad_hoc_email β NOT NULL
ββ other ad_hoc_* β NULL
Indexes for Performanceβ
Critical Query Pathsβ
1. Resolve Rules for Business + Type + Channelβ
-- Index on business_communication_recipient_rule
CREATE INDEX idx_recipient_rule_type_channel
ON business_communication_recipient_rule (business_id, communication_type, channel);
2. Resolve Role to Usersβ
-- Index on business_user
CREATE INDEX idx_business_user_role
ON business_user (business_id, unique_role_name, is_active);
3. Resolve Group Membersβ
-- Index on communication_group_member
CREATE INDEX idx_group_member_active
ON communication_group_member (group_id, is_active);
4. Query Recipient Logsβ
-- Index on communication_recipient_log
CREATE INDEX idx_recipient_log_communication
ON communication_recipient_log (communication_id);
Summaryβ
The recipient targeting system uses:
- 4 new tables for flexible recipient configuration
- Polymorphic relationships for extensibility
- Service-based resolution for clean separation of concerns
- Audit logging for compliance and debugging
The design allows businesses to configure complex recipient scenarios without code changes while maintaining full audit trails and performance through proper indexing.