Portal is a fully-fledged, feature-rich Discord bot built with Deno 2 and Discord.js v14. It provides automatic voice channel generation, music playback, role management, and various utility commands.
- Runtime: Deno 2.6.7
- Framework: Discord.js v14.17.2
- Database: MongoDB (via Mongoose)
- Language: TypeScript (strict mode)
- Audio: @discordjs/voice, @discordjs/opus, ytdl-core
Portal/
├── src/
│ ├── app.ts # Application entry point
│ ├── commands/ # Slash commands (auth/noAuth)
│ ├── events/ # Discord event handlers
│ ├── handlers/ # Core handlers (discord, mongo, events)
│ ├── Interpreter/ # Channel name interpreter system
│ ├── libraries/ # Shared utility libraries
│ ├── types/ # TypeScript types and interfaces
│ ├── blueprints/ # Command/feature blueprints
│ ├── assets/ # Static assets (images, lists, audio)
│ └── utilities/ # Logging and utilities
├── docs/ # Documentation
├── docker/ # Docker configuration
└── deno.json # Deno configuration
# Start the bot
deno task start
# Development mode with watch
deno task dev
# Lint code
deno task lint
# Format code
deno task fmt- Create and modify slash commands in
src/commands/ - Handle Discord events in
src/events/ - Work with Discord.js v14 API patterns
- Implement permission checks and rate limiting
- Write strict TypeScript code
- Use Deno-specific imports (
npm:,jsr:) - Follow project's type definitions in
src/types/ - Use proper async/await patterns
- MongoDB operations via Mongoose in
src/libraries/mongo.library.ts - Work with Guild, Member, and Channel data models
- Handle data persistence for bot state
- Work with the channel name interpreter in
src/Interpreter/ - Understand Variables, Attributes, Pipes, and Structures
- Implement dynamic channel naming features
- Voice channel management
- Music playback functionality (when enabled)
- Audio streaming with ytdl-core
- Commands:
command_name.ts(snake_case) - Events:
eventName.event.ts(camelCase + .event suffix) - Libraries:
name.library.ts - Types/Classes:
PName.class.ts(P prefix for Portal) - Tests:
name.test.ts
export default {
time: number, // Cooldown in seconds
premium: boolean, // Premium-only command
ephemeral: boolean, // Ephemeral response
auth: boolean, // Requires authentication
scopeLimit: ScopeLimit, // NONE, MEMBER, CHANNEL, GUILD
slashCommand: SlashCommandBuilder,
execute: async (interaction, pGuild?) => Promise<ReturnPromise>
}- Use
npm:prefix for npm packages - Use relative paths for internal imports
- Group imports: external, then internal
Required environment variables:
DISCORD_TOKEN- Discord bot tokenMONGO_URL- MongoDB connection stringCLIENT_ID- Discord application client IDLOG- Enable file logging ("true"/"false")
- Test files use
.test.tsextension - Located alongside source files
- Use
@std/expectfor assertions
- Rate Limiting: Discord limits channel name updates to 2 per 10 minutes
- Privacy: Portal never records conversations or stores user messages
- Slash Commands: All commands use Discord's slash command system
- Permissions: Commands are split into
auth(requires permissions) andnoAuth(public)
- Create file in
src/commands/auth/orsrc/commands/noAuth/ - Export default Command object with slashCommand builder
- Add export to corresponding
index.ts
- Create file in
src/events/with.event.tssuffix - Export async function with event handler
- Register in
src/events/index.ts
- Update model in
src/types/models/ - Update corresponding class in
src/types/classes/ - Update mongo.library.ts operations