Skip to main content

Overview

The SkyTeam Discord bot provides alliance members with automated notifications, server management tools, and integration with the ROBLOX platform. This guide walks through setting up and configuring the bot.

Prerequisites

  • Administrator access to your Discord server
  • Node.js 18+ installed
  • Basic command line knowledge
  • Access to the SkyTeam source repository

Creating a Discord Application

1

Create Application

Go to the Discord Developer Portal and create a new application:
  1. Click “New Application”
  2. Name it “SkyTeam Bot” (or your preferred name)
  3. Accept the terms and create
2

Configure Bot Settings

Navigate to the “Bot” section:
  1. Click “Add Bot”
  2. Enable “Presence Intent”
  3. Enable “Server Members Intent”
  4. Enable “Message Content Intent”
  5. Save changes
Message Content Intent is required for the bot to process commands with the st! prefix.
3

Get Bot Token

In the “Bot” section:
  1. Click “Reset Token”
  2. Copy the token immediately (you won’t see it again)
  3. Store it securely for the next step
Never share your bot token publicly. Treat it like a password.
4

Get Application IDs

Navigate to “OAuth2” > “General”:
  1. Copy your “Client ID”
  2. Note your “Client Secret” (optional, for advanced features)

Installation

1

Clone Repository

Clone the SkyTeam source code:
git clone https://github.com/skyteam/skyteam-roblox.git
cd skyteam-roblox
2

Install Dependencies

Install required packages using pnpm:
pnpm install
3

Configure Environment

Create a .env file in the root directory:
.env.example
# Database
DATABASE_URL="postgresql://user:password@localhost:5432/skyteam"

# Discord Bot
DISCORD_TOKEN="your-discord-bot-token"
DISCORD_HOME_GUILD_ID="your-server-id"
DISCORD_CLIENT_ID="your-discord-client-id"

# Web
NEXT_PUBLIC_API_URL="http://localhost:4000"

# Admin
ADMIN_JWT_SECRET="your-admin-jwt-secret"

# Dev
NODE_ENV="development"
Replace the placeholder values with your actual credentials.
4

Invite Bot to Server

Generate an invite link with proper permissions:
  1. Go to OAuth2 > URL Generator in the Developer Portal
  2. Select scopes: bot, applications.commands
  3. Select permissions:
    • Send Messages
    • Embed Links
    • Attach Files
    • Read Message History
    • Use Slash Commands
    • Administrator (for setup commands)
  4. Copy the generated URL and open it
  5. Select your server and authorize

Bot Configuration

Core Settings

The bot is configured in apps/client/src/index.ts:
apps/client/src/index.ts
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!",
  },
});

Activity Status

The bot sets a custom status 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.");
});

Available Commands

The bot includes several built-in commands:

Slash Commands

/ping

Tests bot responsiveness and displays latency:
apps/client/src/commands/public/ping.ts
@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`,
        }),
      ),
    ],
  });
}
Usage: /ping Permissions: Available to all users

/setupchannel

Sets up pre-configured channel layouts for alliance information:
apps/client/src/commands/private/setupchannel.ts
@Slash({
  name: "setupchannel",
  description: "Sets up a channel.",
  dmPermission: false,
  defaultMemberPermissions: ["Administrator"],
})
async setupchannel(interaction: CommandInteraction) {
  const channelName = interaction.channel?.name;
  // Configures 'portal' or 'affiliates' channels
}
Usage: /setupchannel (in a channel named portal or affiliates) Permissions: Administrator only

Text Commands

The bot also supports prefix-based commands using st!:
st!help     # Show help information
st!ping     # Alternative ping command

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 });
    }

    // Error logging with context
    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,
        },
      ]);
  }
});
Errors are automatically:
  • Logged to the console
  • Sent to users as ephemeral messages
  • Include context (user, channel, timestamp)

Running the Bot

1

Development Mode

Start the bot in development with hot-reload:
pnpm dev --filter @skyteam/client
2

Production Build

Build and run in production:
pnpm build --filter @skyteam/client
pnpm start --filter @skyteam/client
3

Using Docker

Run with Docker Compose:
docker-compose up discord-bot

Creating Custom Commands

Add new slash commands by creating files in apps/client/src/commands/:
apps/client/src/commands/public/example.ts
import type { CommandInteraction } from "discord.js";
import { Discord, Slash } from "discordx";

@Discord()
export class ExampleCommand {
  @Slash({
    name: "example",
    description: "An example command.",
    dmPermission: false,
  })
  async example(interaction: CommandInteraction) {
    await interaction.reply({
      content: "This is an example command!",
      ephemeral: true,
    });
  }
}
Commands are automatically loaded using the dynamic import system:
apps/client/src/index.ts
await importx(
  `${dirname(import.meta.url)}/{events,commands,guards}/**/*.{ts,js}`,
);

Troubleshooting

  • Verify DISCORD_TOKEN is correct in .env
  • Check that the bot process is running
  • Ensure no other instances are using the same token
  • Review console logs for connection errors
  • Wait up to 1 hour for global commands to propagate
  • Use guild-specific commands for instant updates
  • Verify DISCORD_HOME_GUILD_ID is set correctly
  • Re-invite the bot with the applications.commands scope
  • Check bot role position in server settings
  • Verify required permissions in OAuth2 invite
  • Ensure channel-specific permissions aren’t blocking the bot
  • Review defaultMemberPermissions in command definitions
  • Enable Message Content Intent in Developer Portal
  • Restart the bot after enabling intents
  • Verify bot has permission to read messages

Security Best Practices

Token Security

  • Never commit .env files
  • Use environment variables in production
  • Rotate tokens if compromised
  • Limit bot permissions to minimum required

Command Permissions

  • Use defaultMemberPermissions for sensitive commands
  • Implement custom guards for additional checks
  • Log administrative actions
  • Rate limit user commands

Next Steps

API Integration

Connect your bot to the SkyTeam API

ROBLOX Setup

Integrate with ROBLOX games

Build docs developers (and LLMs) love