Skip to main content

Overview

Annie Mei only depends on a few infrastructure categories:
  • PostgreSQL for persistent storage
  • Redis for caching
  • Secret injection for environment variables
  • Sentry for error tracking
  • A Linux host or container platform to run the bot and, for full self-hosted account linking, the auth service
For complete self-hosted deployments, plan for two processes: the Discord bot and the AniList OAuth auth service. The bot needs PostgreSQL and Redis. The auth service needs PostgreSQL. The current production deployment uses Neon, Upstash, Doppler, Sentry, and Oracle Cloud, but those are examples rather than requirements. You can use any compatible PostgreSQL, Redis, secrets workflow, and compute provider.

Database: PostgreSQL

What Annie Mei needs

  • A PostgreSQL connection string in DATABASE_URL
  • A database user with permission to run migrations on startup
  • TLS enabled if your database is remote
  • Optional connection pooling if your provider offers it

Setup

  1. Provision a PostgreSQL database with version 17 or later.
  2. Create a database and user for Annie Mei.
  3. Get the connection string:
    • Format: postgres://user:password@host:5432/database
    • Add ?sslmode=require if your provider requires TLS
    • Set it as DATABASE_URL
  4. Start the bot. Annie Mei runs embedded Diesel migrations automatically on startup.

Connection Pooling

If your provider offers a pooled connection string, prefer that in production:
DATABASE_URL=postgres://user:password@db.example.com/annie_mei?sslmode=require
The current production deployment uses Neon, so you may still see Neon-specific examples in workflow or operational notes. They are references, not requirements.

Schema

Annie Mei uses Diesel ORM for database migrations. The schema is defined in:
  • src/schema.rs (auto-generated, do not edit)
  • migrations/ (SQL migration files)
The database stores:
  • User AniList account registrations
  • Linked AniList usernames and AniList user IDs for registered Discord accounts

Cache: Redis

What Annie Mei needs

  • A Redis connection string in REDIS_URL
  • Standard Redis or TLS Redis support
  • Enough memory for cached API responses

Setup

  1. Provision a Redis instance close to where the bot runs.
  2. Get the connection string:
    • Standard Redis: redis://host:6379
    • TLS Redis: rediss://default:password@host:port
    • Set it as REDIS_URL
  3. Enable TLS if your provider supports or requires it.

Caching Strategy

Annie Mei caches:
  • AniList API responses (anime/manga data)
  • MyAnimeList theme song data
  • Spotify track lookups
The current implementation uses one fixed cache TTL of 5 hours for cached responses.

Monitoring

Monitor Redis usage through whatever tooling your host provides:
  • Request count
  • Memory usage
  • Cache hit rate

Secrets management

What Annie Mei needs

  • All required environment variables available at process start
  • A way to keep secrets out of git
  • A repeatable way to inject secrets into production and CI

Setup

You can provide secrets in several ways:
  • A local .env file for development
  • A systemd EnvironmentFile
  • Docker or Kubernetes secrets
  • A hosted secrets manager such as Doppler, 1Password, AWS Secrets Manager, or similar
If you use Doppler, a simple workflow looks like this:
curl -Ls https://cli.doppler.com/install.sh | sh
doppler login
doppler setup
doppler run -- ./annie-mei

CI/CD Integration

Doppler can also sync secrets to GitHub Actions if that matches your workflow:
  1. Generate a service token in Doppler
  2. Add as DOPPLER_TOKEN in GitHub repository secrets
  3. Use in workflows:
    - name: Install Doppler CLI
      uses: dopplerhq/cli-action@v3
    
    - name: Run with secrets
      run: doppler run -- ./annie-mei
      env:
        DOPPLER_TOKEN: ${{ secrets.DOPPLER_TOKEN }}
    

Monitoring: Sentry

Setup

  1. Create a Sentry account at sentry.io
  2. Create a project:
    • Platform: Rust
    • Copy the DSN
    • Set as SENTRY_DSN environment variable
  3. Configure trace sampling:
    SENTRY_TRACES_SAMPLE_RATE=0.1  # 10% of traces
    

Privacy Features

Annie Mei implements privacy-focused monitoring:
  • User ID hashing: Discord user IDs are hashed before sending to Sentry using USERID_HASH_SALT
  • Credential redaction: Database and API credentials in URLs are automatically stripped from error logs
  • Hash lookup utility: Use ./annie-mei hash <user_id> to find a user’s hashed ID in Sentry
See src/main.rs:146-173 for implementation details.

Debug Symbols

The CI/CD pipeline automatically uploads debug symbols to Sentry for symbolicated stack traces:
# From .github/workflows/build-release.yml:44-56
- name: Upload debug symbols to Sentry
  run: |
    curl -sL https://sentry.io/get-cli/ | bash
    sentry-cli debug-files upload --include-sources target/release/
  env:
    SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
    SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
    SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
Set these GitHub secrets:
  • SENTRY_AUTH_TOKEN: Create in Sentry settings
  • SENTRY_ORG: Your Sentry organization slug
  • SENTRY_PROJECT: Your project slug

Compute / VM

Deployment target

Annie Mei can run on any Linux host that can execute the release binary and reach Discord, PostgreSQL, Redis, and the external APIs. The current production deployment uses Oracle Cloud ARM64 VMs and GitHub Actions, so the examples in this section reflect that setup.

Server Setup

  1. Create a Linux VM or host with network access to your services.
  2. Install system dependencies:
    sudo apt-get update
    sudo apt-get install -y libpq-dev
    
  3. Create the application directory:
    sudo mkdir -p /opt/annie-mei
    sudo chown $USER:$USER /opt/annie-mei
    
  4. Create a systemd service (/etc/systemd/system/annie-mei.service):
    [Unit]
    Description=Annie Mei Discord Bot
    After=network.target
    
    [Service]
    Type=simple
    User=annie
    WorkingDirectory=/opt/annie-mei
    ExecStart=/opt/annie-mei/annie-mei
    Restart=always
    RestartSec=10
    
     # Load environment variables from your chosen secrets source
     EnvironmentFile=/opt/annie-mei/.env
    
    [Install]
    WantedBy=multi-user.target
    
  5. Enable and start the service:
    sudo systemctl daemon-reload
    sudo systemctl enable annie-mei
    sudo systemctl start annie-mei
    

Health Checks

Annie Mei runs an HTTP server on port 8080 (configurable via SERVER_PORT) for health checks:
curl http://127.0.0.1:8080/healthz
Use this endpoint for:
  • Load balancer health checks
  • Monitoring systems
  • Deployment verification
The built-in health server listens on 127.0.0.1, not 0.0.0.0. If you want remote health checks, put a reverse proxy or SSH tunnel in front of it.

CI/CD: GitHub Actions

Annie Mei uses GitHub Actions for automated building, testing, and deployment.

Workflows

1. Clippy Analysis (.github/workflows/rust-clippy.yml)

Runs on every PR and push to main:
  • Lints code with cargo clippy
  • Uploads results to GitHub Security
  • Annotates PRs with warnings

2. Build and Deploy (.github/workflows/build-release.yml)

Runs on:
  • Version tags (v*.*.*)
  • Manual workflow dispatch
Steps:
  1. Build ARM64 binary in Rust Docker container
  2. Upload debug symbols to Sentry
  3. Create GitHub release with binaries
  4. Deploy to the target host:
    • Copy binary via SCP
    • Validate binary (executable, dependencies, files)
    • Backup current binary
    • Restart systemd service
    • Verify service started successfully
    • Rollback on failure

Required GitHub Secrets

Set these in your GitHub repository settings: Current host deployment example:
  • ORACLE_HOST: VM hostname or IP
  • ORACLE_USER: SSH username
  • ORACLE_SSH_KEY: Private SSH key
Sentry Integration:
  • SENTRY_AUTH_TOKEN: Sentry API token
  • SENTRY_ORG: Organization slug
  • SENTRY_PROJECT: Project slug

Manual Deployment

To deploy a specific branch manually:
gh workflow run build-release.yml -f ref=your-branch-name

Deployment Process

The automated deployment (.github/workflows/build-release.yml:102-139):
  1. Validates the new binary
  2. Checks library dependencies with ldd
  3. Verifies required files (e.g., mei.jpg)
  4. Backs up the current binary
  5. Stops the service
  6. Replaces the binary
  7. Starts the service
  8. Verifies the service started successfully
  9. Rolls back if startup fails

Cost planning

Your costs depend on the providers you choose, the number of Discord servers using the bot, and how much API traffic you generate. Typical cost buckets are:
  • PostgreSQL hosting
  • Redis hosting
  • Compute or container runtime
  • Error monitoring
  • Optional secrets management
If you self-host PostgreSQL or Redis, those costs shift from managed-service pricing to your own infrastructure and maintenance time.

Security Best Practices

Network Security

  1. Restrict database access to the bot host or private network where possible
  2. Use TLS for PostgreSQL and Redis whenever your provider supports it
  3. Lock down inbound ports so only required management and health-check access is exposed

Secrets Management

  1. Never commit secrets to git
  2. Rotate credentials regularly
  3. Use a secrets manager if you need centralized secret management
  4. Limit secret access to only necessary users and services

Monitoring

  1. Enable Sentry alerts for error spikes
  2. Monitor database and Redis resource usage in your provider dashboards
  3. Set up uptime monitoring for the HTTP health check endpoint
  4. Review Sentry issues regularly

Next Steps

  • Review Configuration for environment setup
  • See Environment Variables for complete variable reference
  • Set up monitoring alerts in Sentry
  • Set up your preferred secret injection workflow for deployments