Skip to content

🤖 Discord Bot — Developer Reference

This page is for developers working on the apps/discord-bot package. For the end-user guide (how to use /dispos etc.), see Discord Bot (User Guide).

Overview

The LIPAIX Discord bot is a standalone Node.js service built with Discord.js 14. It runs as a separate process from the web app. It listens for slash commands in a Discord server (guild) and responds with data fetched from the web app's API.

Project structure

apps/discord-bot/src/
├── index.ts                  # Entry point — connects to Discord, starts HTTP server
├── types.ts                  # Shared TypeScript types
├── commands/
│   ├── commands.ts           # Registry of all commands
│   ├── disposCommand.ts      # /dispos command
│   ├── selecsCommand.ts      # /selecs command
│   └── ticketsCommand.ts     # /tickets command
├── actions/
│   ├── handleInteractions.ts # Routes incoming interactions to the right command
│   ├── registerCommands.ts   # Deploys commands to the Discord guild
│   └── listCommands.ts       # Lists currently registered commands
├── billetweb/
│   ├── BilletwebEmbedsAdapter.ts     # Formats Billetweb data into Discord embeds
│   └── BilletwebAvailabilityModel.ts # Fetches availability data from Billetweb
├── selections/
│   ├── SelectionsViewModel.ts        # Formats selection data for Discord
│   ├── SelectionsDiscordAdapter.ts   # Adapts selection data to Discord embeds
│   ├── addLineupMessageReactions.ts  # Adds emoji reactions to lineup messages
│   └── fetchShowPosterAttachment.ts  # Fetches show poster for Discord attachment
├── core/
│   └── injection.ts          # Dependency injection / service factory
└── http/
    ├── internalHttpServer.ts         # Internal HTTP server for webhooks
    ├── registerInternalRoutes.ts     # Internal route registration
    └── routes/
        └── selectionsPublishedRoute.ts  # Handles selection publish webhook

The three commands

/dispos

Fetches the logged-in Discord user's upcoming availabilities from the web app API (/api/v1/availabilities/single-player). Formats them as a Discord embed showing show dates and the user's declared status.

The user is identified by their Discord user ID, which is looked up in the Players collection.

/selecs

Fetches the published selection for upcoming shows (/api/v1/selections/[eventId]). Displays the lineup (role → player name) as a Discord embed.

/tickets

Fetches upcoming events with ticketing configured from the Billetweb API. Displays event details and direct booking links.

How command handling works

  1. A user types /dispos in Discord
  2. Discord sends an INTERACTION_CREATE event to the bot
  3. handleInteractions.ts identifies the command name and routes to the right handler
  4. The handler calls the web API, formats the result, and calls interaction.reply()
  5. Discord delivers the reply (ephemeral — only visible to the user)

Registering commands

Slash commands must be deployed to Discord before users can see them. This is a one-time operation (repeat when commands change):

bash
pnpm discord:commands:register

This calls Discord's REST API to register all commands in commands.ts for the configured guild (DISCORD_GUILD_ID).

To list currently registered commands:

bash
pnpm discord:commands:list

To remove all registered commands:

bash
pnpm discord:commands:clear

Calling the web app API

The bot authenticates API calls with the LIPAIX_API_TOKEN environment variable, passed in the Authorization header. The web app validates this token before responding.

The base URL of the web app is configured via MYLIPAIX_BASE_URL.

Internal HTTP server

The bot also runs a small internal HTTP server (Express). It exposes a webhook endpoint that the web app calls when a selection is published — the bot then posts the lineup message to Discord and adds emoji reactions.

This is how the "Publish to Discord" button in MyLipaix works: the web app calls the bot's internal endpoint, which handles the Discord posting.

Environment variables

VariableWhat it does
DISCORD_BOT_TOKENThe bot's secret token (from Discord Developer Portal)
DISCORD_BOT_APP_IDThe bot's application ID
DISCORD_GUILD_IDThe ID of the Discord server where the bot operates
DISCORD_MEMBERS_ROLE_IDDiscord role ID for LIPAIX members
MYLIPAIX_BASE_URLURL of the web app (e.g., https://admin.lipaix.com)
LIPAIX_DISCORD_ACTIONInternal shared secret for webhook authentication
BILLETWEB_API_KEYBilletweb API key for the /tickets command
BILLETWEB_USERBilletweb user identifier
PORTPort for the internal HTTP server (default: 3002)

Adding a new command

  1. Create a new file in src/commands/ (e.g., myCommand.ts) following the pattern of existing commands
  2. Export a command object with data (slash command definition) and execute (handler function)
  3. Register it in src/commands/commands.ts
  4. Run pnpm discord:commands:register to deploy it to Discord

Released under the MIT License.