Updates & Maintenance

tvaras updates are delivered as Docker images and gated by your license. Updates are automatic via cron, or can be triggered manually.


How Updates Work

The update.sh script on your VM handles the entire update process:

  1. Validates your license key against tvaras.ai
  2. Obtains a short-lived Docker registry token
  3. Pulls the latest image from ghcr.io
  4. Syncs docker-compose.prod.yml from the image (compose-level changes ship with each release; a timestamped backup of your previous file is kept)
  5. Performs a zero-downtime rollover of the app service
  6. Logs out from the registry

If your license is expired or revoked, the script exits without pulling — your existing installation continues running on the last pulled version.

Zero-Downtime Rollover

Since v0.108.0, updates do not take the app down — not even briefly:

  1. A new app container starts alongside the running one.
  2. It must pass a content-verified readiness probe (/health/ready: database reachable, full route table registered, version readable) before anything changes. If it never turns healthy, it is removed and the old container keeps serving — a failed update cannot take your installation down.
  3. Once healthy, traffic flows to both containers for a few seconds (nginx resolves the app per request via Docker DNS), then the old container is retired with a graceful 60-second drain. Open chats reconnect automatically.
  4. Background workers (schedules, task runner, syncs) run on exactly one container at a time via a database leader lock, so nothing double-fires during the overlap.

nginx configuration changes ship inside the image and are applied with an in-place re-render and graceful reload — no dropped connections.

Automatic Updates

The recommended setup is a cron job that checks for updates every 30 minutes:

*/30 * * * * cd /root/data-bot && ./update.sh >> /var/log/dbt-update.log 2>&1

If no new image is available, docker pull is a no-op and nothing is restarted.

Manual Updates

cd /root/data-bot && sudo ./update.sh

Viewing Update Logs

# Recent update log
cat /var/log/dbt-update.log

# Application logs (the app service is named tvaras-backend since v0.108.0)
cd /root/data-bot && docker compose logs tvaras-backend --tail 50

# All container statuses
docker ps

Maintenance Tasks

Restarting services

cd /root/data-bot
docker compose -f docker-compose.prod.yml restart tvaras-backend

(For an update without downtime, prefer ./update.sh — a plain restart briefly stops the app.)

Viewing logs

# Follow logs in real-time
cd /root/data-bot && docker compose logs -f tvaras-backend

# Filter by conversation
docker logs $(docker ps -q -f label=com.docker.compose.service=tvaras-backend) 2>&1 | grep '[conv=abc123'

SSL certificate renewal

Certbot auto-renews via systemd timer. To manually renew:

certbot renew
docker compose -f docker-compose.prod.yml restart nginx

Database backup

docker exec dbt-postgres pg_dump -U dbt dbt_assistant > backup_$(date +%Y%m%d).sql

Disk usage

# Docker volumes
docker system df -v

# Clean unused images (also runs automatically every 6h)
docker image prune -f

Rollback

If an update causes issues, you can roll back to a previous image by specifying its SHA tag:

# List available image tags
docker images ghcr.io/vej-ai/data-bot

# Run a specific version
DBT_IMAGE=ghcr.io/vej-ai/data-bot:abc1234 docker compose -f docker-compose.prod.yml up -d

What Gets Updated

ComponentAuto-updatedNotes
Application codeYesInside Docker image
FrontendYesBuilt into image
Database schemaYesMigrations run on startup
docker-compose.prod.ymlYesSynced from the image on every update (backup kept)
Nginx configYesShips inside the image; applied with a graceful reload
update.shNoLives on host; deliberately never self-updates
.envNoYour configuration; never touched