This document provides a comprehensive overview of Echo's system architecture, design patterns, and implementation details.
- Overview
- System Architecture
- Core Components
- Data Flow
- Database Schema
- Design Patterns
- Security Considerations
- Performance & Scalability
Echo is a Discord bot built with discord.py that provides economy, gaming, and moderation features. The architecture follows a modular, cog-based design for maintainability and extensibility.
- Language: Python 3.12+
- Framework: discord.py 2.3.2
- Database: SQLite 3
- Image Processing: Pillow (PIL)
- Async: asyncio
- Modularity - Features organized into independent cogs
- Separation of Concerns - Clear boundaries between layers
- Maintainability - Clean code with documentation
- Extensibility - Easy to add new features
┌─────────────────────────────────────────────────────────────┐
│ Discord API │
└────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ main.py (Entry Point) │
│ - Bot initialization │
│ - Cog loading │
│ - Event handling │
└────────────────────────┬────────────────────────────────────┘
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Cogs │ │ Core │ │ Models │
│ │ │ │ │ │
│ - Economy │ │ - Database │ │ - User │
│ - Games │ │ - Config │ │ - Inventory │
│ - Moderation│ │ │ │ │
│ - Fun │ │ │ │ │
└──────┬──────┘ └──────┬──────┘ └─────────────┘
│ │
│ ▼
│ ┌─────────────┐
│ │ SQLite DB │
│ │ │
│ │ - user_data │
│ │ - cooldowns │
│ │ - items │
│ └─────────────┘
│
▼
┌─────────────┐
│ Utils │
│ │
│ - Utilities │
│ - Constants │
│ - Eco │
└─────────────┘
Responsibilities:
- Initialize Discord bot client
- Load all cogs
- Handle global events (
on_ready,on_message) - Start bot and maintain connection
Key Functions:
async def setup_bot() # Load all cogs
async def on_ready() # Bot startup event
async def on_message() # Message filtering
async def run_bot() # Start the botCogs are modular command groups that encapsulate related functionality.
Modular economy system split into:
inventory.py - Inventory Management
- Commands:
inventory,buy,sell,trade - Admin commands:
give,add_item,remove_item - Handles item transactions and inventory operations
transactions.py - Money Management
- Commands:
pay,deposit,withdraw,balance,baltop,networth - Manages pocket money and bank accounts
- Calculates user net worth
games.py - Earning & Gambling
- Earning:
dig,hunt,scrap,beg,daily - Gambling:
gamble,rob - Fun:
shoot,bomb
__init__.py - Main Economy Cog
- Combines all economy sub-cogs
- Initializes economy system
blackjack.py
- Interactive blackjack game
- Card rendering with PIL
- Image composition for hands
slots.py
- Animated slot machine
- GIF generation
- Weighted probability system
farming.py
- Plant and harvest crops
- Time-based growth system
- Profit calculation
crafting.py
- Recipe-based crafting
- Item combination system
- Ingredient validation
fun.py
- General utility commands
- QR code generation
- Server/user info
help.py
- Dynamic help system
- Pagination
- Tutorial system
moderation.py
- User moderation (kick, ban, mute)
- Channel management (lock, clear)
- Server management
database.py - Database Management
Encapsulates all database operations:
class Database:
def __init__(self, db_dir: str = 'data')
# Balance operations
def get_user_balance(user_id: int) -> int
def get_bank_balance(user_id: int) -> int
def update_user_balance(user_id: int, amount: int)
def update_bank_balance(user_id: int, amount: int)
# Inventory operations
def get_user_inventory(user_id: int) -> List[str]
def add_item_to_inventory(user_id: int, item_id: str)
def remove_item_from_inventory(user_id: int, item_id: str) -> bool
# Cooldown operations
def get_cooldown_remaining(user_id: int, action: str) -> float
def update_cooldown(user_id: int, action: str, timestamp: float)
def clear_cooldowns(exclude_actions: List[str] = None)user.py - Data Models
Data classes representing entities:
@dataclass
class UserBalance:
user_id: int
pocket: int
bank: int
@property
def total(self) -> int:
return self.pocket + self.bank
@dataclass
class UserInventory:
user_id: int
items: List[str]
def count_item(self, item_id: str) -> int
def has_item(self, item_id: str) -> bool
def add_item(self, item_id: str) -> None
def remove_item(self, item_id: str) -> bool
@dataclass
class UserPlantation:
user_id: int
harvest_time: float
amount: intconstants.py - Constants & Configuration
- Color constants
- Cooldown durations
- Economy settings
- Message templates
- File paths
utilities.py - Helper Functions
- Embed creation
- Channel locking
- Admin checks
- Time conversion
- QR code generation
eco_support.py - Economy Support
- Item definitions (cosmetics, craftables, shop)
- Crafting recipes
- Database initialization
- Cooldown functions
- Farming functions
User sends message
│
▼
Discord API receives message
│
▼
Bot on_message event
│
├─> Link filter check
│
▼
Command dispatcher
│
▼
Cog command handler
│
├─> Check permissions
├─> Check cooldowns
├─> Validate input
│
▼
Execute command logic
│
├─> Database operations
├─> Calculations
├─> State updates
│
▼
Create response embed
│
▼
Send to Discord API
│
▼
User sees response
Command needs data
│
▼
Call eco_support function
│
▼
Open SQLite connection
│
▼
Execute SQL query
│
├─> SELECT (read)
├─> INSERT (create)
├─> UPDATE (modify)
└─> DELETE (remove)
│
▼
Process results
│
▼
Close connection
│
▼
Return data to command
Table: user_balances
CREATE TABLE user_balances (
user_id TEXT PRIMARY KEY,
balance INTEGER DEFAULT 0,
inventory TEXT DEFAULT '[]' -- JSON array
)Table: user_bank_balances
CREATE TABLE user_bank_balances (
user_id TEXT PRIMARY KEY,
balance INTEGER DEFAULT 0,
last_interest_update REAL DEFAULT 0
)Table: user_carrot_plantations
CREATE TABLE user_carrot_plantations (
user_id TEXT PRIMARY KEY,
harvest_time REAL,
amount INTEGER
)Table: cooldowns
CREATE TABLE cooldowns (
user_id TEXT,
action TEXT,
last_action_time REAL,
PRIMARY KEY (user_id, action)
)Table: items
CREATE TABLE items (
item_name TEXT PRIMARY KEY,
desc TEXT,
cost INTEGER
)Discord.py's Cog system implements the Command pattern:
class Economy(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.command()
async def balance(self, ctx):
# Command logic
passBenefits:
- Encapsulation of related commands
- Easy to load/unload features
- Clear separation of concerns
The Database class acts as a repository:
class Database:
def get_user_balance(self, user_id: int) -> int:
# Encapsulates database access
passBenefits:
- Centralized data access
- Easy to swap database implementations
- Testable with mocks
Configuration is loaded once and shared:
# In utilities.py
with open('config.json', 'r') as config_file:
config = json.load(config_file)Helper function creates consistent embeds:
def make_embed(title: str, description: str, color: discord.Color) -> discord.Embed:
embed = discord.Embed(title=title, description=description, color=color)
embed.set_footer(text="Footer text")
return embedWeighted random selection for item drops:
chosen_item = random.choices(
list(cosmetics_items.keys()),
weights=[item["chance"] for item in cosmetics_items.values()],
k=1
)[0]-
Admin Authorization
def is_admin(ctx): return ctx.author.id == config.get("ADMIN_ID")
-
Link Filtering
if any(link in message.content for link in BANNED_LINKS): await message.delete()
-
Input Validation
- Amount checks for transactions
- User existence validation
- Item ownership verification
-
Eval() Usage (CRITICAL)
- Location:
utils/utilities.py:217 - Risk: Arbitrary code execution
- Fix: Use
ast.literal_eval()or safe math parser
- Location:
-
Plain Text Token Storage
- Location:
config.json - Risk: Token exposure if committed
- Fix: Use environment variables
- Location:
-
SQL Injection (LOW RISK)
- Using parameterized queries (✅ Protected)
- But should migrate to ORM
- Move secrets to
.envfile - Remove
eval()usage - Add rate limiting
- Implement permission checks
- Add input sanitization
- Use prepared statements everywhere
Database:
- SQLite (file-based)
- Synchronous operations
- No connection pooling
Limitations:
- Single server only (no sharding)
- Blocking I/O for database
- In-memory data structures
-
Database Reads
- Every command hits database
- No caching layer
- Synchronous SQLite
-
Image Generation
- Blackjack card rendering
- Slots GIF generation
- CPU-intensive
-
Message Processing
- Link filtering on every message
- No rate limiting
For Small to Medium Servers (< 10k users):
- Current architecture is fine
- SQLite handles load well
For Large Servers (> 10k users):
-
Add Caching
from functools import lru_cache @lru_cache(maxsize=1000) def get_user_balance(user_id: int) -> int: # Cache frequently accessed data pass
-
Migrate to PostgreSQL
- Better concurrency
- ACID transactions
- Connection pooling
-
Add Redis for Caching
- Cache balances
- Cache cooldowns
- Session management
-
Implement Sharding
- Discord.py sharding support
- Horizontal scaling
-
Add Rate Limiting
@commands.cooldown(1, 60, commands.BucketType.user) async def command(self, ctx): pass
main.py
│
├─> cogs/
│ ├─> economy/
│ │ ├─> inventory.py ──┐
│ │ ├─> transactions.py ┼──> utils.eco_support
│ │ └─> games.py ─┘
│ ├─> farming.py ────────────> utils.eco_support
│ ├─> crafting.py ───────────> utils.eco_support
│ └─> ...
│
├─> core/
│ └─> database.py
│
├─> models/
│ └─> user.py
│
└─> utils/
├─> constants.py
├─> utilities.py ──> config.json
└─> eco_support.py
- Replace direct SQLite calls with
Databaseclass - Add comprehensive logging
- Split
eco_support.pyinto modules - Add type hints throughout
- Implement caching layer
- Add proper error handling
- Create test suite
- Add monitoring/metrics
- Migrate to PostgreSQL
- Add Redis for caching
- Implement microservices architecture
- Add API for external integrations
Last Updated: 28-11-2025