- Implemented a comprehensive health check utility to monitor system dependencies including NocoDB, SMTP, Represent API, disk space, and memory usage. - Created a logger utility using Winston for structured logging with daily rotation and various log levels. - Developed a metrics utility using Prometheus client to track application performance metrics such as email sends, HTTP requests, and user activity. - Added a backup script for automated backups of NocoDB data, uploaded files, and environment configurations with optional S3 support. - Introduced a toggle script to switch between development (MailHog) and production (ProtonMail) SMTP configurations.
BNKops Influence Campaign Tool
A comprehensive web application that helps Alberta residents connect with their elected representatives across all levels of government. Users can find their representatives by postal code and send direct emails to advocate for important issues.
Features
- Representative Lookup: Find elected officials by Alberta postal code (T prefixed)
- Multi-Level Government: Displays federal MPs, provincial MLAs, and municipal representatives
- Contact Information: Shows photos, email addresses, phone numbers, and office locations
- Direct Email: Built-in email composer to contact representatives
- Campaign Management: Create and manage advocacy campaigns with customizable settings
- Public Campaigns Grid: Homepage display of all active campaigns for easy discovery and participation
- Response Wall: Community-driven platform for sharing and voting on representative responses
- Email Count Display: Optional engagement metrics showing total emails sent per campaign
- Smart Caching: Fast performance with NocoDB caching and graceful fallback to live API
- Responsive Design: Works seamlessly on desktop and mobile devices
- Real-time Data: Integrates with Represent OpenNorth API for up-to-date information
Technology Stack
- Backend: Node.js with Express.js
- Database: NocoDB (REST API)
- External API: Represent OpenNorth Canada API
- Frontend: Vanilla JavaScript, HTML5, CSS3
- Email: SMTP integration
- Deployment: Docker with docker-compose
- Rate Limiting: Express rate limiter for API protection
Quick Start
Prerequisites
- Docker and Docker Compose
- Access to existing NocoDB instance
- SMTP email configuration
Installation
-
Clone and navigate to the project:
cd /path/to/changemaker.lite/influence -
Configure environment:
cp .env.example .env # Edit .env with your configuration -
Set up NocoDB tables:
./scripts/build-nocodb.sh -
Start the application:
docker compose up --build -
Access the application:
- Open http://localhost:3333
- Enter an Alberta postal code (e.g., T5N4B8)
- View your representatives and send emails
Development Mode
Email Testing with MailHog
For development and testing, the application includes MailHog integration to safely test email functionality without sending real emails to elected officials.
Quick Setup for Development
-
Use development configuration:
# Your .env should include these settings for development: NODE_ENV=development EMAIL_TEST_MODE=true SMTP_HOST=mailhog SMTP_PORT=1025 SMTP_USER=test SMTP_PASS=test TEST_EMAIL_RECIPIENT=your-email@example.com -
Start with MailHog included:
docker compose up --build -
Access development tools:
- Application: http://localhost:3333
- Email Testing Interface: http://localhost:3333/email-test.html (admin login required)
- MailHog Web UI: http://localhost:8025 (view all caught emails)
Email Testing Features
Test Mode Benefits:
- ✅ All emails redirected to your test recipient
- ✅ Original recipient shown in subject line:
[TEST - Original: real@email.com] Subject - ✅ Safe testing without spamming elected officials
- ✅ Complete email logging with test mode indicators
Email Testing Interface (/email-test.html):
- Quick Test: Send test email with one click
- Email Preview: See exactly how emails will look before sending
- Custom Composition: Test with your own subject and message content
- Email Logs: View all sent emails with test/live filtering
- SMTP Diagnostics: Test connection and troubleshoot issues
MailHog Web Interface (http://localhost:8025):
- View all emails caught during development
- Inspect email content, headers, and formatting
- Search and filter caught emails
- No emails leave your local environment
Development Workflow
-
Safe Development:
# Ensure test mode is enabled EMAIL_TEST_MODE=true # Start development environment docker compose up --build -
Test Email Functionality:
- Use the main app to send emails (they'll be redirected)
- Check MailHog UI to see the actual email content
- Use
/email-test.htmlfor advanced testing and preview
-
Production Deployment:
# Switch to production SMTP settings EMAIL_TEST_MODE=false SMTP_HOST=smtp.your-provider.com SMTP_USER=your-real-email@domain.com SMTP_PASS=your-real-password # Restart application docker compose restart
Development Environment Variables
# Development Mode Configuration
NODE_ENV=development
EMAIL_TEST_MODE=true
# MailHog SMTP (for development)
SMTP_HOST=mailhog
SMTP_PORT=1025
SMTP_SECURE=false
SMTP_USER=test
SMTP_PASS=test
SMTP_FROM_EMAIL=dev@albertainfluence.local
SMTP_FROM_NAME="BNKops Influence Campaign (DEV)"
# Email Testing
TEST_EMAIL_RECIPIENT=developer@example.com
# Production SMTP (commented out for dev)
# SMTP_HOST=smtp.protonmail.ch
# SMTP_PORT=587
# SMTP_USER=your-production-email@domain.com
# SMTP_PASS=your-production-password
Configuration
Environment Variables (.env)
# Server Configuration
NODE_ENV=production
PORT=3333
# NocoDB Configuration
NOCODB_API_URL=https://db.cmlite.org
NOCODB_API_TOKEN=your_nocodb_token
NOCODB_PROJECT_ID=your_project_id
# Email Configuration (SMTP)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your_email@gmail.com
SMTP_PASS=your_app_password
SMTP_FROM_NAME=BNKops Influence Campaign
SMTP_FROM_EMAIL=your_email@gmail.com
# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100
Campaign Management Guide
Creating a Campaign
-
Access Admin Panel: Navigate to
/admin.htmland log in with admin credentials -
Create New Campaign: Click "Create Campaign" button
-
Configure Basic Settings:
- Campaign Title: Short, descriptive name (becomes the URL slug)
- Description: Brief overview shown on the campaign landing page
- Call to Action: Motivational message encouraging participation
-
Set Email Template:
- Email Subject: Pre-filled subject line for emails
- Email Body: Default message template (users may edit if allowed)
-
Upload Cover Photo (Optional):
- Click "Choose File" to upload a hero image
- Supported formats: JPEG, PNG, GIF, WebP
- Maximum size: 5MB
- Image displays as campaign page banner
-
Configure Campaign Settings:
- 📧 Allow SMTP Email: Enable server-side email sending
- 🔗 Allow Mailto Link: Enable browser-based mailto: links
- 👤 Collect User Info: Request user name and email
- 📊 Show Email Count: Display total emails sent (engagement metric)
- ✏️ Allow Email Editing: Let users customize email template
- 🎯 Target Government Levels: Select Federal, Provincial, Municipal, School Board
-
Set Campaign Status:
- Draft: Hidden from public, testing mode
- Active: Visible to public on main page
- Paused: Temporarily disabled
- Archived: Completed campaigns
-
Save Campaign: Click "Create Campaign" to publish
Public Campaigns Display
The homepage automatically displays all active campaigns in a responsive grid below the representative lookup section.
Features:
- Automatic Display: Only active campaigns (status="active") are shown publicly
- Campaign Cards: Each campaign displays as an attractive card with:
- Cover photo (if uploaded) or gradient background
- Campaign title and truncated description
- Target government level badges (Federal, Provincial, Municipal, etc.)
- Email count badge (if enabled via campaign settings)
- "Learn More & Participate" call-to-action
- Responsive Grid: Automatically adjusts columns based on screen size
- Desktop: 3-4 columns
- Tablet: 2 columns
- Mobile: 1 column
- Click Navigation: Users can click any campaign card to visit the full campaign page
- Smart Loading: Shows loading state while fetching campaigns, gracefully hides section if no active campaigns exist
- Security: HTML content is escaped to prevent XSS attacks
- Sorting: Campaigns display newest first by creation date
Public API Endpoint: /api/public/campaigns (no authentication required)
- Returns only campaigns with
status='active' - Includes email counts when
show_email_count=true - Optimized for performance with minimal data transfer
Email Count Display Feature
The Show Email Count setting controls whether campaign pages display total engagement metrics.
When Enabled (✅ checked):
- Campaign page shows: "X Albertans have sent emails through this campaign"
- Provides social proof and encourages participation
- Updates in real-time as users send emails
- Displays prominently above the call-to-action
When Disabled (❌ unchecked):
- Email count section is hidden
- Useful for sensitive campaigns or privacy concerns
- Engagement metrics still tracked in admin panel
Best Practices:
- ✅ Enable for public awareness campaigns to show momentum
- ✅ Enable for volunteer recruitment to demonstrate support
- ❌ Disable for personal advocacy or sensitive issues
- ❌ Disable for new campaigns until participation grows
Technical Details:
- Count includes all successfully sent emails via campaign
- Tracks both SMTP-sent and mailto-initiated emails (if logged)
- Admin panel always shows counts regardless of public display setting
- Database field:
show_email_count(checkbox, default: true)
Editing Campaigns
- Navigate to Admin Panel → "Campaigns" tab
- Find campaign card and click "Edit"
- Modify any settings including the email count display toggle
- Save changes - updates apply immediately to public-facing page
Campaign Analytics
Access campaign performance metrics in the Admin Panel:
- Total emails sent per campaign
- User participation rates
- Email delivery status
- Representative contact distribution
API Endpoints
Representatives
GET /api/representatives/by-postal/:postalCode- Get representatives by postal codePOST /api/representatives/refresh-postal/:postalCode- Refresh cached data
POST /api/emails/send- Send email to representativeGET /api/emails/logs- Get email sending logs (with filters)
Email Testing (Development)
POST /api/emails/preview- Preview email without sending (admin only)POST /api/emails/test- Send test email to configured recipient (admin only)GET /api/test-smtp- Test SMTP connection (admin only)
Health
GET /api/health- Application health checkGET /api/test-represent- Test Represent API connection
Database Schema
Campaigns Table
- slug, title, description
- email_subject, email_body
- call_to_action, cover_photo
- status (draft/active/paused/archived)
- allow_smtp_email, allow_mailto_link
- collect_user_info, show_email_count
- allow_email_editing
- target_government_levels (MultiSelect)
- created_by_user_id, created_by_user_email, created_by_user_name
Campaign Emails Table
- campaign_id, user_name, user_email, user_postal_code
- recipient_name, recipient_email, recipient_level
- subject, message, status, sent_at
Representatives Table
- postal_code, name, email, district_name
- elected_office, party_name, representative_set_name
- url, photo_url, cached_at
Email Logs Table
- recipient_email, recipient_name, sender_email
- subject, message, status, sent_at
Postal Codes Table
- postal_code, city, province
- centroid_lat, centroid_lng, last_updated
Users Table
- email, password_hash, name
- role (admin/user), status (active/temporary)
- expires_at, last_login
Development
Project Structure
influence/
├── app/
│ ├── controllers/ # Business logic
│ ├── routes/ # API routes
│ ├── services/ # External integrations
│ ├── utils/ # Helper functions
│ ├── middleware/ # Express middleware
│ ├── public/ # Frontend assets
│ └── server.js # Express app entry point
├── scripts/
│ └── build-nocodb.sh # Database setup
├── docker-compose.yml # Container orchestration
├── Dockerfile # Container definition
└── .env # Environment configuration
Key Components
- RepresentativesController: Handles postal code lookups and caching
- EmailController: Manages email composition, sending, and testing
- NocoDBService: Database operations with error handling
- RepresentAPI: Integration with OpenNorth Represent API
- EmailService: SMTP email functionality with test mode support
- Email Testing System: Preview, test, and log email functionality for development
Features in Detail
Smart Caching System
- First request fetches from Represent API and caches in NocoDB
- Subsequent requests served from cache for fast performance
- Graceful fallback to API when NocoDB is unavailable
- Automatic error recovery and retry logic
Representative Display
- Shows photo with fallback to initials
- Contact information including phone and address
- Party affiliation and government level
- Direct links to official profiles
Campaign System
- Campaign Creation: Create advocacy campaigns with custom titles, descriptions, and email templates
- Cover Photos: Upload hero images for campaign landing pages (JPEG/PNG/GIF/WebP, max 5MB)
- Flexible Email Methods: Choose between SMTP email or mailto links for user convenience
- User Info Collection: Optional name/email collection for campaign tracking
- Email Count Display: Show total engagement metrics on campaign pages (toggle on/off)
- Email Editing: Allow users to customize campaign email templates (optional)
- Target Levels: Select which government levels to target (Federal/Provincial/Municipal/School Board)
- Campaign Status: Draft, Active, Paused, or Archived workflow states
Response Wall Feature
The Response Wall creates transparency and accountability by allowing campaign participants to share responses they receive from elected representatives.
Key Features:
- Public Response Sharing: Constituents can post responses received via email, letter, phone, meetings, or social media
- Community Voting: Upvote system highlights helpful and representative responses
- Verification System: Admin-moderated verification badges for authentic responses
- Screenshot Support: Upload visual proof of responses (images up to 5MB)
- Anonymous Posting: Option to share responses without revealing identity
- Filtering & Sorting: Filter by government level, sort by recent/upvotes/verified
- Engagement Statistics: Track total responses, verified count, and community upvotes
- Moderation Queue: Admin panel for approving, rejecting, or verifying submitted responses
- Campaign Integration: Response walls linked to specific campaigns for contextualized feedback
Access Response Wall:
- Via campaign page: Add
?campaign=your-campaign-slugparameter to/response-wall.html - Admin moderation: Navigate to "Response Moderation" tab in admin panel
- Public viewing: All approved responses visible to encourage participation
Moderation Workflow:
- Users submit responses with required details (representative name, level, type, response text)
- Submissions enter "pending" status in moderation queue
- Admins review and approve/reject from admin panel
- Approved responses appear on public Response Wall
- Admins can mark verified responses with special badge
- Community upvotes highlight most impactful responses
QR Code Sharing Feature
The application includes dynamic QR code generation for easy campaign and response wall sharing.
Key Features:
- Campaign QR Codes: Generate scannable QR codes for campaign pages
- Response Wall QR Codes: Share response walls with QR codes for mobile scanning
- High-Quality Generation: 400x400px PNG images with high error correction (level H)
- Download Support: One-click download of QR code images for printing or sharing
- Social Integration: QR code button alongside social share buttons (Facebook, Twitter, LinkedIn, etc.)
- Caching: QR codes cached for 1 hour to improve performance
How to Use:
- Visit any campaign page or response wall
- Click the QR code icon (📱) in the social share buttons section
- A modal appears with the generated QR code
- Scan with any smartphone camera to visit the page
- Click "Download QR Code" to save the image for printing or sharing
Technical Implementation:
- Backend endpoint:
GET /api/campaigns/:slug/qrcode?type=campaign|response-wall - Uses
qrcodenpm package for generation - Proper MIME type and cache headers
- Modal UI with download functionality
Use Cases:
- Print QR codes on flyers and posters for offline campaign promotion
- Share QR codes in presentations and meetings
- Include in email newsletters for mobile-friendly access
- Display at events for easy sign-up
Email Integration
- Modal-based email composer
- Pre-filled recipient information
- SMTP sending with delivery confirmation
- Email history and logging
Error Handling
- Comprehensive error logging
- User-friendly error messages
- API fallback mechanisms
- Rate limiting protection
Production Deployment
Docker Production
# Build and start in production mode
docker compose -f docker-compose.yml up -d --build
# View logs
docker compose logs -f app
# Scale if needed
docker compose up --scale app=2
Monitoring
- Health check endpoint:
/api/health - Application logs via Docker
- NocoDB integration status monitoring
- Email delivery tracking
Troubleshooting
Common Issues
-
NocoDB Connection Errors:
- Check API URL and token in .env
- Run
./scripts/build-nocodb.shto setup tables - Application works without NocoDB (API fallback)
-
Email Not Sending:
- Verify SMTP credentials in .env
- Check spam/junk folders
- Review email logs via API endpoint
- In development: Check MailHog UI at http://localhost:8025
- Use email testing interface at
/email-test.htmlfor diagnostics
-
No Representatives Found:
- Ensure postal code starts with 'T' (Alberta)
- Check Represent API status
- Try different postal code format
Log Analysis
# View application logs
docker compose logs app
# Follow logs in real-time
docker compose logs -f app
# Check specific errors
docker compose logs app | grep ERROR
Contributing
This is part of the larger changemaker.lite project. Follow the established patterns for:
- Error handling and logging
- API response formats
- Database integration
- Frontend component structure
License
Part of the changemaker.lite project ecosystem.