Skip to content

Database Configuration

Alita Robot uses PostgreSQL as its primary database with GORM as the ORM layer. This guide covers database setup, migrations, connection pooling, and schema design.

  • PostgreSQL 14 or higher
  • UTF-8 encoding support
  • Minimum 512MB RAM for the database

Configure the database URL in your environment:

Terminal window
# Format
DATABASE_URL=postgres://username:password@host:port/database?sslmode=disable
# Example (local development)
DATABASE_URL=postgres://postgres:password@localhost:5432/alita_robot?sslmode=disable
# Example (Docker Compose)
DATABASE_URL=postgresql://alita:alita@postgres:5432/alita
# Example (production with SSL)
DATABASE_URL=postgres://user:pass@db.example.com:5432/alita?sslmode=require
ModeDescription
disableNo SSL (development only)
requireRequire SSL but don’t verify certificate
verify-caRequire SSL and verify server certificate
verify-fullRequire SSL, verify certificate and hostname

Alita Robot supports automatic database migrations on startup, eliminating the need to manually run migration commands.

Terminal window
# Enable automatic migrations
AUTO_MIGRATE=true
# Optional: Continue running even if migrations fail (not recommended for production)
AUTO_MIGRATE_SILENT_FAIL=false
# Optional: Custom migration directory
MIGRATIONS_PATH=migrations
  1. Migration Files: SQL migrations are stored in the migrations/ directory
  2. Version Tracking: Applied migrations are tracked in the schema_migrations table
  3. Idempotent: Migrations are only applied once; safe to run multiple times
  4. Transactional: Each migration runs in a transaction for atomicity
  5. Auto-Cleaning: Supabase-specific SQL (GRANT statements, RLS policies) is automatically removed

When AUTO_MIGRATE=true, the bot will:

  1. Check for pending migrations in migrations/
  2. Clean any Supabase-specific SQL commands automatically
  3. Apply migrations in alphabetical order (by filename)
  4. Track applied migrations in schema_migrations table
  5. Log migration status and any errors

Example log output:

[Migrations] Starting automatic database migration...
[Migrations] Found 15 migration files
[Migrations] Applying 20240101_initial_schema.sql...
[Migrations] Successfully applied 20240101_initial_schema.sql
[Migrations] Migration complete - Applied: 5, Skipped: 10

If you prefer manual control over migrations, use the Makefile targets:

Terminal window
# Set required environment variables
export PSQL_DB_HOST=localhost
export PSQL_DB_NAME=alita
export PSQL_DB_USER=postgres
export PSQL_DB_PASSWORD=password
export PSQL_DB_PORT=5432 # Optional, defaults to 5432
# Apply all pending migrations
make psql-migrate
Terminal window
make psql-status

Output:

version | executed_at
----------------------------+----------------------------
20240315_add_captcha.sql | 2024-03-15 10:30:00.000000
20240301_add_notes.sql | 2024-03-01 09:15:00.000000
20240101_initial.sql | 2024-01-01 00:00:00.000000

This will drop all tables and recreate the schema:

Terminal window
make psql-reset

You will be prompted to confirm with yes before proceeding.

Optimize database performance with connection pooling:

Terminal window
# Maximum idle connections in the pool
# Default: 10, Recommended: 30-80 depending on deployment size
DB_MAX_IDLE_CONNS=50
# Maximum open connections to the database
# Default: 100, Recommended: 150-400 depending on deployment size
DB_MAX_OPEN_CONNS=200
# Maximum connection lifetime in minutes
# Default: 60, Recommended: 120-480 minutes
DB_CONN_MAX_LIFETIME_MIN=240
# Maximum idle time in minutes
# Default: 10, Recommended: 30-120 minutes
DB_CONN_MAX_IDLE_TIME_MIN=60
Deployment SizeMAX_IDLE_CONNSMAX_OPEN_CONNSUse Case
Small10-30100< 50 groups
Medium30-5020050-500 groups
Large50-80300-400500+ groups

Alita Robot uses a surrogate key pattern for all database tables:

Each table has an auto-incremented id field as the primary key (internal identifier):

CREATE TABLE users (
id SERIAL PRIMARY KEY, -- Internal ID
user_id BIGINT NOT NULL UNIQUE, -- Telegram user ID
username VARCHAR(255),
name VARCHAR(255),
language VARCHAR(10) DEFAULT 'en',
created_at TIMESTAMP,
updated_at TIMESTAMP
);
  1. Decoupling: Internal schema is independent of external systems (Telegram IDs)
  2. Stability: If external IDs change or new platforms are added, internal references remain stable
  3. Performance: Integer primary keys are faster for joins and indexing
  4. GORM Compatibility: Consistent integer primary keys simplify ORM operations

External identifiers like user_id (Telegram user ID) and chat_id (Telegram chat ID) are stored with unique constraints:

user_id BIGINT NOT NULL UNIQUE -- Prevents duplicates
chat_id BIGINT NOT NULL UNIQUE -- Ensures one row per chat

The chat_users join table uses a composite primary key:

CREATE TABLE chat_users (
chat_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
PRIMARY KEY (chat_id, user_id)
);

Alita Robot creates the following tables:

TablePurpose
usersTelegram user data
chatsChat/group information
chat_usersUser-chat membership
warns_settingsWarning configuration per chat
warns_usersUser warning records
greetingsWelcome/goodbye messages
filtersChat filters
notesSaved notes
notes_settingsNotes configuration
rulesChat rules
blacklistsBlacklisted words
locksLock settings
pinsPin settings
adminAdmin settings
antiflood_settingsAnti-flood configuration
connectionConnection settings
connection_settingsChat connection config
disableDisabled commands
disable_chat_settingsPer-chat disable settings
report_chat_settingsReport configuration
report_user_settingsUser report preferences
devsDeveloper settings
channelsLinked channels
captcha_settingsCaptcha configuration
captcha_attemptsActive captcha attempts
captcha_muted_usersUsers muted due to captcha failure
stored_messagesMessages stored during captcha
schema_migrationsMigration tracking
Terminal window
# Using pg_dump
pg_dump -h localhost -U postgres -d alita > backup.sql
# Compressed backup
pg_dump -h localhost -U postgres -d alita | gzip > backup.sql.gz
# Docker
docker-compose exec -T postgres pg_dump -U alita -d alita > backup.sql
Terminal window
# From SQL file
psql -h localhost -U postgres -d alita < backup.sql
# From compressed file
gunzip -c backup.sql.gz | psql -h localhost -U postgres -d alita
# Docker
docker-compose exec -T postgres psql -U alita -d alita < backup.sql
Failed to connect to database: connection refused
  • Verify PostgreSQL is running
  • Check host and port in DATABASE_URL
  • Ensure firewall allows connections on port 5432
password authentication failed for user
  • Verify username and password in connection string
  • Check pg_hba.conf authentication settings
too many connections for role
  • Reduce DB_MAX_OPEN_CONNS
  • Increase PostgreSQL max_connections in postgresql.conf
  • Consider using connection pooling (PgBouncer)
Migration failed: column already exists

This usually means the migration was partially applied. Options:

  1. Set AUTO_MIGRATE_SILENT_FAIL=true and let the bot continue
  2. Manually fix the schema and mark the migration as applied:
    INSERT INTO schema_migrations (version, executed_at)
    VALUES ('problematic_migration.sql', NOW());

Enable query logging in PostgreSQL:

ALTER SYSTEM SET log_min_duration_statement = 1000; -- Log queries > 1 second
SELECT pg_reload_conf();

Or enable debug mode in the bot:

Terminal window
DEBUG=true