Target: Docker Compose โ MySQL 8.0 + Node 20 Alpine
For the full runbook see docs/DEPLOYMENT_RUNBOOK.md in the repo.
Prerequisites
- Docker + Docker Compose installed on server
- MySQL 8.0 accessible (or running in compose)
- Environment variables configured (see below)
Deploy
git pull origin main
docker compose build
docker compose up -d
Required environment variables
| Variable | Purpose |
|---|---|
DATABASE_URL |
MySQL connection string |
JWT_SECRET |
Session/JWT signing key (required in production, min 16 chars) |
RESEND_API_KEY |
Transactional email |
PUBLIC_APP_URL |
Server base URL (e.g. https://www.thesmartpro.io) |
Feature-specific
| Variable | Feature |
|---|---|
CAL_WEBHOOK_SECRET |
Demo booking webhook validation |
SALES_NOTIFICATION_EMAIL |
Demo/trial lead notifications |
Run migrations
docker compose exec app pnpm db:migrate
Or directly:
DATABASE_URL="..." pnpm db:migrate
Verify:
SELECT COUNT(*) FROM __drizzle_migrations;
Health check
curl https://www.thesmartpro.io/api/health
# expect: {"ok":true,"ts":<epoch_ms>,"migrationError":null}
Liveness /health and readiness /health/ready are also exposed; /health/ready returns 503 with a migrationError if a migration failed at boot.
Rollback
git checkout <previous-tag>
docker compose build
docker compose up -d
Migrations are additive โ no need to revert schema changes when rolling back code.
Logs
docker compose logs -f app