---
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](https://discord.gg/kHNyb6Vyf8). 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](https://chat.nhcarrigan.com) 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:

```sh
# 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:
```bash
git clone https://git.nhcarrigan.com/NHCarrigan/a4p-bot.git
cd nodejs-typescript-template
```

2. Install dependencies:
```bash
pnpm install
```

3. Configure environment variables (see section 2.3)

4. Build the TypeScript code:
```bash
pnpm build
```

### 2.6. Running the Bot

Start the bot in production mode:
```bash
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:**
```bash
pnpm lint
```
Runs ESLint and Prettier to check code style and formatting.

**Testing:**
```bash
pnpm test
```
Runs Mocha test suite with TypeScript support (timeout: 10 seconds).

**Building:**
```bash
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):**
```typescript
{
  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):
```typescript
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

---

## 3. Legal Documentation

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:
- Chat Server: https://chat.nhcarrigan.com
- Email: contact@nhcarrigan.com

### 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**
   ```bash
   # Visit GitHub and fork the repository to your account
   ```

2. **Clone Your Fork**
   ```bash
   git clone https://github.com/YOUR_USERNAME/nodejs-typescript-template.git
   cd nodejs-typescript-template
   ```

3. **Install Dependencies**
   ```bash
   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**
   ```bash
   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:**
```bash
pnpm lint
```

**Auto-Fixing Issues:**
```bash
# 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:**
```bash
pnpm test
```

**Writing a Test:**
```typescript
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:

```typescript
/**
 * 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:
```typescript
// 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:

```typescript
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`:
```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:**
   ```bash
   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:

- **Discord Forum:** Post in the #bug-reports or #feature-requests forum channels on our Discord community
- **Chat Server:** https://chat.nhcarrigan.com
- **Email:** contact@nhcarrigan.com

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

---
