# Custom Recipients Implementation ## Overview This feature allows campaigns to target any email address (custom recipients) instead of or in addition to elected representatives from the Represent API. ## Implementation Summary ### ✅ Backend (Complete) #### 1. Database Schema (`scripts/build-nocodb.sh`) - **custom_recipients table** with fields: - `id` - Primary key - `campaign_id` - Links to campaigns table - `campaign_slug` - Campaign identifier - `recipient_name` - Full name of recipient - `recipient_email` - Email address - `recipient_title` - Job title/position (optional) - `recipient_organization` - Organization name (optional) - `notes` - Internal notes (optional) - `is_active` - Boolean flag - **campaigns table** updated: - Added `allow_custom_recipients` boolean field (default: false) #### 2. Backend Controller (`app/controllers/customRecipients.js`) Full CRUD operations: - `getRecipientsByCampaign(req, res)` - Fetch all recipients for a campaign - `createRecipient(req, res)` - Add single recipient with validation - `bulkCreateRecipients(req, res)` - Import multiple recipients from CSV - `updateRecipient(req, res)` - Update recipient details - `deleteRecipient(req, res)` - Delete single recipient - `deleteAllRecipients(req, res)` - Clear all recipients for a campaign #### 3. NocoDB Service (`app/services/nocodb.js`) - `getCustomRecipients(campaignId)` - Query by campaign ID - `getCustomRecipientsBySlug(campaignSlug)` - Query by slug - `createCustomRecipient(recipientData)` - Create with field mapping - `updateCustomRecipient(recipientId, updateData)` - Partial updates - `deleteCustomRecipient(recipientId)` - Single deletion - `deleteCustomRecipientsByCampaign(campaignId)` - Bulk deletion #### 4. API Routes (`app/routes/api.js`) All routes protected with `requireNonTemp` authentication: - `GET /api/campaigns/:slug/custom-recipients` - List all recipients - `POST /api/campaigns/:slug/custom-recipients` - Create single recipient - `POST /api/campaigns/:slug/custom-recipients/bulk` - Bulk import - `PUT /api/campaigns/:slug/custom-recipients/:id` - Update recipient - `DELETE /api/campaigns/:slug/custom-recipients/:id` - Delete recipient - `DELETE /api/campaigns/:slug/custom-recipients` - Delete all recipients #### 5. Campaign Controller Updates (`app/controllers/campaigns.js`) - Added `allow_custom_recipients` field to all campaign CRUD operations - Field normalization in 5+ locations for consistent API responses ### ✅ Frontend (Complete) #### 1. JavaScript Module (`app/public/js/custom-recipients.js`) Comprehensive module with: - **CRUD Operations**: Add, edit, delete recipients - **Bulk Import**: CSV file upload or paste with parsing - **Validation**: Email format validation - **UI Management**: Dynamic recipient list display with cards - **Error Handling**: User-friendly error messages - **XSS Protection**: HTML escaping for security Key methods: ```javascript CustomRecipients.init(campaignSlug) // Initialize module CustomRecipients.loadRecipients(slug) // Load from API CustomRecipients.displayRecipients() // Render list // Plus handleAddRecipient, handleEditRecipient, handleDeleteRecipient, etc. ``` #### 2. Admin Panel Integration (`app/public/admin.html` + `app/public/js/admin.js`) - **Create Form**: Checkbox to enable custom recipients - **Edit Form**: - Checkbox with show/hide toggle - Add recipient form (5 fields: name, email, title, organization, notes) - Bulk CSV import button with modal - Recipients list with edit/delete actions - Clear all button - **JavaScript Integration**: - `toggleCustomRecipientsSection()` - Show/hide based on checkbox - `setupCustomRecipientsHandlers()` - Event listeners for checkbox - Auto-load recipients when editing campaign with feature enabled - Form data includes `allow_custom_recipients` in create/update #### 3. Bulk Import Modal (`app/public/admin.html`) Complete modal with: - CSV format instructions - File upload input - Paste textarea for direct CSV input - Import results display with success/failure details - CSV format: `recipient_name,recipient_email,recipient_title,recipient_organization,notes` #### 4. CSS Styling (`app/public/admin.html`) - `.recipient-card` - Card layout with hover effects - `.recipient-info` - Name, email, metadata display - `.recipient-actions` - Edit/delete icon buttons with hover colors - `.bulk-import-help` - Modal styling - Responsive grid layout ## Usage ### For Administrators: 1. **Create Campaign**: - Check "Allow Custom Recipients" during creation - An info section will appear explaining that recipients can be added after campaign is created - Complete the campaign creation 2. **Edit Campaign**: - Navigate to the Edit tab and select your campaign - Check "Allow Custom Recipients" to enable the feature - The custom recipients management section will appear below the checkbox 3. **Add Single Recipient**: - Fill in name (required) and email (required) - Optionally add title, organization, notes - Click "Add Recipient" 4. **Bulk Import**: - Click "Bulk Import (CSV)" button - Upload CSV file or paste CSV data - CSV format: `recipient_name,recipient_email,recipient_title,recipient_organization,notes` - First row can be header (will be skipped if contains "recipient_name") - Results show success/failure for each row 5. **Edit Recipient**: - Click edit icon on recipient card - Form populates with current data - Make changes and click "Update Recipient" - Or click "Cancel" to revert 6. **Delete Recipients**: - Single: Click delete icon on card - All: Click "Clear All" button ### API Examples: ```bash # Create recipient curl -X POST /api/campaigns/my-campaign/custom-recipients \ -H "Content-Type: application/json" \ -d '{ "recipient_name": "Jane Doe", "recipient_email": "jane@example.com", "recipient_title": "CEO", "recipient_organization": "Tech Corp" }' # Bulk import curl -X POST /api/campaigns/my-campaign/custom-recipients/bulk \ -H "Content-Type: application/json" \ -d '{ "recipients": [ {"recipient_name": "John Smith", "recipient_email": "john@example.com"}, {"recipient_name": "Jane Doe", "recipient_email": "jane@example.com"} ] }' # Get all recipients curl /api/campaigns/my-campaign/custom-recipients # Update recipient curl -X PUT /api/campaigns/my-campaign/custom-recipients/123 \ -H "Content-Type: application/json" \ -d '{"recipient_title": "CTO"}' # Delete recipient curl -X DELETE /api/campaigns/my-campaign/custom-recipients/123 # Delete all recipients curl -X DELETE /api/campaigns/my-campaign/custom-recipients ``` ## Security Features - **Authentication**: All API routes require non-temporary user session - **Validation**: Email format validation on client and server - **XSS Protection**: HTML escaping in display - **Campaign Check**: Verifies campaign exists and feature is enabled - **Input Sanitization**: express-validator on API endpoints ## Next Steps (TODO) 1. **Dashboard Integration**: Add same UI to `dashboard.html` for regular users 2. **Campaign Display**: Update `campaign.js` to show custom recipients alongside elected officials 3. **Email Composer**: Ensure custom recipients work in email sending flow 4. **Testing**: Comprehensive end-to-end testing 5. **Documentation**: Update main README and files-explainer ## Files Modified/Created ### Backend: - ✅ `scripts/build-nocodb.sh` - Database schema - ✅ `app/controllers/customRecipients.js` - NEW FILE (282 lines) - ✅ `app/services/nocodb.js` - Service methods - ✅ `app/routes/api.js` - API endpoints - ✅ `app/controllers/campaigns.js` - Field updates ### Frontend: - ✅ `app/public/js/custom-recipients.js` - NEW FILE (538 lines) - ✅ `app/public/js/admin.js` - Integration code - ✅ `app/public/admin.html` - UI components and forms ### Documentation: - ✅ `CUSTOM_RECIPIENTS_IMPLEMENTATION.md` - This file ## Testing Checklist - [ ] Database table creation (run build-nocodb.sh) - [ ] Create campaign with custom recipients enabled - [ ] Add single recipient via form - [ ] Edit recipient information - [ ] Delete single recipient - [ ] Bulk import via CSV file - [ ] Bulk import via paste - [ ] Clear all recipients - [ ] Toggle checkbox on/off - [ ] Verify API authentication - [ ] Test with campaign where feature is disabled - [ ] Check recipient display on campaign page - [ ] Test email sending to custom recipients ## Known Limitations 1. Custom recipients can only be added AFTER campaign is created (not during creation) 2. Dashboard UI not yet implemented (admin panel only) 3. Campaign display page doesn't show custom recipients yet 4. CSV import uses simple comma splitting (doesn't handle quoted commas) 5. No duplicate email detection ## Future Enhancements - [ ] Duplicate email detection/prevention - [ ] Import validation preview before saving - [ ] Export recipients to CSV - [ ] Recipient groups/categories - [ ] Import from external sources (Google Contacts, etc.) - [ ] Recipient engagement tracking - [ ] Custom fields for recipients - [ ] Merge tags in email templates using recipient data