9.9 KiB
Instructions
Welcome to BNKops Influence, a tool for creating political change by targeting influential individuals within a community. This application is designed to help campaigns identify and engage with key figures who can sway public opinion and mobilize support.
Environment Setup
We want to deploy using a docker container. We use the new docker compose format. We use a .env file for environment variables. The developer likes to down, build, and up the container for testing / new features.
Wej are using NocoDB as a no-code database solution. You will need to set up a NocoDB instance and create the necessary tables for your application. Refer to the build-nocodb.sh file for the schema setup.
Project Overview
- Purpose: Create influence campaigns by identifying and engaging with key community figures over email, text, or phone.
- Backend: Node.js/Express, with NocoDB as the database (REST API).
- Frontend: Vanilla JS, Leaflet.js for mapping, modular code in
/public/js. - Admin Panel: Accessible via
/admin.htmlfor managing campaigns, users, and settings.
Campaign Settings Overview
The application supports flexible campaign configuration through the admin panel:
Available Campaign Settings
-
Show Email Count (
show_email_count) - Default: ON ✅- Displays total emails sent on campaign landing pages
- Provides social proof and engagement metrics
- Toggle via checkbox: "📊 Show Email Count" in admin panel
- Database: Boolean field in campaigns table
- Backend: Conditionally fetches count via
getCampaignEmailCount() - Frontend: Shows/hides stats banner in
campaign.js
-
Allow SMTP Email (
allow_smtp_email) - Default: ON ✅- Enables server-side email sending through configured SMTP
- Full logging and tracking of email delivery
-
Allow Mailto Link (
allow_mailto_link) - Default: ON ✅- Enables browser-based email client launching
- Useful fallback for users without SMTP
-
Collect User Info (
collect_user_info) - Default: ON ✅- Requests user name and email before participation
- Enables campaign tracking and follow-up
-
Allow Email Editing (
allow_email_editing) - Default: OFF ❌- Lets users customize email templates before sending
- Increases personalization but may dilute messaging
-
Cover Photo (
cover_photo) - Optional- Hero image for campaign landing pages
- Max 5MB, JPEG/PNG/GIF/WebP formats
-
Target Government Levels (
target_government_levels) - MultiSelect- Federal, Provincial, Municipal, School Board
- Filters which representatives are shown
-
Highlight Campaign (
highlight_campaign) - Default: OFF ❌- Displays the campaign prominently on the homepage
- Replaces the postal code search section with campaign information
- Only ONE campaign can be highlighted at a time
- Database: Boolean field in campaigns table
- Backend:
setHighlightedCampaign()ensures only one campaign is highlighted - Frontend:
main.jschecks on page load and replaces postal code section - Admin Panel: Shows ⭐ badge on highlighted campaign card
-
Campaign Status (
status) - Required- Draft: Testing only, hidden from public
- Active: Visible on main page
- Paused: Temporarily disabled
- Archived: Completed campaigns
Using Campaign Settings in Code
When creating new campaign features:
- Add field to
build-nocodb.shcampaigns table schema - Add field mapping in
nocodb.jsservice (createCampaign,updateCampaign) - Add field normalization in
campaigns.jscontroller - Add checkbox/input in
admin.htmlcreate and edit forms - Add form handling in
admin.js(read/write form data) - Implement frontend logic in
campaign.jsbased on setting value - Update
README.MDandfiles-explainer.mdwith new setting documentation
Example: Accessing settings in frontend:
// In campaign.js after loading campaign data
if (this.campaign.show_email_count && this.campaign.emailCount !== null) {
document.getElementById('email-count').textContent = this.campaign.emailCount;
document.getElementById('campaign-stats').style.display = 'block';
}
Example: Setting default values in backend:
// In campaigns.js createCampaign()
const campaignData = {
show_email_count: req.body.show_email_count ?? true, // Default ON
allow_email_editing: req.body.allow_email_editing ?? false, // Default OFF
// ... other fields
};
Key Principles
- Separation of Concerns: Keep logic for API, UI, and data management in their respective files/modules.
- Security: Never expose sensitive credentials. All API calls to NocoDB go through the backend.
- Scalability: Write code that is easy to extend (e.g., adding new location fields, new admin features).
- User Experience: Prioritize clear feedback, error handling, and mobile responsiveness.
- Documentation: Keep code well-documented and maintain the
Instructions.md,README.mdandfiles-explainer.mdfiles. - Modularity: Use modular JavaScript to keep code organized and reusable; try to avoid large monolithic scripts keeping functionality separated by feature with files no longer than 500 lines.
Directory Structure
app/- Node.js backend (Express server, routes, controllers, services, utils)app/public/- Frontend static files (HTML, CSS, JS)app/public/js/- Modular JavaScript for map, UI, auth, etc.app/controllers/- Express controllers for business logicapp/routes/- Express routers for API endpointsapp/services/- Backend services (NocoDB, geocoding, QR code)app/utils/- Shared backend utilities
Development Rules
- No inline event handlers. Always use
addEventListenerin JS files. - Update documentation. Always update
README.mdandfiles-explainer.mdwhen adding features or files. - Consistent style. Follow the existing code style and naming conventions.
- Error handling. Always provide user feedback for errors (both backend and frontend).
- Environment variables. Use
.envfor secrets/config, never hardcode sensitive data. - Testing. Test new features locally and ensure they do not break existing functionality.
- Pagination Use pagination for API endpoints returning large datasets to avoid performance issues. For example, getAll should be getAllPaginated
NocoDB Development Best Practices
Field Naming and Access
- Use Column Titles, Not Column Names: NocoDB expects column titles (e.g., "Campaign Slug") in API calls, not column names (e.g., "slug")
- Consistent Mapping: Always map between your application's field names and NocoDB's column titles in the service layer
- Where Clauses: Use column titles in where conditions:
(Campaign Slug,eq,value)not(slug,eq,value)
System Fields
- Avoid System Field Conflicts: Never create user-defined fields with names like
created_at,updated_atas they conflict with NocoDB system fields - Use System Fields: Leverage NocoDB's automatic system fields (
CreatedAt,UpdatedAt,CreatedBy, etc.) instead of creating your own - Sorting: Sort by system field titles:
-CreatedAtnot-created_at
Select Field Configuration
- Use colOptions: For SingleSelect and MultiSelect fields, always use
colOptionswith anoptionsarray - Never use dtxp: The
dtxpparameter is deprecated and causes corrupted select options - Example Structure:
{ "uidt": "SingleSelect", "colOptions": { "options": [ {"title": "draft", "color": "#d0f1fd"}, {"title": "active", "color": "#c2f5e8"} ] } }
Table Management
- Clean Recreation: When fixing table schema issues, delete and recreate tables rather than trying to modify corrupted structures
- Environment Cleanup: Remove duplicate table IDs from
.envfiles to avoid using old/deleted tables - Restart After Changes: Always restart the application after table recreation to pick up new table IDs
API Endpoints
- Use Correct API Versions:
- Data operations:
/db/data/v1/{projectId}/{tableId} - Meta operations:
/db/meta/tables/{tableId}
- Data operations:
- Field Validation: Test field access directly via NocoDB API before implementing in application logic
- Error Handling: NocoDB returns specific error codes like
FIELD_NOT_FOUND,TABLE_NOT_FOUND- handle these appropriately
Debugging Tips
- Direct API Testing: Use curl to test NocoDB API directly before implementing in application
- Check Table Metadata: Use
/db/meta/tables/{tableId}to inspect actual column names and titles - Verify System Fields: Check which fields are marked as
"system": trueto avoid conflicts - Log API Responses: Always log NocoDB API responses during development to understand the exact data structure returned
How to Add a Feature
First look through the existing codebase to understand where similar logic is implemented.
You can find a full listing of the files in the files-explainer.md file.
When adding a new feature, follow these steps:
- Plan: Decide where your logic belongs (backend controller, frontend JS, etc).
- Backend: Add/modify controllers, services, and routes as needed. Use NocoDB API via the service layer.
- Frontend: Add/modify JS modules in
/public/js. Update HTML/CSS as needed. - Document: Update
README.mdandfiles-explainer.md. - Test: Manually test your feature in both desktop and mobile views.
- Pull Request: Submit your changes for review.
Visuals
We want a clean modern look. We use Leaflet.js for mapping. We use vanilla JS for the frontend. We want a responsive design that works well on both desktop and mobile. We want clear feedback for user actions (loading spinners, success/error messages). We want error handling to provide appropriate feedback when errors occur (both backend and frontend).