Skip to main content

Overview

The SkyTeam ROBLOX Discord bot provides community management features, channel setup automation, and real-time notifications for airlines and passengers.

Bot Setup

The bot is built with discord.js and discordx:
apps/client/src/index.ts
import { Client } from "discordx";
import { IntentsBitField, Partials } from "discord.js";

export const bot = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMembers,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.GuildMessageReactions,
    IntentsBitField.Flags.GuildVoiceStates,
    IntentsBitField.Flags.MessageContent,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.DirectMessageTyping,
  ],
  partials: [
    Partials.Message,
    Partials.Channel,
    Partials.Reaction,
    Partials.User,
  ],
  botGuilds: [process.env.DISCORD_HOME_GUILD_ID],
  silent: false,
  guards: [NotBot],
  simpleCommand: {
    prefix: "st!",
  },
});

Prefix Commands

Use st! prefix for simple text commands

Slash Commands

Modern Discord interactions with / commands

Bot Initialization

The bot sets up on startup:
apps/client/src/index.ts
bot.once("ready", async () => {
  await bot.initApplicationCommands();
  bot.user?.setActivity({
    type: ActivityType.Custom,
    name: "⬇️ DM the bot below for help",
  });

  console.log("Bot initalized.");
});

Custom Status

The bot displays a helpful status message guiding users to DM for assistance.

Commands

Ping Command

Test the bot’s responsiveness:
apps/client/src/commands/public/ping.ts
import { Discord, Slash } from "discordx";
import type { CommandInteraction } from "discord.js";
import { ContainerBuilder, MessageFlags, TextDisplayBuilder } from "discord.js";

@Discord()
export class PingCommand {
  @Slash({
    name: "ping",
    description: "Test ping command.",
    dmPermission: false,
  })
  async ping(interaction: CommandInteraction) {
    await interaction.reply({
      flags: [MessageFlags.IsComponentsV2, MessageFlags.Ephemeral],
      components: [
        new ContainerBuilder().addTextDisplayComponents(
          new TextDisplayBuilder({
            content: `Ping: ${interaction.client.ws.ping}ms`,
          }),
        ),
      ],
    });
  }
}

Ephemeral Responses

The ping command uses ephemeral messages that only the command user can see.

Setup Channel Command

Automatically configure server channels with branded content:
apps/client/src/commands/private/setupchannel.ts
@Discord()
export class SetupChannelCommand {
  @Slash({
    name: "setupchannel",
    description: "Sets up a channel.",
    dmPermission: false,
    defaultMemberPermissions: ["Administrator"],
  })
  async setupchannel(interaction: CommandInteraction) {
    const channelName = interaction.channel?.name;

    interaction.deferReply({
      flags: [MessageFlags.Ephemeral],
    });

    switch (channelName) {
      case "portal":
        await interaction.channel?.send({
          content:
            "https://files.skyteam.dev/api/public/dl/dir8x9Bc/Assets/Portal.png",
        });

        await interaction.channel?.send({
          flags: [MessageFlags.IsComponentsV2],
          components: [
            // Rich content with community rules, links, and branding
          ],
        });
        break;
      case "affiliates":
        await interaction.channel?.send({
          content:
            "https://files.skyteam.dev/api/public/dl/5GAYQdYA/Assets/Affiliates.png",
        });
    }

    interaction.editReply({
      flags: [MessageFlags.IsComponentsV2],
      components: [
        new ContainerBuilder().addTextDisplayComponents(
          new TextDisplayBuilder({
            content: "Channel setup complete.",
          }),
        ),
      ],
    });
  }
}

Administrator Only

The setupchannel command requires Administrator permissions for security.

Portal Channel Setup

The portal channel includes:
  • Community safeguarding rules: 7 comprehensive rules for maintaining a safe environment
  • Discord TOS enforcement: Link to Discord’s Terms of Service
  • Social media links: Discord, Twitter, ROBLOX group, and fact sheet
  • Media galleries: Branded images and banners
  • Welcome message: “Caring more about you” commitment

Example Rules

### 1. Mutual Respect
You must respect all users within our community, regardless of your personal feeling towards others.

### 2. No Spamming
Please do not send repeated or excessive messages in any channel.

### 3. SFW Content
We ask that you do not send any NSFW content as this community is largely minors.

### 4. No advertising
Please refrain from unsolicited advertising or posting links to other groups.

### 5. No Malicious Content
This server strictly prohibits content which is malicious.

### 6. Politics
We ask that you do not discuss any insensitive political topics within our community.

### 7. Voice Chat
We ask that you be respectful and courteous to all users within our voice channels.

Interactive Components

The bot uses Discord’s modern component system:

Text Displays

Rich text content with markdown formatting

Media Galleries

Image carousels and branded visuals

Buttons

Link buttons for external resources

Separators

Visual dividers for content organization

Error Handling

The bot includes comprehensive error handling:
apps/client/src/index.ts
bot.on("interactionCreate", (interaction) => {
  try {
    bot.executeInteraction(interaction);
  } catch (error) {
    const errEmbed = new EmbedBuilder()
      .setDescription(
        `<:warning:1204923305895665705>_ _ An error occured whilst trying to run this command; please try again later.`,
      )
      .setTimestamp();

    if (interaction.isRepliable()) {
      interaction.reply({ embeds: [errEmbed], ephemeral: true });
    }

    const log = new EmbedBuilder()
      .setDescription(
        "<:alert:1255679013158916177>_ _ An error occured :( \n**Error:** ```\n" +
          error +
          "\n```",
      )
      .setFields([
        {
          name: "User",
          value: `<@${interaction.user.id}>`,
          inline: true,
        },
        {
          name: "Channel",
          value: `<#${interaction.channel?.id}>`,
          inline: true,
        },
      ]);
  }
});

User-Friendly Errors

Users see friendly error messages while detailed logs are captured for debugging.

Message Commands

The bot also supports prefix-based commands:
apps/client/src/index.ts
bot.on("messageCreate", async (message: Message) => {
  await bot.executeCommand(message);
});
Use st! prefix for simple text commands.

Environment Setup

Required environment variables:
DISCORD_TOKEN=your_bot_token_here
DISCORD_HOME_GUILD_ID=your_guild_id_here

Security

Never commit your bot token to version control. Use environment variables.

Bot Login

apps/client/src/index.ts
if (!process.env.DISCORD_TOKEN) {
  throw Error("Bot token not found.");
}

bot.login(process.env.DISCORD_TOKEN);

Command Structure

Commands are organized by access level:
  • commands/public/ - Commands all users can access
  • commands/private/ - Admin-only commands

Best Practices

Use Ephemeral

Use ephemeral replies for commands that don’t need to be public

Defer Long Operations

Defer replies for operations that take longer than 3 seconds

Permission Checks

Always verify permissions for sensitive commands

Error Handling

Implement try-catch blocks for all command handlers

Next Steps

ROBLOX Integration

Learn how the bot connects with ROBLOX games

Build docs developers (and LLMs) love