Files
aurorabot/AGENTS.md

7.2 KiB

AGENTS.md - AI Coding Agent Guidelines

Project Overview

AuroraBot is a Discord bot with a web dashboard built using Bun, Discord.js, React, and PostgreSQL with Drizzle ORM.

Build/Lint/Test Commands

# Development
bun --watch bot/index.ts         # Run bot with hot reload
bun --hot web/src/index.ts       # Run web dashboard with hot reload

# Testing
bun test                         # Run all tests ( expect some tests to fail when running all at once like this due to the nature of the tests )
bun test path/to/file.test.ts    # Run single test file
bun test --watch                 # Watch mode
bun test shared/modules/economy  # Run tests in directory

# Database
bun run generate                 # Generate Drizzle migrations (Docker)
bun run migrate                  # Run migrations (Docker)
bun run db:push                  # Push schema changes (Docker)
bun run db:push:local            # Push schema changes (local)
bun run db:studio                # Open Drizzle Studio

# Web Dashboard
cd web && bun run build          # Build production web assets
cd web && bun run dev            # Development server

Project Structure

bot/                    # Discord bot
├── commands/           # Slash commands by category
├── events/             # Discord event handlers
├── lib/                # Bot core (BotClient, handlers, loaders)
├── modules/            # Feature modules (views, interactions)
└── graphics/           # Canvas image generation

shared/                 # Shared between bot and web
├── db/                 # Database schema and migrations
├── lib/                # Utils, config, errors, types
└── modules/            # Domain services (economy, user, etc.)

web/                    # React dashboard
├── src/pages/          # React pages
├── src/components/     # UI components (ShadCN/Radix)
└── src/hooks/          # React hooks

Import Conventions

Use path aliases defined in tsconfig.json:

// External packages first
import { SlashCommandBuilder } from "discord.js";
import { eq } from "drizzle-orm";

// Path aliases second
import { economyService } from "@shared/modules/economy/economy.service";
import { UserError } from "@shared/lib/errors";
import { users } from "@db/schema";
import { createErrorEmbed } from "@lib/embeds";
import { handleTradeInteraction } from "@modules/trade/trade.interaction";

// Relative imports last
import { localHelper } from "./helper";

Available Aliases:

  • @/* - bot/
  • @shared/* - shared/
  • @db/* - shared/db/
  • @lib/* - bot/lib/
  • @modules/* - bot/modules/
  • @commands/* - bot/commands/

Naming Conventions

Element Convention Example
Files camelCase or kebab-case BotClient.ts, economy.service.ts
Classes PascalCase CommandHandler, UserError
Functions camelCase createCommand, handleShopInteraction
Constants UPPER_SNAKE_CASE EVENTS, BRANDING
Enums PascalCase TimerType, TransactionType
Services camelCase singleton economyService, userService
Types/Interfaces PascalCase Command, Event, GameConfigType
DB tables snake_case users, moderation_cases
Custom IDs snake_case with prefix shop_buy_, trade_accept_

Code Patterns

Command Definition

export const commandName = createCommand({
  data: new SlashCommandBuilder()
    .setName("commandname")
    .setDescription("Description"),
  execute: async (interaction) => {
    await interaction.deferReply();
    // Implementation
  },
});

Service Pattern (Singleton Object)

export const serviceName = {
  methodName: async (params: ParamType): Promise<ReturnType> => {
    return await withTransaction(async (tx) => {
      // Database operations
    });
  },
};

Module File Organization

  • *.view.ts - Creates Discord embeds/components
  • *.interaction.ts - Handles button/select/modal interactions
  • *.types.ts - Module-specific TypeScript types
  • *.service.ts - Business logic (in shared/modules/)
  • *.test.ts - Test files (co-located with source)

Error Handling

Custom Error Classes

import { UserError, SystemError } from "@shared/lib/errors";

// User-facing errors (shown to user)
throw new UserError("You don't have enough coins!");

// System errors (logged, generic message shown)
throw new SystemError("Database connection failed");

Standard Error Pattern

try {
  const result = await service.method();
  await interaction.editReply({ embeds: [createSuccessEmbed(result)] });
} catch (error) {
  if (error instanceof UserError) {
    await interaction.editReply({ embeds: [createErrorEmbed(error.message)] });
  } else {
    console.error("Unexpected error:", error);
    await interaction.editReply({
      embeds: [createErrorEmbed("An unexpected error occurred.")],
    });
  }
}

Database Patterns

Transaction Usage

import { withTransaction } from "@/lib/db";

return await withTransaction(async (tx) => {
  const user = await tx.query.users.findFirst({
    where: eq(users.id, discordId),
  });

  await tx
    .update(users)
    .set({ coins: newBalance })
    .where(eq(users.id, discordId));
  await tx.insert(transactions).values({ userId: discordId, amount, type });

  return user;
}, existingTx); // Pass existing tx if in nested transaction

Schema Notes

  • Use bigint mode for Discord IDs and currency amounts
  • Relations defined separately from table definitions
  • Schema location: shared/db/schema.ts

Testing

Test File Structure

import { describe, it, expect, mock, beforeEach } from "bun:test";

// Mock modules BEFORE imports
mock.module("@shared/db/DrizzleClient", () => ({
  DrizzleClient: { query: mockQuery },
}));

describe("serviceName", () => {
  beforeEach(() => {
    mockFn.mockClear();
  });

  it("should handle expected case", async () => {
    // Arrange
    mockFn.mockResolvedValue(testData);

    // Act
    const result = await service.method(input);

    // Assert
    expect(result).toEqual(expected);
    expect(mockFn).toHaveBeenCalledWith(expectedArgs);
  });
});

Tech Stack

  • Runtime: Bun 1.0+
  • Bot: Discord.js 14.x
  • Web: React 19 + Bun HTTP Server
  • Database: PostgreSQL 16+ with Drizzle ORM
  • UI: Tailwind CSS v4 + ShadCN/Radix
  • Validation: Zod
  • Testing: Bun Test
  • Container: Docker

Key Files Reference

Purpose File
Bot entry bot/index.ts
DB schema shared/db/schema.ts
Error classes shared/lib/errors.ts
Config loader shared/lib/config.ts
Environment shared/lib/env.ts
Embed helpers bot/lib/embeds.ts
Command utils shared/lib/utils.ts