🤖 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 webhookThe 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
- A user types
/disposin Discord - Discord sends an
INTERACTION_CREATEevent to the bot handleInteractions.tsidentifies the command name and routes to the right handler- The handler calls the web API, formats the result, and calls
interaction.reply() - 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):
pnpm discord:commands:registerThis calls Discord's REST API to register all commands in commands.ts for the configured guild (DISCORD_GUILD_ID).
To list currently registered commands:
pnpm discord:commands:listTo remove all registered commands:
pnpm discord:commands:clearCalling 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
| Variable | What it does |
|---|---|
DISCORD_BOT_TOKEN | The bot's secret token (from Discord Developer Portal) |
DISCORD_BOT_APP_ID | The bot's application ID |
DISCORD_GUILD_ID | The ID of the Discord server where the bot operates |
DISCORD_MEMBERS_ROLE_ID | Discord role ID for LIPAIX members |
MYLIPAIX_BASE_URL | URL of the web app (e.g., https://admin.lipaix.com) |
LIPAIX_DISCORD_ACTION | Internal shared secret for webhook authentication |
BILLETWEB_API_KEY | Billetweb API key for the /tickets command |
BILLETWEB_USER | Billetweb user identifier |
PORT | Port for the internal HTTP server (default: 3002) |
Adding a new command
- Create a new file in
src/commands/(e.g.,myCommand.ts) following the pattern of existing commands - Export a command object with
data(slash command definition) andexecute(handler function) - Register it in
src/commands/commands.ts - Run
pnpm discord:commands:registerto deploy it to Discord
