Files
docs/src/content/docs/projects/a4p-bot.md
T
hikari 3789116d1f
Node.js CI / CI (push) Successful in 1m52s
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 3m13s
style: apply style guide fonts, colours, and readability fixes (#31)
## Summary

- Replaces custom "Vampyr" font with style guide fonts (Griffy, Kalam, Creepster, Henny Penny)
- Fixes illegible tagline, search placeholder, search results, shortcut badge, theme dropdown, and active sidebar item across light and dark modes
- Applies witchy code themes for light and dark mode
- Fixes invalid `env` language in code blocks (replaced with `sh`)
- Fixes invalid `message` aside icon in contact page (replaced with `star`)

 This PR was created with help from Hikari~ 🌸

Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com>
Reviewed-on: #31
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
2026-03-03 17:54:53 -08:00

27 KiB

title
title
Artists4Palestine Bot

Artists4Palestine Bot (hereinafter the "Application") is a Discord bot designed to facilitate the Art for Palestine charity event. The Application serves as an automated bridge between Airtable, Trello, and Discord to manage art commission requests, artist assignments, delivery tracking, and support tickets for the charity event.

1. User Documentation

This section is for those interacting with a live instance of the Application.

1.1. Getting Started

The Art for Palestine Bot is available on the Art for Palestine Discord server. Once you join the server, you will automatically be assigned the member role and can begin interacting with the bot's features.

1.2. Requesting Art Commissions

Art commission requests are submitted through an Airtable form (external to Discord). Once submitted, your request will automatically appear in the designated commission channel where artists can view and claim it. Your request should include:

  • Your name
  • Preferred contact method (Email, Discord, or Twitter)
  • Your contact handle/username
  • Description of the art you would like drawn
  • Reference images (optional)
  • Any additional notes or requirements

1.3. Artist Features

1.3.1. Claiming Art Commissions

As an artist, you can claim art commissions by reacting to commission posts in the art commission channel (ID: 1172568787330019340).

Important Notes:

  • You can only claim up to 2 commissions at a time
  • Claiming a commission creates a private thread for coordination
  • The thread will include your mention and the requester's information

1.3.2. Submitting Completed Artwork

Once you've completed the artwork:

  1. Post the completed artwork as an image attachment in the private thread
  2. The bot will automatically forward your submission to the distribution channel
  3. Your thread will be archived
  4. The commission will be removed from your active count

1.3.3. Art Reminders

The bot sends automated reminders to help manage workload:

  • Unclaimed Art Reminders: Sent Monday, Wednesday, and Friday at 9:00 AM
  • Unfinished Art Reminders: Sent Saturday at 9:00 AM

1.4. Distribution Features

1.4.1. Claiming Distributions

Distribution team members can claim distribution tasks by reacting to posts in the distribution channel (ID: 1173061747737903315). Similar to art commissions:

  • Maximum 2 concurrent distributions per member
  • Creates a private coordination thread
  • Includes recipient and artwork details

1.4.2. Confirming Deliveries

To confirm a distribution:

  1. Deliver the artwork to the recipient
  2. Post a confirmation image in the private thread
  3. The bot will close and archive the thread

1.4.3. Distribution Reminders

  • Unclaimed Distribution Reminders: Sent Monday, Wednesday, and Friday at 9:00 AM
  • Unfinished Distribution Reminders: Sent Saturday at 9:00 AM

1.5. Support Ticket System

1.5.1. Opening a Ticket

Users can open support tickets using the ticket button in the designated ticket channel:

  1. Click the "Open Ticket" button
  2. Fill out the modal form with your issue description
  3. A private thread will be created for your ticket
  4. Support team members will be notified

1.5.2. Ticket Workflow

  • For Users: Describe your issue in the private thread and wait for a support team member to claim it
  • For Support Team: Click "Claim Ticket" to add your mention and take responsibility for the issue
  • Conversations in the ticket thread are automatically logged

1.5.3. Closing Tickets

Support team members can close tickets using the "Close Ticket" button:

  • A log file of the entire conversation will be generated
  • The log is sent to the ticket archive channel
  • The thread is closed and archived

1.6. Moderation Commands

Moderation team members with the support role (ID: 1173582640843063366) have access to these commands:

!mute <user_id> <duration> <reason>

Temporarily timeout a user.

Parameters:

  • user_id: The Discord user ID to mute
  • duration: Duration with unit (e.g., 30m, 2h, 1d)
    • Supported units: s (seconds), m (minutes), h (hours), d (days)
  • reason: Explanation for the timeout

Example:

!mute 123456789012345678 1h Spam in general channel

!unmute <user_id> <reason>

Remove a timeout from a user.

Parameters:

  • user_id: The Discord user ID to unmute
  • reason: Explanation for removing the timeout

Example:

!unmute 123456789012345678 Appeal accepted

1.7. Palestine News Updates

The bot automatically fetches and posts news updates from Al Jazeera's Palestine live blog:

  • Updates are checked every 10 minutes
  • New articles are posted to the news channel
  • Prevents duplicate posts using article ID tracking

1.8. Getting Help

If you encounter issues or have questions:

  • Open a support ticket in the Discord server
  • Report bugs in the #bug-reports forum channel on our Discord community
  • Contact via the chat server or email at contact@nhcarrigan.com

2. Technical Documentation

This section is for those interested in running their own instance of the Application.

2.1. Prerequisites

Before running your own instance, ensure you have:

  • Node.js: Version 22 (specified in package.json)
  • pnpm: Version 10 (package manager)
  • Discord Bot Account: With a bot token and appropriate permissions
  • Airtable Account: With API access
  • Discord Webhooks: Multiple webhooks configured for different channels

2.2. Required Discord Permissions

Your Discord bot requires the following Gateway Intents:

  • GuildMessages: Access to guild message events
  • Guilds: Access to guild/server data
  • GuildMessageReactions: Access to message reaction events
  • MessageContent: Privileged intent for full message content access
  • GuildMembers: Access to member data

2.3. Environment Configuration

Create a .env file in the project root with the following variables:

# Discord Bot Configuration
TOKEN=your_discord_bot_token

# Discord Webhooks
DEBUG=https://discord.com/api/webhooks/...    # Debug/error logging
COMM=https://discord.com/api/webhooks/...     # Commission notifications
DIST=https://discord.com/api/webhooks/...     # Distribution notifications
NEWS=https://discord.com/api/webhooks/...     # Palestine news updates
TICKET=https://discord.com/api/webhooks/...   # Ticket logs

# Airtable Configuration
AIRTABLE_KEY=your_airtable_api_key
AIRTABLE_BASE_ID=your_base_id
AIRTABLE_TABLE_ID=your_table_name

# Server Configuration (optional)
NODE_ENV=production    # Set to enable HTTPS server on port 10443

2.4. Hardcoded Configuration

Several IDs are hardcoded in the src/config/ directory and must be updated for your server:

File: src/config/Tickets.ts

  • guildId: Your Discord server ID
  • supportRole: Your support team role ID

File: src/config/Webhooks.ts

  • artChannelId: Channel for art commission posts
  • distributionChannelId: Channel for distribution posts

File: src/config/Trello.ts

  • Trello board, list, and label IDs (if using Trello integration)

2.5. Installation

  1. Clone the repository:
git clone https://git.nhcarrigan.com/NHCarrigan/a4p-bot.git
cd nodejs-typescript-template
  1. Install dependencies:
pnpm install
  1. Configure environment variables (see section 2.3)

  2. Build the TypeScript code:

pnpm build

2.6. Running the Bot

Start the bot in production mode:

pnpm start

This will:

  • Load environment variables from .env
  • Execute the compiled JavaScript from prod/index.js
  • Connect to Discord
  • Initialize event listeners and scheduled tasks
  • Start the HTTP server on port 10080 (HTTP) or 10443 (HTTPS if NODE_ENV=production)

2.7. Development Workflow

For development and testing:

Linting:

pnpm lint

Runs ESLint and Prettier to check code style and formatting.

Testing:

pnpm test

Runs Mocha test suite with TypeScript support (timeout: 10 seconds).

Building:

pnpm build

Compiles TypeScript files from src/ to JavaScript in prod/.

2.8. Architecture Overview

2.8.1. Project Structure

a4p-bot/
├── src/
│   ├── index.ts              # Main entry point, bot initialization
│   ├── config/               # Configuration files (channels, webhooks, Trello)
│   ├── events/               # Discord event handlers
│   ├── modules/              # Core business logic
│   │   ├── buttons/          # Button interaction handlers
│   │   ├── messages/         # Message processing logic
│   │   ├── modals/           # Modal form handlers
│   │   └── reminders/        # Scheduled reminder tasks
│   ├── interface/            # TypeScript interfaces and types
│   ├── server/               # Express HTTP server
│   └── utils/                # Utility functions
├── prod/                     # Compiled JavaScript output
├── logs/                     # Ticket conversation logs (runtime)
└── .env                      # Environment variables (not committed)

2.8.2. Core Components

Discord Bot (src/index.ts:1)

  • Initializes Discord.js client with required intents
  • Registers event listeners for messages, reactions, interactions, and member joins
  • Creates webhook clients for different notification types
  • Starts HTTP server for monitoring

Event Handlers (src/events/)

  • onReady.ts:1: Initializes scheduled jobs, caches messages, sends startup notification
  • onMessageCreate.ts:1: Handles commands (!mute, !unmute) and ticket message logging
  • onInteractionCreate.ts:1: Routes button clicks and modal submissions
  • onReactionAdd.ts:1: Manages art commission and distribution claims
  • onMemberAdd.ts:1: Auto-assigns member role to new joiners

Scheduled Tasks (node-schedule)

  • Runs every 60 minutes: Check Airtable for new form submissions
  • Runs every 10 minutes: Fetch and post Palestine news updates
  • Monday/Wednesday/Friday 9 AM: Send unclaimed art and distribution reminders
  • Saturday 9 AM: Send unfinished art and distribution reminders

Ticket System (src/modules/)

  • buttons/ticketOpen.ts:1: Opens modal form for ticket creation
  • modals/handleTicketModal.ts:1: Creates private thread and initializes log file
  • buttons/ticketClaim.ts:1: Adds support member's mention to thread
  • buttons/ticketClose.ts:1: Generates log file, sends to archive, closes thread
  • logTicketMessage.ts:1: Appends messages to log file in real-time
  • generateLogs.ts:1: Reads log file and creates Discord attachment

Airtable Integration (src/modules/checkAirtableRecords.ts:1)

  • Polls Airtable API for new form submissions
  • Tracks latest record ID to avoid duplicate processing
  • Extracts form fields (name, contact info, request details, reference images)
  • Posts formatted messages to commission channel via webhook

News Feed (src/utils/getNewsFeed.ts:1)

  • Fetches latest articles from Al Jazeera Palestine live blog via GraphQL
  • Tracks last posted article ID to prevent duplicates
  • Sends new updates to news webhook channel

2.8.3. Data Flow

User Action (Discord) → Event Listener → Event Handler → Module Logic
                                                              ↓
                                              External API / Webhook Call
                                                              ↓
                                              Response/Notification
                                                              ↓
                                              Logging (Winston + Debug Webhook)
Scheduled Task → External API (Airtable/Al Jazeera) → Parse Response
                                                              ↓
                                              Send to Discord Webhook
                                                              ↓
                                              Update Cache/State

2.9. Database

While Prisma ORM is installed as a dependency, the Application does not currently use a database. All state is managed in memory using cache objects attached to the extended Discord client:

  • bot.ticketLogs: Maps channel IDs to log file message IDs
  • bot.lastArticle: Tracks the most recent news article ID

Ticket conversation logs are temporarily stored as text files in the logs/ directory and deleted after being sent to the archive channel.

2.10. API Integrations

2.10.1. Airtable REST API

Endpoint: https://api.airtable.com/v0/{BASE_ID}/{TABLE_ID}

Method: GET

Headers:

Authorization: Bearer {AIRTABLE_KEY}

Query Parameters:

  • maxRecords=100: Limit results
  • sort[0][field]=Created: Sort by creation time
  • sort[0][direction]=desc: Newest first

Response Structure (src/interface/AirtableResponse.ts:1):

{
  records: [{
    id: string;
    createdTime: string;
    fields: {
      Name: string;
      "Contact Method": "Email" | "Discord" | "Twitter";
      Handle: string;
      "What would you like us to draw?": string;
      "Anything Else?": string;
      Reference?: { url: string }[];
    }
  }]
}

2.10.2. Al Jazeera GraphQL API

Endpoint: https://www.aljazeera.com/graphql (inferred from code)

Operations:

  • SingleLiveBlogChildrensQuery: Fetch live blog structure
  • LiveBlogUpdateQuery: Fetch latest blog updates

The bot extracts article content and posts to the news webhook channel.

2.11. HTTP Server

The Application includes a minimal Express server (src/server/serve.ts:1):

Endpoints:

  • GET / - Returns HTML landing page with project information

Ports:

  • HTTP: 10080 (default)
  • HTTPS: 10443 (when NODE_ENV=production)

Note: The server file includes a TODO comment suggesting deletion after Trello integration is complete.

2.12. Logging

The Application uses Winston for structured logging (src/utils/logHandler.ts:1):

Log Levels:

  • info: General information (bot startup, scheduled task execution)
  • error: Error conditions (API failures, Discord errors)

Log Format:

[TIMESTAMP] LEVEL: MESSAGE

Log Destinations:

  • Console (stdout)
  • Debug webhook (errors only)

2.13. Error Handling

All errors are caught and:

  1. Logged to console via Winston
  2. Sent to the debug webhook with error details
  3. Presented to users with friendly messages (when applicable)

Example error flow (src/modules/checkAirtableRecords.ts):

try {
  // API call
} catch (error) {
  logHandler.error("Error message", error);
  debugHook.send({ content: "Error details" });
}

2.14. Performance Considerations

  • Message Caching: Fetches messages in batches of 100 to reduce API calls
  • Duplicate Prevention: Tracks latest Airtable record ID and news article ID
  • Rate Limiting:
    • Airtable: 60-minute polling interval
    • News API: 10-minute polling interval
  • Concurrent Limits: Artists/distributors limited to 2 active tasks each

2.15. Security Considerations

  • Environment Variables: Sensitive tokens stored in .env (not committed)
  • Role Verification: Commands require support role for execution (src/events/onMessageCreate.ts:1)
  • Webhook Validation: Checks webhook existence before use (src/utils/isValidWebhook.ts:1)
  • Privileged Intents: Requires approval from Discord for MessageContent intent

2.16. Troubleshooting

Bot doesn't start:

  • Verify TOKEN is valid in .env
  • Check Node.js version is 22
  • Ensure all dependencies are installed: pnpm install

Webhooks not working:

  • Verify webhook URLs are valid and accessible
  • Check webhook permissions in Discord channel settings
  • Use isValidWebhook utility for validation

Airtable integration failing:

  • Verify AIRTABLE_KEY, AIRTABLE_BASE_ID, and AIRTABLE_TABLE_ID
  • Check Airtable API permissions
  • Review Airtable API rate limits

Scheduled tasks not running:

  • Check server timezone matches expected cron schedule
  • Review onReady.ts for cron expression syntax
  • Check debug webhook for error messages

Ticket logs not saving:

  • Verify write permissions for logs/ directory
  • Check disk space availability
  • Review console for Winston logging errors

This section is for expansions to our legal policies specific to the Application.

3.1. Terms of Service

The Application is subject to our global Terms of Service, which can be found at:

https://docs.nhcarrigan.com/#/terms

3.2. Privacy Policy

The Application's privacy practices are governed by our global Privacy Policy, which can be found at:

https://docs.nhcarrigan.com/#/privacy

3.2.1. Data Collection

The Application collects and temporarily stores the following data:

Discord Data:

  • User IDs (for role assignment, moderation, and ticket management)
  • Message content in ticket threads (logged to text files)
  • Reaction events (for tracking commission/distribution claims)
  • Member join events (for auto-role assignment)

Airtable Data:

  • Form submission data (name, contact method, handle, art request details)
  • Reference images (URLs only)
  • Submission timestamps and record IDs

Temporary Storage:

  • Ticket conversation logs (stored as text files, deleted after archival)
  • In-memory cache for article IDs and ticket log mappings

Data Retention:

  • Ticket logs: Deleted immediately after being sent to the archive channel
  • Cached data: Cleared on bot restart
  • Airtable record IDs: Stored in memory to prevent duplicate processing

Third-Party Services: The Application integrates with:

  • Discord (message delivery and bot functionality)
  • Airtable (form submission retrieval)
  • Al Jazeera (public news feed)
  • Trello (configuration only, no active integration)

Users should review the privacy policies of these services for their data handling practices.

3.3. License

This software is licensed under our global software licence:

https://docs.nhcarrigan.com/#/license

Copyright: Held by Naomi Carrigan

License Type: Proprietary (see link above for full terms)

3.4. Code of Conduct

All contributors and users must adhere to our Code of Conduct:

See: CODE_OF_CONDUCT.md in the repository root

3.5. Security Policy

Security vulnerabilities should be reported according to our Security Policy:

See: SECURITY.md in the repository root

For security concerns, please contact us through:

3.6. Disclaimer

The Application is provided for the specific purpose of facilitating the Art for Palestine charity event. While we strive for reliability and accuracy, the Application is provided "as-is" without warranties of any kind.

Moderation Actions: The Application includes moderation features (mute/unmute). Server administrators and support team members are responsible for using these features in accordance with Discord's Terms of Service and Community Guidelines.

External Content: The Application fetches and displays news content from Al Jazeera. We do not control or endorse this content and are not responsible for its accuracy or appropriateness.

Charity Event: This Application is specifically designed for the Art for Palestine charity event. For questions about the event itself, please visit https://art4palestine.org or contact the event organizers.


4. Contributing Documentation

This section is for documentation related to contributing to the Application's codebase.

4.1. Contributing Guidelines

Our complete contributing guidelines can be found at:

https://docs.nhcarrigan.com/#/contributing

4.2. Getting Started with Development

  1. Fork the Repository

    # Visit GitHub and fork the repository to your account
    
  2. Clone Your Fork

    git clone https://github.com/YOUR_USERNAME/nodejs-typescript-template.git
    cd nodejs-typescript-template
    
  3. Install Dependencies

    pnpm install
    
  4. Set Up Environment

    • Create a .env file (see section 2.3)
    • Create a test Discord server and bot
    • Configure test webhooks
  5. Create a Branch

    git checkout -b feature/your-feature-name
    

4.3. Code Style and Standards

The project enforces code style through automated tooling:

ESLint Configuration:

  • Extends @nhcarrigan/eslint-config
  • Maximum warnings allowed: 0 (all warnings treated as errors)
  • Checks both src/ and test/ directories

Prettier Configuration:

  • Extends @nhcarrigan/prettier-config
  • Enforces consistent formatting

TypeScript Configuration:

  • Extends @nhcarrigan/typescript-config
  • Strict type checking enabled
  • Root directory: ./src
  • Output directory: ./prod

Running Linters:

pnpm lint

Auto-Fixing Issues:

# Fix ESLint issues
npx eslint src test --fix

# Fix Prettier issues
npx prettier src test --write

4.4. Writing Tests

The project uses Mocha and Chai for testing:

Test Structure:

  • Test files: test/**/*.spec.ts
  • Test style: TDD (Test-Driven Development)
  • Timeout: 10 seconds per test
  • Type: TypeScript (via ts-mocha)

Running Tests:

pnpm test

Writing a Test:

import { expect } from "chai";
import { suite, test } from "mocha";

suite("Feature Name", () => {
  test("should do something", () => {
    // Arrange
    const input = "test";

    // Act
    const result = myFunction(input);

    // Assert
    expect(result).to.equal("expected");
  });
});

4.5. Documentation Standards

JSDoc Comments: All functions, classes, and complex logic should include JSDoc comments:

/**
 * Brief description of the function.
 *
 * @param {Type} paramName - Parameter description
 * @returns {Type} Return value description
 */
function myFunction(paramName: Type): Type {
  // Implementation
}

Inline Comments: Use inline comments for complex logic:

// Explanation of why this approach is used
const result = complexOperation();

Commit Messages: Follow conventional commit format:

  • feat: Add new feature
  • fix: Resolve bug in ticket system
  • docs: Update README
  • chore: Update dependencies
  • refactor: Restructure event handlers
  • test: Add tests for webhook validation

4.6. Pull Request Process

  1. Ensure All Checks Pass:

    • Run pnpm lint (must pass with 0 warnings)
    • Run pnpm test (all tests must pass)
    • Run pnpm build (must compile without errors)
  2. Create Pull Request:

    • Use a descriptive title
    • Provide detailed description of changes
    • Reference any related issues
    • Include screenshots/videos for UI changes
  3. Code Review:

    • Address reviewer feedback
    • Make requested changes
    • Re-request review after updates
  4. Merge:

    • Maintainers will merge approved PRs
    • Squash and merge is preferred for clean history

4.7. Areas for Contribution

The project welcomes contributions in these areas:

Feature Enhancements:

  • Trello integration completion (see TODO in src/server/serve.ts)
  • Database integration using Prisma (currently installed but unused)
  • Additional moderation commands
  • Enhanced reporting and analytics

Bug Fixes:

  • Report bugs in the #bug-reports forum channel on our Discord community
  • Include reproduction steps and environment details
  • PRs to fix bugs are highly appreciated

Documentation:

  • Improve code comments
  • Expand user guides
  • Add troubleshooting sections
  • Create video tutorials

Testing:

  • Increase test coverage
  • Add integration tests
  • Create test utilities

Performance:

  • Optimise message caching
  • Reduce webhook API calls
  • Improve scheduled task efficiency

4.8. Development Environment Setup

Recommended Tools:

  • Editor: VS Code (or any TypeScript-compatible editor)
  • Extensions:
    • ESLint
    • Prettier
    • TypeScript and JavaScript Language Features
  • Node Version Manager: nvm (for managing Node.js versions)
  • Package Manager: pnpm 10

Discord Developer Portal Setup:

  1. Create a new application at https://discord.com/developers/applications
  2. Create a bot user
  3. Enable required privileged intents: Message Content, Server Members
  4. Generate and save bot token
  5. Invite bot to test server with required permissions

Webhook Setup:

  1. Create test channels in your Discord server
  2. Go to channel settings → Integrations → Webhooks
  3. Create webhooks for: debug, comm, dist, news, ticket
  4. Copy webhook URLs to .env

4.9. Debugging

Console Logging: The project uses Winston for logging. To add debug logs:

import { logHandler } from "./utils/logHandler.js";

logHandler.info("Informational message");
logHandler.error("Error message", error);

Discord Debug Webhook: Error details are automatically sent to the debug webhook. Check this channel for runtime errors.

VS Code Launch Configuration: Create .vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Debug Bot",
      "runtimeArgs": ["-r", "dotenv/config"],
      "program": "${workspaceFolder}/prod/index.js",
      "preLaunchTask": "npm: build",
      "outFiles": ["${workspaceFolder}/prod/**/*.js"]
    }
  ]
}

4.10. Common Development Tasks

Adding a New Command:

  1. Add handler logic to src/events/onMessageCreate.ts
  2. Implement command functionality in src/modules/
  3. Update user documentation (section 1)
  4. Add tests in test/

Adding a New Button:

  1. Create button handler in src/modules/buttons/
  2. Export handler in button module
  3. Register handler in src/events/onInteractionCreate.ts
  4. Update user documentation

Adding a New Event Listener:

  1. Create event handler in src/events/
  2. Register listener in src/index.ts
  3. Add error handling
  4. Update technical documentation

Modifying Configuration:

  1. Update relevant file in src/config/
  2. Document changes in section 2.4
  3. Update environment variable documentation if needed

4.11. Release Process

(For maintainers)

  1. Version Bump:

    • Update version in package.json
    • Follow semantic versioning (MAJOR.MINOR.PATCH)
  2. Changelog:

    • Document all changes since last release
    • Include breaking changes, features, and bug fixes
  3. Testing:

    • Run full test suite
    • Test in staging environment
    • Verify all integrations work
  4. Deployment:

    • Build production bundle: pnpm build
    • Deploy to production server
    • Monitor logs for issues
  5. Tag Release:

    git tag -a v2.0.0 -m "Release version 2.0.0"
    git push origin v2.0.0
    

4.12. Contact for Contributors

If you have questions about contributing:

We review pull requests as soon as possible and appreciate all contributions to the project.