Aller au contenu

Maintenance and best practices

Version française
Back to index


Backups

PostgreSQL database

Automatic backup: a Docker backup service (or a server cron job) can be configured to run pg_dump regularly.

Manual backup:

# On the server
pg_dump -h postgres -U postgres -d racines -F c -f /backups/racines_$(date +%Y%m%d).dump

Restore:

pg_restore -h postgres -U postgres -d racines /backups/racines_20260515.dump

Recommendations: - Daily backup minimum - 30-day retention minimum - Store backups off the same server (S3, remote MinIO, etc.) - Monthly restoration test

MinIO audio files

Audio files are stored in the audios bucket with versioning enabled (each re-recording creates a new version, the old one is preserved).

MinIO backup:

# Via mc (MinIO Client)
mc mirror minio/audios /backup/audios/

# Or via the provided npm script
npm run audio:download-originals

Monitoring

Application health check

The health endpoint is always available:

GET /api/health/live

Expected response (HTTP status 200):

{ "status": "ok", "timestamp": "2026-05-31T12:00:00Z" }

This endpoint is used by Docker (healthcheck every 30s) and can be monitored by an external tool (UptimeRobot, Grafana, etc.).

Application logs

Accessing logs via Docker:

# Live logs
docker logs -f racines-app

# Last 100 lines
docker logs --tail=100 racines-app

# Logs from the past hour
docker logs --since=1h racines-app

Patterns to watch for: - 500 errors on /api/audio/upload routes - AUDIO_CDN_URL is empty messages (missing environment variable) - PostgreSQL connection errors (ECONNREFUSED, too many clients) - CSP violations (Refused to connect in client logs)

Disk space

Monitor server disk space, particularly: - /var/lib/docker/volumes/: PostgreSQL and MinIO data - /backups/: pg_dump backups

df -h
du -sh /var/lib/docker/volumes/*

Updating the application

Any push to the develop (or main/production) branch triggers the GitLab pipeline which: 1. Lints + tests 2. Builds the Docker image 3. Pushes to GitLab Registry 4. Deploys via Ansible (SSH + docker pull + docker-compose up -d)

Via manual SSH (emergency)

# On the server
cd /opt/racines
docker-compose pull app
docker-compose up -d app
docker-compose ps  # Check that all services are "Up"

After an update

Check: 1. GET /api/health/live{ "status": "ok" } 2. The homepage loads correctly 3. An audio plays from the CDN 4. The admin page is accessible 5. The speaker interface is accessible


Performance optimisation

PostgreSQL connection pool

The pool is configured at 20 maximum connections (file src/lib/postgres.ts). Under peak load, connections are queued (10s timeout). If you see connection timeout errors, increase the pool or check for slow queries.

Slow queries:

-- Long-running queries
SELECT pid, now() - pg_stat_activity.query_start AS duration, query
FROM pg_stat_activity
WHERE (now() - pg_stat_activity.query_start) > interval '5 seconds';

CDN audio cache

Make sure AUDIO_CDN_URL is set and correct. A well-configured CDN (MinIO accessible publicly or via a third-party CDN) is critical for audio performance.


Troubleshooting common issues

Audio files not loading

Checks: 1. Is the AUDIO_CDN_URL variable set? → docker inspect racines-app | grep AUDIO_CDN_URL 2. Is the CDN URL accessible from outside? → curl -I [AUDIO_CDN_URL]/test.mp3 3. Are MinIO CORS settings configured? → Is the Access-Control-Allow-Origin header present? 4. Is the CSP blocking the CDN domain? → Check AUDIO_CDN_DOMAIN in env vars

Admin page inaccessible

  1. Check that the app container is running: docker-compose ps
  2. Check logs: docker logs racines-app --tail=50
  3. Test the health check: curl http://localhost:3000/api/health/live
  4. Check Traefik (reverse proxy): docker logs traefik --tail=50

Excel import failing in production

  1. Check the file size (> 50MB?)
  2. Check the file's UTF-8 encoding
  3. Check app logs for the detailed error

Service Worker not updated for players

After a deployment, players may keep the old version cached. Solutions: - The application automatically detects the update and displays a "Mise à jour disponible" banner - The player must manually reload the page or click the banner - If the problem persists: the player must clear their browser cache


Security

Best practices

  1. Change admin passwords regularly (via npm run create-admin or direct SQL)
  2. Limit the number of administrators — each admin must have their own credentials
  3. Never commit .env files to Git (already in .gitignore)
  4. Regenerate JWT_SECRET if you suspect a compromise — all active sessions are invalidated

Sensitive environment variables

All sensitive variables are stored in GitLab CI/CD secrets and in the .app_env file on the server (outside Git).

Critical variables never to expose: - JWT_SECRET - PG_PASSWORD - MINIO_SECRET_KEY - MINIO_ACCESS_KEY


Next steps