# Deployment and operations

## cPanel and small shared hosting

Recommended when PHP 8.2+, PDO MySQL, cURL, sodium, MySQL, HTTPS and cron are all available. For 10–15 low-traffic bots, initial architecture is appropriately lightweight. Each cron invocation handles up to 100 inbound and 100 outbound records; a DB advisory lock serializes worker execution. Cron-based delivery may wait up to 60 seconds plus processing time. Avoid sending bursts without queue rate controls.

The subdomain's **document root must be `PROJECT/public`**; do not put `.env`, backups and PHP source inside `public_html` accessible paths. If the host cannot point a domain to the public folder, switch hosting/structure rather than expose secrets.

Create a subdomain + SSL certificate, fill `.env`, run `keygen`, `install`, schedule worker, then link each bot. CLI paths and PHP version differ between hosts. Confirm `curl` has trusted CA certificates and outbound connectivity to `tapi.bale.ai:443`.

## VPS

Supervisor example:

```ini
[program:bale-studio-worker]
command=/usr/bin/php /srv/bale-studio/bin/serve-worker.php
directory=/srv/bale-studio
autostart=true
autorestart=true
user=bale
redirect_stderr=true
stdout_logfile=/var/log/bale-studio-worker.log
```

Configure Nginx root `/srv/bale-studio/public`, use PHP-FPM and TLS, deny hidden files, use a separate DB user and OS service user. An `APP_URL` exactly matching public HTTPS origin is required.

## Backups

Run `php bin/backup.php` to create encrypted database-only backup in `storage/backups/`. Test with `php bin/check-backup.php /path/backup.sql.enc`. These backups are not copied offsite automatically. Keep APP_KEY separately. A restore requires an authorized operator to decrypt in a safe location and import SQL manually to staging before affecting production.

## Monitoring checklist

- Confirm `getWebhookInfo` matches configured route.
- Confirm Cron is running by checking growth/drain of `inbound_updates` and `outbound_jobs`.
- Track `failed` jobs and API 429 errors. Never assume read receipts without official data.
- Check user count and form report using an actual test user.
- Test turning bot off/on without deleting history.
- Run DB snapshots before version changes and explicitly plan rollback of incompatible migrations.
