Guidelines for contributing to Azalea.
- Bun (v1.3+)
- SQLite (bundled with Bun)
- A Discord bot token
bun run setup # bun install + bun run db:generateCopy .env.example to .env and fill in the required values. See README.md for the full table.
bun run db:migrate # Apply migrationsbun run db applies migrations and regenerates the Prisma client in one go.
bun start- Strict mode enabled (
strict: truein tsconfig) - Use
@utils/,@managers/,@/path aliases (defined in tsconfig) - Prefer explicit return types on exported functions and public methods
- Use
ascasts for discord.js type incompatibilities (not@ts-expect-error)
| Kind | Convention | Example |
|---|---|---|
| Files | PascalCase (commands, events, components) | ModerationActivity.ts |
| Utility files | camelCase | eventLogging.ts |
| Classes | PascalCase | MessageCache |
| Types/Interfaces | PascalCase | CommandResponse |
| Enums | PascalCase (name), PascalCase (members) | InfractionSource.Quick |
| Functions | camelCase | humanizeDuration() |
| Private methods | _camelCase |
_buildSearchQuery() |
| Constants | UPPER_SNAKE_CASE | MAX_MUTE_DURATION |
| Config properties | snake_case | ban_delete_message_days |
All time-based configuration values and constants use milliseconds unless documented otherwise. The only exception is the duration column in the MuteRequest database table, which stores seconds.
The project uses ESLint with TypeScript rules. Run the linter:
bun run lint # check
bun run lint:fix # auto-fixAll code must pass linting with zero errors and zero warnings.
- Tabs for indentation
- Double quotes for strings
- Semicolons required
- Trailing commas in multiline structures
bun testTests live in the tests/ directory. All tests must pass before merging.
bun run typecheckMust produce zero errors.
bun run verifyRuns the same checks CI runs (lint + typecheck + tests + Prisma schema validation + migration drift check). Use this before pushing.
src/
index.ts # Entry point
commands/ # Slash and context menu commands
components/ # Button and select menu handlers
events/ # Discord event listeners
managers/
commands/ # Command registration and dispatch
components/ # Component registration and dispatch
config/ # Guild config loading, schema, and validation
events/ # Event listener registration
utils/ # Shared utilities
configs/ # Guild YAML configuration files
prisma/ # Database schema and migrations
tests/ # Test files
Guild configs are YAML files in configs/ named by guild ID (e.g., configs/123456789.yml). They are validated against the Zod schema in src/managers/config/schema.ts. See docs/configuration.md for the full schema.
The log() function has its own internal try/catch with Sentry reporting. Unawaited log() calls are intentional.
Used deliberately for Discord API calls where failure is expected and acceptable (e.g., fetching a user who may not exist).
RawGuildConfig is inferred from the Zod schema via z.infer. Changing property names in schema.ts automatically updates the type everywhere.