> ## Documentation Index
> Fetch the complete documentation index at: https://anniemei.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Infrastructure

> Set up the infrastructure for deploying Annie Mei to production

## 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 hosted Annie Mei bot currently uses Supabase, Upstash, and Doppler. Those providers are not self-hosting 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 read/write permissions for the bot and auth service schemas
* 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**. The bot connects to PostgreSQL and expects the schema to already be in place.

### Connection Pooling

If your provider offers a pooled connection string, prefer that in production:

```bash theme={}
DATABASE_URL=postgres://user:password@db.example.com/annie_mei?sslmode=require
```

<Note>
  Provider-specific examples are references, not requirements. Any PostgreSQL provider works if the connection string is reachable from both services.
</Note>

### Schema

The auth service owns the current OAuth schema migrations. The schema is defined in:

* `auth/migrations/` (SQLx migration files in the auth service repo)

The bot repo's `migrations/` directory contains bot-owned migrations for settings tables in the `annie_mei` schema. It is not used to prepare the OAuth schema.

The bot reads from the auth-service-owned `oauth_credentials` table. The database stores:

* OAuth credentials linking Discord accounts to AniList accounts
* AniList usernames and AniList user IDs for registered Discord accounts
* OAuth session state for in-progress and completed registration flows

## 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:

```bash theme={}
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:
   ```yaml theme={}
   - 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](https://sentry.io)

2. **Create a project**:
   * Platform: Rust
   * Copy the DSN
   * Set as `SENTRY_DSN` environment variable

3. **Configure trace sampling**:
   ```bash theme={}
   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:

```yaml theme={}
# 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**:
   ```bash theme={}
   sudo apt-get update
   sudo apt-get install -y libpq-dev
   ```

3. **Create the application directory**:
   ```bash theme={}
   sudo mkdir -p /opt/annie-mei
   sudo chown $USER:$USER /opt/annie-mei
   ```

4. **Create a systemd service** (`/etc/systemd/system/annie-mei.service`):
   ```ini theme={}
   [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**:
   ```bash theme={}
   sudo systemctl daemon-reload
   sudo systemctl enable annie-mei
   sudo systemctl start annie-mei
   ```

### Health Checks

The auth service owns HTTP health checks for the stack:

```bash theme={}
curl http://127.0.0.1:8000/healthz
curl http://127.0.0.1:8000/readyz
```

Use `/healthz` for liveness and `/readyz` for dependency-aware readiness in load balancers, monitoring systems, and deployment verification. The Discord bot process does not expose an HTTP health server.

## 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:

```bash theme={}
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](/deployment/configuration) for environment setup
* See [Environment Variables](/deployment/environment-variables) for complete variable reference
* Set up monitoring alerts in Sentry
* Set up your preferred secret injection workflow for deployments
