EyeBOT is a Discord bot built with TypeScript and discord.js v14, designed to integrate Albion Online player data with Discord servers. It provides character registration, verification, automatic nickname synchronization, and comprehensive health monitoring for production deployments.
- Character Registration: Link Discord accounts to Albion Online characters
- Character Verification: Secure verification system via in-game mail
- Automatic Nickname Sync: Discord nicknames update to match Albion character names
- Multi-Character Support: Users can register multiple Albion characters
- Bulk Updates: Admin command to update all registered members at once
- Health Monitoring: Built-in system monitoring with heartbeat functionality
- Database Migrations: Version-controlled database schema management
- Modular Architecture: Feature-based organization for easy expansion
| Technology | Purpose |
|---|---|
| TypeScript | Type-safe development |
| discord.js v14 | Discord API integration |
| MySQL | Data persistence |
| Node.js | Runtime environment |
| Albion Online API | Character data retrieval |
Before installing EyeBOT, ensure you have:
- Node.js v22 or higher (Download)
- npm (comes with Node.js)
- MySQL / MariaDB (Download)
- Discord Bot Token (Create a bot)
- Git (optional, for cloning)
git clone https://github.com/DBcide/EyeBOT.git
cd EyeBOTnpm installCreate a .env file in the project root:
# Copy the example below and fill in your values# ================================
# Discord Configuration
# ================================
# Your Discord bot token (from https://discord.com/developers/applications)
DISCORD_TOKEN=your_discord_bot_token_here
# Your Discord application client ID
CLIENT_ID=your_client_id_here
# (Optional) Your Discord guild/server ID for testing
GUILD_ID=your_guild_id_here
# ================================
# Database Configuration
# ================================
# MySQL database host
DB_HOST=localhost
# MySQL username
DB_USER=root
# MySQL password (leave empty if no password)
DB_PASSWORD=your_password_here
# Database name (will be created during setup)
DB_NAME=eyebot
# MySQL port (default: 3306)
DB_PORT=3306
# ================================
# Health Monitoring (Optional)
# ================================
# How often to collect system metrics (milliseconds)
HEALTH_MONITOR_INTERVAL_MS=10000
# How often to send heartbeat requests (milliseconds)
HEARTBEAT_INTERVAL_MS=60000
# URL to send heartbeat POST requests (prevents host shutdown)
HEARTBEAT_URL=https://your-monitoring-endpoint.com/heartbeatWhere to find these values:
| Variable | How to Obtain |
|---|---|
DISCORD_TOKEN |
1. Go to Discord Developer Portal 2. Select your application 3. Go to "Bot" tab 4. Click "Reset Token" and copy the new token |
CLIENT_ID |
Found in "General Information" tab of your Discord application |
GUILD_ID |
Right-click your Discord server → "Copy Server ID" (requires Developer Mode enabled) |
DB_* |
Your MySQL installation credentials |
HEARTBEAT_URL |
Your monitoring service endpoint (e.g., UptimeRobot, custom server) |
Create the database in MySQL:
CREATE DATABASE eyebot CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;Or use the MySQL command line:
mysql -u root -p -e "CREATE DATABASE eyebot CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"npm run migrateThis will create all necessary tables:
migrations- Migration trackingtracer_users- Albion character registrations
npm run registerThis registers all slash commands with Discord's API.
npm run buildDevelopment Mode (with auto-reload):
npm run devProduction Mode:
npm startWith PM2 (recommended for production):
pm2 start ecosystem.config.js| Command | Description | Example |
|---|---|---|
/register <pseudo> |
Register your Albion Online character | /register MyCharName |
/update |
Update your character information from Albion API | /update |
/verify <character> |
Verify a character (admin only) | /verify PlayerName |
| Command | Permission Required | Description |
|---|---|---|
/updateall |
Manage Nicknames | Updates all registered members' nicknames from Albion API |
/verify |
Administrator | Verifies a user's Albion character claim |
npm run dev # Run bot with ts-node (development)
npm run watch # Compile TypeScript in watch mode
npm run build # Compile TypeScript to dist/
npm run clean # Clean dist/ directorynpm start # Run compiled bot from dist/npm run migrate # Run all pending migrations
npm run migrate:rollback # Rollback last migration
npm run migrate:list # List executed migrationsnpm test # Run all tests
npm run test:coverage # Run tests with LCOV coverage report (used by SonarCloud)npm run register # Register slash commands with Discord APIEyeBOT has a full test suite built with Jest and ts-jest (TypeScript support).
Tests are organized to mirror the src/ directory layout:
tests/
├── features/
│ └── tracer/
│ ├── commands/
│ │ ├── RegisterCommand.test.ts
│ │ ├── UpdateAllCommand.test.ts
│ │ ├── UpdateCommand.test.ts
│ │ └── VerifyCommand.test.ts
│ ├── services/
│ │ ├── AlbionService.test.ts
│ │ └── TracerService.test.ts
│ └── utils/
│ ├── DiscordUtils.test.ts
│ ├── EmbedBuilders.test.ts # Snapshot tests
│ ├── ErrorHandlers.test.ts
│ └── GuildUtils.test.ts
└── shared/
└── services/
├── DatabaseService.test.ts
└── LoggerService.test.ts
| Module | Covered |
|---|---|
RegisterCommand |
Registration flow, duplicate detection, collector timeout |
UpdateAllCommand |
Bulk update, permission guard, batch processing |
UpdateCommand |
Single update, multi-character selector, API errors |
VerifyCommand |
Verification flow, owner guard, DM notification |
AlbionService |
API search, player details, fame formatting, error codes |
TracerService |
All DB operations, conflict detection, character helpers |
DiscordUtils |
Nickname update, guild tag formatting |
EmbedBuilders |
Snapshot tests for all embed builders |
ErrorHandlers |
Error type detection, localized messages |
GuildUtils |
Acronym extraction, fallback truncation |
DatabaseService |
CRUD, transactions, connection pool |
LoggerService |
All log levels, formatting, debug mode |
[positif]labels mark happy-path cases;[extrême]labels mark edge cases and error scenarios.- All external dependencies (Discord.js, mysql2, Albion API HTTP calls) are mocked at the module level.
- Snapshot tests for Discord embeds live in
tests/features/tracer/utils/__snapshots__/. Update them intentionally with:npx jest --updateSnapshot
EyeBOT includes a comprehensive health monitoring system designed to prevent shutdown by hosting providers that terminate idle processes (e.g., O2Switch).
System Metrics:
- CPU usage (%)
- Memory usage (total, used, percentage)
- Heap memory (Node.js)
- Process uptime
- System load averages
Discord Metrics:
- Number of guilds
- Total users across all guilds
- Channel count
- WebSocket ping (latency)
- Connection status
When HEARTBEAT_URL is configured, the bot sends periodic POST requests with the following JSON payload:
{
"timestamp": "2025-01-05T10:30:00.000Z",
"status": "healthy",
"uptime": 3600,
"memory": {
"percentage": "45.23",
"used": "512.00 MB"
},
"cpu": {
"usage": "12.50"
},
"discord": {
"guilds": 5,
"users": 1250,
"ping": 45,
"status": "READY"
}
}Headers sent:
Content-Type: application/json
User-Agent: EyeBOT-HealthMonitor/1.0
-
Set environment variables:
HEARTBEAT_URL=https://your-endpoint.com/heartbeat HEARTBEAT_INTERVAL_MS=60000 # Send every 60 seconds
-
Use with monitoring services:
- UptimeRobot: Create HTTP monitor pointing to your endpoint
- Pingdom: Set up transaction check
- Custom server: Create endpoint that receives POST requests
-
Example Node.js heartbeat receiver:
app.post('/heartbeat', (req, res) => { console.log('Heartbeat received:', req.body); // Store metrics, trigger alerts, etc. res.status(200).send('OK'); });
Metrics are logged every 10 seconds (configurable):
📊 Health | CPU: 12.34% | RAM: 45.67% | Heap: 89.12 MB/256.00 MB | Uptime: 1h 23m 45s | Guilds: 5 | Users: 1250 | Ping: 45ms
Alerts are triggered when:
- CPU usage > 80%
- Memory usage > 80%
EyeBOT/
├── src/
│ ├── core/ # Core bot framework
│ │ ├── Bot.ts # Main bot orchestrator
│ │ ├── BaseCommand.ts # Abstract command class
│ │ └── BaseEvent.ts # Abstract event class
│ │
│ ├── features/ # Feature modules
│ │ └── tracer/ # Albion character tracking
│ │ ├── commands/ # Slash commands
│ │ ├── models/ # TypeScript interfaces
│ │ ├── services/ # Business logic
│ │ └── utils/ # Utilities
│ │
│ ├── shared/ # Shared services
│ │ └── services/
│ │ ├── DatabaseService.ts # MySQL wrapper
│ │ ├── LoggerService.ts # Logging
│ │ ├── HealthMonitorService.ts # Health monitoring
│ │ └── ServiceContainer.ts # DI container
│ │
│ ├── database/ # Database layer
│ │ ├── migrations/ # Schema migrations
│ │ ├── Migration.ts # Migration interface
│ │ └── MigrationService.ts
│ │
│ ├── scripts/ # Utility scripts
│ │ ├── register-commands.ts
│ │ ├── run-migrations.ts
│ │ ├── rollback-migration.ts
│ │ └── list-migrations.ts
│ │
│ └── index.ts # Entry point
│
├── tests/ # Test suite (mirrors src/ structure)
│ ├── features/
│ │ └── tracer/
│ │ ├── commands/ # Command handler tests
│ │ ├── services/ # Service layer tests
│ │ └── utils/ # Utility tests (incl. snapshots)
│ └── shared/
│ └── services/ # Shared service tests
│
├── dist/ # Compiled JavaScript (generated)
├── .env # Environment variables (not in git)
├── jest.config.js # Jest test configuration
├── package.json
├── tsconfig.json
└── README.md # This file
Stores Albion Online character registrations.
| Column | Type | Description |
|---|---|---|
id |
INT (PK) | Auto-incrementing ID |
discord_id |
VARCHAR(20) | Discord user ID |
albion_id |
VARCHAR(255) | Albion character ID |
albion_name |
VARCHAR(255) | Albion character name |
kill_fame |
BIGINT | Character kill fame |
death_fame |
BIGINT | Character death fame |
guild_name |
VARCHAR(255) | Guild name (nullable) |
alliance_name |
VARCHAR(255) | Alliance name (nullable) |
is_main |
TINYINT(1) | Main character flag |
is_verified |
TINYINT(1) | Verification status |
registered_at |
TIMESTAMP | Registration timestamp |
updated_at |
TIMESTAMP | Last update timestamp |
-
Create
src/features/<feature>/commands/MyCommand.ts:import { BaseCommand } from '../../../core/BaseCommand'; import { ChatInputCommandInteraction, SlashCommandBuilder } from 'discord.js'; export default class MyCommand extends BaseCommand { public name = 'mycommand'; public description = 'My command description'; public buildCommand(): SlashCommandBuilder { return new SlashCommandBuilder() .setName(this.name) .setDescription(this.description); } public async execute(interaction: ChatInputCommandInteraction): Promise<void> { await interaction.reply('Hello!'); } }
-
Build and register:
npm run build npm run register
-
Create
src/database/migrations/YYYYMMDD_HHMMSS_description.ts:import { Migration } from '../Migration'; import mysql from 'mysql2/promise'; export const migration: Migration = { name: '20250105_120000_add_new_table', async up(connection: mysql.PoolConnection): Promise<void> { await connection.query(` CREATE TABLE my_table ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL ); `); }, async down(connection: mysql.PoolConnection): Promise<void> { await connection.query('DROP TABLE my_table'); } };
-
Export in
src/database/migrations/index.ts -
Run:
npm run migrate
-
Install PM2 globally:
npm install -g pm2
-
Create
ecosystem.config.js:module.exports = { apps: [{ name: 'eyebot', script: './dist/index.js', instances: 1, autorestart: true, watch: false, max_memory_restart: '1G', env: { NODE_ENV: 'production' } }] };
-
Start:
pm2 start ecosystem.config.js
-
Useful PM2 commands:
pm2 status # Check status pm2 logs eyebot # View logs pm2 restart eyebot # Restart bot pm2 stop eyebot # Stop bot pm2 delete eyebot # Remove from PM2
This project follows Semantic Versioning (SemVer) — format MAJOR.MINOR.PATCH:
| Segment | When to increment | Example |
|---|---|---|
| MAJOR | Breaking change — old code would break on the new version | 1.0.0 → 2.0.0 |
| MINOR | New backward-compatible feature | 1.0.0 → 1.1.0 |
| PATCH | Bug fix or minor correction | 1.0.0 → 1.0.1 |
Database changes:
- Adding a nullable column or a new table → MINOR
- Removing/renaming a column or changing its type → MAJOR
The rule: if the previous version of the code can still run against the new database without crashing → MINOR. If it would crash → MAJOR.
The project uses a two-workflow CI/CD pipeline:
-
CI (
ci.yml): Automatically triggered on every push and PR tomain. Runsnpm ci+npm run buildto validate the TypeScript compiles correctly. PRs cannot be merged if this check fails. -
Release & Deploy (
release.yml): Manually triggered via GitHub Actions UI. Enter the version number (e.g.1.1.0) and the workflow will:- Create a git tag and GitHub Release
- Pull the latest code on the production server
- Build and restart the bot via PM2
Release workflow:
- Merge all features to
mainvia PRs - Update
versioninpackage.jsonin a final PR - Go to Actions → Release & Deploy → Run workflow and enter the version
- The bot restarts automatically in production
- Check bot is online in Discord
- Verify slash commands are registered:
npm run register - Check bot has proper permissions in your server
- Review logs for errors
- Verify MySQL is running:
mysql --version - Check
.envcredentials are correct - Ensure database exists:
SHOW DATABASES; - Test connection:
npm run migrate:list
- Re-register commands:
npm run register - Wait up to 1 hour for global commands to propagate
- Use
GUILD_IDin.envfor instant testing (guild-specific commands)
- Check
HEARTBEAT_URLis set in.env - Verify endpoint is accessible:
curl -X POST <HEARTBEAT_URL> - Check logs for heartbeat errors
- Ensure firewall allows outbound HTTP requests
The bot implements automatic rate limiting for the Albion Online API:
- Batch processing:
/updateallprocesses 5 users at a time - Delays: 1 second between batches to avoid 429 errors
- Error handling: Graceful degradation on API failures
Public Project
- Author: DBcide (Olivier Français)
- Contact: contact@dbcide.fr
- Commercial use prohibited without authorization
- Modification and redistribution prohibited without authorization
- Attribution required for any authorized use
- See LICENSE.txt for full details
For issues, questions, or feature requests:
- Check existing documentation (README.md)
- Review troubleshooting section above
- Contact: contact@dbcide.fr
- discord.js - Discord API wrapper
- Albion Online - Game data API
- OVH - VPS hosting platform