Architecture
High-level architecture and design principles of Alita Robot.
Alita Robot is a modern Telegram group management bot built with Go and the gotgbot library. This document provides an overview of the architectural decisions, technology stack, and design principles that guide the codebase.
Technology Stack
| Component | Technology | Purpose |
|---|---|---|
| Language | Go 1.26+ | Core application runtime |
| Telegram Library | gotgbot v2 | Telegram Bot API wrapper |
| Build System | GoReleaser | Multi-platform builds and releases |
| Component | Technology | Purpose |
|---|---|---|
| Database | PostgreSQL | Persistent data storage |
| ORM | GORM | Object-relational mapping |
| Migrations | Custom Engine | Schema versioning with transactional execution |
The database uses a surrogate key pattern: auto-increment id as PK with external IDs (user_id, chat_id) as unique constraints.
| Component | Technology | Purpose |
|---|---|---|
| Caching | Redis | Distributed caching layer |
| Client | gocache | Go cache library with marshaling |
| Stampede Protection | singleflight | Prevents thundering herd on cache misses |
All cache keys are prefixed with alita: for namespace isolation. TTLs range from 20 seconds (anonymous admin verification) to 1 hour (language preferences).
| Component | Technology | Purpose |
|---|---|---|
| Metrics | Prometheus | Metrics and observability |
| Tracing | OpenTelemetry | Distributed tracing with OTLP/console exporters |
| Health | HTTP /health | Unified health, metrics, pprof on single port |
Architecture Components
Dispatcher
Routes incoming Telegram updates to appropriate handlers. Configurable max goroutines (default: 200) with enhanced error handling and panic recovery.
Module System
Feature modules in alita/modules/ follow a consistent pattern: moduleStruct, handler methods, LoadModule registration. Help module loads last to collect all commands.
Cache Layer
Redis caching with singleflight stampede protection. Per-type TTLs, automatic invalidation on writes, and distributed cache with namespace isolation.
Permission System
Centralized permission validation in alita/utils/chat_status/. Checks are cached to reduce Telegram API calls. Supports anonymous admin detection.
Monitoring
4-tier auto-remediation, activity tracking (per-chat and per-user DAU/WAU/MAU), background stats every 30s, and GC triggers on memory thresholds.
Graceful Shutdown
Central coordinator with LIFO handler execution. Each handler gets panic recovery. Total timeout: 60 seconds.
Core Design Principles
1. Domain Functions Pattern
All database operations are organized by domain in alita/db/{domain}/repository.go files (e.g., alita/db/bans/repository.go, alita/db/filters/repository.go). Each package provides Get/Add/Update/Delete functions for its domain, with surrogate key pattern (auto-increment id as PK, external IDs as unique constraints):
// Example: Direct domain function calls
settings := db.GetChatSettings(chatId)
db.UpdateChatSettings(chatId, newSettings)
2. Decorator Pattern
Middleware functionality is implemented through decorators in alita/utils/helpers/decorators.go. Common cross-cutting concerns are handled uniformly:
- Permission checking (admin, restrict, delete rights)
- Error handling with panic recovery
- Logging and metrics collection
3. Worker Pools
Concurrent processing uses bounded worker pools with panic recovery:
- Dispatcher: Limited to 200 max goroutines by default (configurable via
DISPATCHER_MAX_ROUTINES) - Message Pipeline: Concurrent validation stages
- Bulk Operations: Parallel batch processors with generic framework
4. Redis Caching
Redis-based caching with stampede protection:
- Distributed cache using Redis for persistence across restarts
- Singleflight pattern prevents thundering herd on cache misses
- Configurable TTLs per data type (30min - 1hr typically)
Request Flow Diagram
+------------------+
| Telegram |
| Bot API |
+--------+---------+
|
+------------------+------------------+
| |
Webhook Mode Polling Mode
| |
v v
+----------+----------+ +-----------+-----------+
| HTTP Server | | Updater |
| /webhook | | GetUpdates loop |
+----------+----------+ +-----------+-----------+
| |
+------------------+------------------+
|
v
+----------+----------+
| Dispatcher |
| (configurable routines)|
+----------+----------+
|
+-------------------+-------------------+
| | |
v v v
+------+------+ +------+------+ +------+------+
| Handler | | Handler | | Handler |
| (Command) | | (Callback) | | (Message) |
+------+------+ +------+------+ +------+------+
| | |
+-------------------+-------------------+
|
+--------------+--------------+
| |
v v
+---------+----------+ +---------+----------+
| Redis Cache | | PostgreSQL |
| (cache lookup) | | (via GORM) |
+--------------------+ +--------------------+
Key Subsystems
Dispatcher
The dispatcher routes incoming Telegram updates to appropriate handlers:
- Configurable max goroutines (default: 200)
- Enhanced error handler with structured logging
- Recovery from panics in any handler
dispatcher := ext.NewDispatcher(&ext.DispatcherOpts{
Error: func(b *gotgbot.Bot, ctx *ext.Context, err error) ext.DispatcherAction {
// Error handling with structured logging
return ext.DispatcherActionNoop
},
MaxRoutines: config.AppConfig.DispatcherMaxRoutines,
})
Module System
Each feature module follows a consistent pattern:
- Define a
moduleStructwith module name - Implement handler functions as methods
- Register handlers in a
LoadModulefunction - Self-register in
init()viaRegisterLegacyModule(name, priority, loadFunc)orRegisterModule(m Module) - Loaded collectively via
modules.LoadAllModules(dispatcher)in priority order
Cache Layer
Redis caching with stampede protection:
- Cache Keys: Prefixed with
alita:for namespace isolation - Stampede Protection: Singleflight prevents concurrent cache rebuilds
- TTL Management: Per-type expiration (settings: 30min, language: 1hr)
Monitoring
Comprehensive monitoring subsystems:
- Resource Monitor: Tracks memory and goroutine usage every 5 minutes
- Activity Monitor: Automatic group activity tracking with configurable thresholds
- Background Stats: Performance metrics collection
- Auto-Remediation: GC triggers when memory exceeds thresholds
Concurrency Model
Bounded Concurrency
// Dispatcher limits concurrent handler execution
MaxRoutines: 200 // Configurable via DISPATCHER_MAX_ROUTINES
// Hot bulk paths have fixed local limits: purges, flood cleanup, admin checks,
// and multi-member greetings. They are intentionally not configuration knobs.
Singleflight for Cache
// Prevents multiple goroutines from rebuilding same cache entry
var cacheGroup singleflight.Group
// 30-second timeout with automatic cleanup
resultCh := cacheGroup.DoChan(cacheKey, func() (any, error) {
return loadFromDatabase()
})
select {
case res := <-resultCh:
result = res.Val
err = res.Err
case <-time.After(30 * time.Second):
cacheGroup.Forget(cacheKey) // Prevent goroutine accumulation
err = errors.New("cache load timeout")
}
Graceful Shutdown
// Shutdown manager coordinates cleanup in order
shutdownManager := shutdown.NewManager()
shutdownManager.RegisterHandler(func() error {
// Cleanup monitoring, database, cache
return nil
})
Error Handling Strategy
Alita uses a 4-layer error handling hierarchy:
Layer 1: Dispatcher Level
Error: func(b *gotgbot.Bot, ctx *ext.Context, err error) ext.DispatcherAction {
defer error_handling.RecoverFromPanic("DispatcherErrorHandler", "Main")
// Log error with structured fields
return ext.DispatcherActionNoop
}
Layer 2: Worker Level
Worker pools implement panic recovery:
go func() {
defer func() {
if r := recover(); r != nil {
log.WithField("panic", r).Error("Panic in worker")
}
}()
// Worker logic
}()
Layer 3: Handler Level
Individual handlers use decorators for error handling:
// Permission checks return early on failure
if !chat_status.RequireUserAdmin(b, ctx, nil, user.Id, false) {
return ext.EndGroups
}
Layer 4: Decorator Level
Command decorators provide permission validation and error context:
// Decorators wrap handlers with cross-cutting concerns
helpers.MultiCommand(dispatcher, []string{"cmd", "alias"}, handler)
Database Schema Design
The database uses a surrogate key pattern:
- Primary Keys: Auto-incremented
idfield (internal identifier) - Business Keys:
user_idandchat_idwith unique constraints - Benefits:
- Decouples internal schema from Telegram IDs
- Stable identifiers if external systems change
- Better performance for joins and indexing
Next Steps
- Project Structure - Directory layout and key files
- Request Flow - Detailed update processing pipeline
- Module Pattern - How to add new modules
- Caching - Redis caching architecture