# 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.html` for managing campaigns, users, and settings. ## Campaign Settings Overview The application supports flexible campaign configuration through the admin panel: ### Available Campaign Settings 1. **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` 2. **Allow SMTP Email** (`allow_smtp_email`) - **Default: ON** ✅ - Enables server-side email sending through configured SMTP - Full logging and tracking of email delivery 3. **Allow Mailto Link** (`allow_mailto_link`) - **Default: ON** ✅ - Enables browser-based email client launching - Useful fallback for users without SMTP 4. **Collect User Info** (`collect_user_info`) - **Default: ON** ✅ - Requests user name and email before participation - Enables campaign tracking and follow-up 5. **Allow Email Editing** (`allow_email_editing`) - **Default: OFF** ❌ - Lets users customize email templates before sending - Increases personalization but may dilute messaging 6. **Cover Photo** (`cover_photo`) - **Optional** - Hero image for campaign landing pages - Max 5MB, JPEG/PNG/GIF/WebP formats 7. **Target Government Levels** (`target_government_levels`) - **MultiSelect** - Federal, Provincial, Municipal, School Board - Filters which representatives are shown 8. **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.sh` campaigns table schema - Add field mapping in `nocodb.js` service (`createCampaign`, `updateCampaign`) - Add field normalization in `campaigns.js` controller - Add checkbox/input in `admin.html` create and edit forms - Add form handling in `admin.js` (read/write form data) - Implement frontend logic in `campaign.js` based on setting value - Update `README.MD` and `files-explainer.md` with new setting documentation **Example: Accessing settings in frontend:** ```javascript // 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:** ```javascript // 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.md` and `files-explainer.md` files. - **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 logic - `app/routes/` - Express routers for API endpoints - `app/services/` - Backend services (NocoDB, geocoding, QR code) - `app/utils/` - Shared backend utilities ## Development Rules - **No inline event handlers.** Always use `addEventListener` in JS files. - **Update documentation.** Always update `README.md` and `files-explainer.md` when 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 `.env` for 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_at` as 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: `-CreatedAt` not `-created_at` ### Select Field Configuration - **Use colOptions:** For SingleSelect and MultiSelect fields, always use `colOptions` with an `options` array - **Never use dtxp:** The `dtxp` parameter is deprecated and causes corrupted select options - **Example Structure:** ```json { "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 `.env` files 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}` - **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": true` to 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: 1. **Plan:** Decide where your logic belongs (backend controller, frontend JS, etc). 2. **Backend:** Add/modify controllers, services, and routes as needed. Use NocoDB API via the service layer. 3. **Frontend:** Add/modify JS modules in `/public/js`. Update HTML/CSS as needed. 4. **Document:** Update `README.md` and `files-explainer.md`. 5. **Test:** Manually test your feature in both desktop and mobile views. 6. **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).