Refresh repository documentation
Some checks failed
Deploy to Production / test (push) Failing after 33s
Some checks failed
Deploy to Production / test (push) Failing after 33s
- Rewrite AGENTS and README files to match the current app layout - Document API routes, trivia UI, and the active panel design language
This commit is contained in:
262
AGENTS.md
262
AGENTS.md
@@ -1,211 +1,135 @@
|
||||
# CLAUDE.md
|
||||
# AGENTS.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
This file documents the current implementation shape of the Aurora repository.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Development
|
||||
bun --watch bot/index.ts # Run bot + API with hot reload
|
||||
docker compose up # Start all services (bot, API, database)
|
||||
docker compose up app # Start just the app (bot + API)
|
||||
docker compose up db # Start just the database
|
||||
# App
|
||||
bun run dev # bot + API in one Bun process with watch mode
|
||||
docker compose up # app + db
|
||||
docker compose up app # app only
|
||||
docker compose up db # database only
|
||||
|
||||
# Testing
|
||||
bun test # Run all tests
|
||||
bun test path/to/file.test.ts # Run a single test file
|
||||
bun test shared/modules/economy # Run tests in a directory
|
||||
bun test --watch # Watch mode
|
||||
bun test # Bun's native runner
|
||||
bun run test # repo test wrapper script
|
||||
bun run test:ci # include CI/integration path
|
||||
|
||||
# Database
|
||||
bun run db:push:local # Push schema changes (local)
|
||||
bun run db:studio # Open Drizzle Studio (localhost:4983)
|
||||
bun run generate # Generate Drizzle migrations (Docker)
|
||||
bun run migrate # Apply migrations (Docker)
|
||||
bun run db:push # drizzle-kit push via Docker
|
||||
bun run db:push:local # drizzle-kit push locally
|
||||
bun run db:generate # drizzle-kit generate via Docker
|
||||
bun run db:migrate # drizzle-kit migrate via Docker
|
||||
bun run db:studio # local Drizzle Studio on :4983
|
||||
|
||||
# Admin Panel
|
||||
bun run panel:dev # Start Vite dev server for dashboard
|
||||
bun run panel:build # Build React dashboard for production
|
||||
# Panel
|
||||
bun run panel:dev # Vite dev server on :5173
|
||||
bun run panel:build # build panel/dist
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
Aurora is a Discord RPG bot + REST API running as a **single Bun process**. The bot and API share the same database client and services.
|
||||
Aurora is a single-process Bun application:
|
||||
|
||||
```
|
||||
bot/ # Discord bot
|
||||
├── commands/ # Slash commands by category (admin, economy, inventory, etc.)
|
||||
├── events/ # Discord event handlers
|
||||
├── lib/ # BotClient, handlers, loaders, embed helpers, commandUtils
|
||||
├── modules/ # Feature modules (views, interactions per domain)
|
||||
└── graphics/ # Canvas-based image generation (@napi-rs/canvas)
|
||||
- `bot/index.ts` boots shared config, registers domain listeners, starts the API server, then logs into Discord.
|
||||
- `api/src/server.ts` hosts REST routes, WebSocket traffic, and built panel assets.
|
||||
- `shared/modules/*` contains the business logic used by both the bot and the API.
|
||||
- `shared/games/*` contains reusable game plugins; `api/src/games/*` runs rooms and WebSocket orchestration.
|
||||
|
||||
shared/ # Shared between bot and API
|
||||
├── db/ # Drizzle ORM client + schema (users, economy, inventory, quests, etc.)
|
||||
├── lib/ # env, config, errors, logger, types, utils
|
||||
└── modules/ # Domain services (economy, user, inventory, quest, moderation, etc.)
|
||||
Current high-level layout:
|
||||
|
||||
api/ # REST API (Bun HTTP server)
|
||||
└── src/routes/ # Route handlers for each domain
|
||||
|
||||
panel/ # React admin dashboard (Vite + Tailwind + Radix UI)
|
||||
```text
|
||||
bot/ Discord commands, events, views, interactions
|
||||
api/ Bun HTTP + WebSocket server
|
||||
panel/ React dashboard
|
||||
shared/db/ Drizzle client and schema
|
||||
shared/lib/ config, env, errors, logger, events, constants
|
||||
shared/modules/ domain services
|
||||
shared/games/ game plugins shared by API and panel
|
||||
```
|
||||
|
||||
**Key architectural details:**
|
||||
- Bot and API both import from `shared/` — do not duplicate logic.
|
||||
- Services in `shared/modules/` are singleton objects, not classes.
|
||||
- The database uses PostgreSQL 16+ via Drizzle ORM with `bigint` mode for Discord IDs and currency.
|
||||
- Feature modules follow a strict file suffix convention (see below).
|
||||
## Import conventions
|
||||
|
||||
## Import Conventions
|
||||
Use path aliases from the repo `tsconfig.json`:
|
||||
|
||||
Use path aliases (defined in `tsconfig.json`). Order: external packages → aliases → relative.
|
||||
- `@/*` -> `bot/*`
|
||||
- `@commands/*` -> `bot/commands/*`
|
||||
- `@db/*` -> `shared/db/*`
|
||||
- `@lib/*` -> `bot/lib/*`
|
||||
- `@modules/*` -> `bot/modules/*`
|
||||
- `@shared/*` -> `shared/*`
|
||||
|
||||
```typescript
|
||||
import { SlashCommandBuilder } from "discord.js"; // external
|
||||
import { economyService } from "@shared/modules/economy/economy.service"; // alias
|
||||
import { users } from "@db/schema"; // alias
|
||||
import { createErrorEmbed } from "@lib/embeds"; // alias
|
||||
import { localHelper } from "./helper"; // relative
|
||||
```
|
||||
Import order in the repo is generally:
|
||||
|
||||
**Aliases:**
|
||||
- `@/*` → `bot/`
|
||||
- `@shared/*` → `shared/`
|
||||
- `@db/*` → `shared/db/`
|
||||
- `@lib/*` → `bot/lib/`
|
||||
- `@modules/*` → `bot/modules/`
|
||||
- `@commands/*` → `bot/commands/`
|
||||
1. external packages
|
||||
2. aliases
|
||||
3. relative imports
|
||||
|
||||
## Code Patterns
|
||||
## File patterns
|
||||
|
||||
### Module File Suffixes
|
||||
- `*.service.ts`: domain/business logic, usually in `shared/modules/*`
|
||||
- `*.view.ts`: Discord message/view construction
|
||||
- `*.interaction.ts`: component interaction handlers
|
||||
- `*.types.ts`: local types and custom ID helpers
|
||||
- `*.handler.ts`: bot-side orchestration around services/views
|
||||
- `*.test.ts`: colocated tests
|
||||
|
||||
- `*.view.ts` — Creates Discord embeds/components
|
||||
- `*.interaction.ts` — Handles button/select/modal interactions
|
||||
- `*.service.ts` — Business logic (lives in `shared/modules/`)
|
||||
- `*.types.ts` — Module-specific TypeScript types
|
||||
- `*.test.ts` — Tests (co-located with source)
|
||||
## Runtime config
|
||||
|
||||
### Interaction Routing
|
||||
- Global game settings live in `game_settings` and are loaded into `shared/lib/config.ts`.
|
||||
- Guild-specific settings live in `guild_settings`; `getGuildConfig()` adds a 60-second cache on top of DB reads.
|
||||
- Most numeric DB values exposed through runtime config are converted to `bigint` in `shared/lib/config.ts`.
|
||||
|
||||
Component interactions (buttons, select menus, modals) flow through a centralized routing system:
|
||||
## Interaction routing
|
||||
|
||||
```
|
||||
Discord event → interactionCreate → ComponentInteractionHandler → interaction.routes.ts → *.interaction.ts
|
||||
```
|
||||
Global component routing is defined in `bot/lib/interaction.routes.ts` and consumed by `ComponentInteractionHandler`.
|
||||
|
||||
`ComponentInteractionHandler` (`bot/lib/handlers/ComponentInteractionHandler.ts`) iterates over the route table in `bot/lib/interaction.routes.ts`. Each route has a `predicate` that matches on `customId`, a lazy `handler` import, and a `method` name to call. The handler also provides centralized `UserError` / system error handling.
|
||||
Current route table:
|
||||
|
||||
**Route table (custom ID prefix → handler):**
|
||||
- `trade_` and `amount` -> `bot/modules/trade/trade.interaction.ts`
|
||||
- `shop_buy_` -> `bot/modules/economy/shop.interaction.ts`
|
||||
- `lootdrop_` -> `bot/modules/economy/lootdrop.interaction.ts`
|
||||
- `trivia_` -> `bot/modules/trivia/trivia.interaction.ts`
|
||||
- `createitem_` -> `bot/modules/admin/item_wizard.ts`
|
||||
- `enrollment` -> `bot/modules/user/enrollment.interaction.ts`
|
||||
- `feedback_` -> `bot/modules/feedback/feedback.interaction.ts`
|
||||
|
||||
| Custom ID prefix | Handler file | Method |
|
||||
| ------------------ | ----------------------------------------------- | ------------------------------ |
|
||||
| `trade_`, `amount` | `bot/modules/trade/trade.interaction.ts` | `handleTradeInteraction` |
|
||||
| `shop_buy_` | `bot/modules/economy/shop.interaction.ts` | `handleShopInteraction` |
|
||||
| `lootdrop_` | `bot/modules/economy/lootdrop.interaction.ts` | `handleLootdropInteraction` |
|
||||
| `trivia_` | `bot/modules/trivia/trivia.interaction.ts` | `handleTriviaInteraction` |
|
||||
| `createitem_` | `bot/modules/admin/item_wizard.ts` | `handleItemWizardInteraction` |
|
||||
| `enrollment` | `bot/modules/user/enrollment.interaction.ts` | `handleEnrollmentInteraction` |
|
||||
| `feedback_` | `bot/modules/feedback/feedback.interaction.ts` | `handleFeedbackInteraction` |
|
||||
Some features still use local collectors instead of the global route table, notably inventory.
|
||||
|
||||
Routes are evaluated in order — the first matching predicate wins. Some modules (e.g., inventory with `inv_` prefix) handle interactions locally via message component collectors instead of the global route table.
|
||||
## Commands and access control
|
||||
|
||||
### Command Definition
|
||||
- Slash command execution is centralized in `bot/lib/handlers/CommandHandler.ts`.
|
||||
- `withCommandErrorHandling()` is the normal command wrapper for defer/reply/error behavior.
|
||||
- Beta commands rely on `featureFlagsService.hasAccess()`.
|
||||
- `ADMIN_USER_IDS` controls admin panel access, not Discord permissions inside command code.
|
||||
|
||||
```typescript
|
||||
export const commandName = createCommand({
|
||||
data: new SlashCommandBuilder().setName("name").setDescription("desc"),
|
||||
execute: async (interaction) => {
|
||||
await withCommandErrorHandling(interaction, async () => {
|
||||
const result = await service.method();
|
||||
await interaction.editReply({ embeds: [createSuccessEmbed(result)] });
|
||||
}, { ephemeral: true });
|
||||
},
|
||||
});
|
||||
```
|
||||
## API and panel
|
||||
|
||||
`withCommandErrorHandling` (from `@lib/commandUtils`) handles `deferReply`, `UserError` display, and unexpected error logging automatically.
|
||||
- API routes are prefix-matched in `api/src/routes/index.ts`.
|
||||
- `/auth/*` and `/api/health` are public.
|
||||
- Players may access `/api/stats`, `/api/health`, `/api/me`, and `/api/me/inventory`.
|
||||
- Remaining `/api/*` routes are admin-only.
|
||||
- The panel dev server proxies back to the Bun server; the integrated server serves `panel/dist` when built.
|
||||
|
||||
### Service Pattern
|
||||
## Database notes
|
||||
|
||||
```typescript
|
||||
export const serviceName = {
|
||||
methodName: async (params: ParamType): Promise<ReturnType> => {
|
||||
return await withTransaction(async (tx) => {
|
||||
// database operations
|
||||
});
|
||||
},
|
||||
};
|
||||
```
|
||||
- Docker Compose uses PostgreSQL 17.
|
||||
- Discord IDs and currency/xp values are stored as `bigint`.
|
||||
- `withTransaction()` lives in `bot/lib/db.ts` and is the normal way shared services compose DB work.
|
||||
|
||||
### Error Handling
|
||||
## Testing
|
||||
|
||||
```typescript
|
||||
import { UserError, SystemError } from "@shared/lib/errors";
|
||||
- Tests use `bun:test`.
|
||||
- Mock modules before importing the unit under test.
|
||||
- Most service tests stub `DrizzleClient` or `withTransaction()` rather than hitting the real database.
|
||||
|
||||
throw new UserError("You don't have enough coins!"); // shown to user
|
||||
throw new SystemError("DB connection failed"); // logged, generic message shown
|
||||
```
|
||||
## Key entrypoints
|
||||
|
||||
### Database Transactions
|
||||
|
||||
```typescript
|
||||
import { withTransaction } from "@/lib/db";
|
||||
|
||||
return await withTransaction(async (tx) => {
|
||||
const user = await tx.query.users.findFirst({ where: eq(users.id, id) });
|
||||
await tx.update(users).set({ coins: newBalance }).where(eq(users.id, id));
|
||||
return user;
|
||||
}, existingTx); // pass existing tx for nested transactions
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
Mock modules **before** imports. Use `bun:test`.
|
||||
|
||||
```typescript
|
||||
import { describe, it, expect, mock, beforeEach } from "bun:test";
|
||||
|
||||
mock.module("@shared/db/DrizzleClient", () => ({
|
||||
DrizzleClient: { query: mockQuery },
|
||||
}));
|
||||
|
||||
describe("serviceName", () => {
|
||||
beforeEach(() => mockFn.mockClear());
|
||||
it("should handle expected case", async () => {
|
||||
mockFn.mockResolvedValue(testData);
|
||||
const result = await service.method(input);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## 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_` |
|
||||
| API routes | kebab-case | `/api/guild-settings` |
|
||||
|
||||
## Key Files
|
||||
|
||||
| Purpose | File |
|
||||
| ----------------- | -------------------------- |
|
||||
| Bot entry point | `bot/index.ts` |
|
||||
| Discord client | `bot/lib/BotClient.ts` |
|
||||
| DB schema index | `shared/db/schema.ts` |
|
||||
| Error classes | `shared/lib/errors.ts` |
|
||||
| Environment vars | `shared/lib/env.ts` |
|
||||
| Config loader | `shared/lib/config.ts` |
|
||||
| Embed helpers | `bot/lib/embeds.ts` |
|
||||
| Command utils | `bot/lib/commandUtils.ts` |
|
||||
| API server | `api/src/server.ts` |
|
||||
- `bot/index.ts`
|
||||
- `bot/lib/BotClient.ts`
|
||||
- `api/src/server.ts`
|
||||
- `api/src/routes/index.ts`
|
||||
- `shared/lib/config.ts`
|
||||
- `shared/db/DrizzleClient.ts`
|
||||
- `shared/db/schema/index.ts`
|
||||
|
||||
Reference in New Issue
Block a user