Your deployment pipeline is now automated from development through production. This includes:
- Local development with hot reload (
docker compose watch) - PR validation with security scanning, type-checking, and smoke tests
- Automated builds to Docker Hub
- Staging environment for testing before production
- Production deployment to Hyperlift with zero-downtime rolling updates
Run the entire stack with hot reload (backend + database):
# First time setup: copy environment template
cp .env.example .env
# Start everything with live reload
bash dev.sh
# or manually:
docker compose up --pull=missing --watch --buildThe docker-compose.yml uses develop.watch to sync code changes without rebuilding:
- Backend code changes (
src/,server.js) sync in ~1s - Package changes trigger a rebuild
- Database persists in a Docker volume (
spectra-data)
Access:
- Backend: http://localhost:3001
- Frontend: http://localhost:5173 (run
npm run dev:frontendseparately) - API health: http://localhost:3001/api/health
Before pushing to main, simulate production locally:
bash test-prod.shThis builds your exact production image and validates the startup sequence.
Runs on every push and PR to main or develop.
- Runs
npm audit(moderate level) - Scans for committed secrets with TruffleHog
- Fails fast if high-risk vulnerabilities found
- Type-checks TypeScript (
tsc --noEmit) - Runs smoke test: starts server and validates
/api/healthendpoint - Caches npm dependencies for faster builds
- Type-checks all React/TypeScript
- Builds production bundle (
vite build) - Uploads
dist/artifact (retained 3 days for debugging)
- Builds production image with layer caching
- On main branch only: pushes to Docker Hub with tags:
latest(always points to main)<branch>-<short-sha>(for rollback traceability)- Semantic versions (if tags follow
v*.*.*)
- On PRs: builds locally only (no push)
- Calls your
HYPERLIFT_DEPLOY_HOOKwebhook - Passes commit SHA for automatic image selection
- Hyperlift watches the image tag and redeploys automatically
Runs after CI/CD passes on develop branch.
- Builds and pushes staging-specific image tags
- Calls
STAGING_DEPLOY_HOOKif configured - Runs smoke tests against staging environment
- Gives you a safe testing ground before merging to main
Your old workflows (ci.yml, cd.yml, docker-image.yml) are replaced by the new unified pipeline. You can delete them to avoid confusion.
Add these repository secrets in Settings → Secrets and variables → Repository secrets:
| Secret | Value |
|---|---|
DOCKERHUB_USERNAME |
Your Docker Hub username |
DOCKERHUB_TOKEN |
Docker Hub access token (not password) |
HYPERLIFT_DEPLOY_HOOK |
Webhook URL from Hyperlift dashboard |
STAGING_DEPLOY_HOOK |
(Optional) Staging webhook URL |
STAGING_URL |
(Optional) Staging base URL for health checks |
- Log in to hub.docker.com
- Click your profile → Account Settings → Security → Personal access tokens
- Click "Generate new token" → give it read/write permissions
- Copy the token and add it to GitHub Secrets as
DOCKERHUB_TOKEN
┌─────────────────────────────────────────────────────────────┐
│ Developer: git push to main or develop │
└────────────────┬────────────────────────────────────────────┘
│
┌───────▼────────┐
│ Security Scan │
│ (TruffleHog) │
└───────┬────────┘
│
┌────────────┴────────────┐
│ │
┌───▼──────────┐ ┌────────▼─────┐
│ Backend Test │ │ Frontend Build│
│ (TypeScript) │ │ (Vite) │
└───┬──────────┘ └────────┬─────┘
│ │
└────────────┬────────────┘
│
┌────────────▼────────────┐
│ Docker Build & Push │
│ (to Docker Hub) │
└────────────┬────────────┘
│
┌────────▼─────────┐
│ Hyperlift Deploy │
│ (main only) │
└──────────────────┘
main branch:
- ✅ All tests pass
- ✅ Docker image builds and pushes to
<user>/spectracleanse-api:latest - ✅ Hyperlift automatically redeploys (watches image tag)
- ✅ Zero-downtime rolling update (Medium plan+)
develop branch:
- ✅ All tests pass
- ✅ Docker image builds and pushes to
<user>/spectracleanse-api:staging-latest - ✅ Staging deployment triggered (if webhook configured)
- ⏸ Waiting for manual promotion to main
PR branches:
- ✅ All tests pass
- ✅ Docker image builds locally (no push)
- ⏸ Blocked from merging if tests fail
- 🔄 Review required before merge
Copy from .env.example and update:
cp .env.example .env
# Edit .env with your local valuesThe dev.sh script loads .env automatically. Missing vars use safe defaults.
Set these in Hyperlift Dashboard → Project Settings → Environment Variables:
Secrets (encrypted at rest):
JWT_SECRET→ Generate:node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"STRIPE_SECRET_KEY→ From Stripe DashboardSTRIPE_WEBHOOK_SECRET→ From Stripe WebhooksSTRIPE_CREATOR_PRICE_ID→ From Stripe ProductsSTRIPE_STUDIO_PRICE_ID→ From Stripe ProductsGEMINI_API_KEY→ From Google AI Studio
Non-secrets:
PORT=3001NODE_ENV=productionFRONTEND_URL=https://spectracleanse.comDB_PATH=/data/spectra.db
Create a persistent volume in Hyperlift (at least 10 GB) mounted at /data. This is where SQLite database lives.
All deployments validate the /api/health endpoint:
curl https://spectracleanse.com/api/health
# Response: {"status":"ok"}If health checks fail for 3 consecutive intervals (30s default), Hyperlift stops the deployment.
# Local development
docker compose logs -f app
# Production (via Hyperlift)
# Dashboard → Service → Logs tabIf production fails:
- Quick rollback: In Hyperlift dashboard, click "Redeploy" with a previous image tag
- Full rollback: Push a revert commit to main, wait for CI/CD to rebuild and redeploy
- Emergency stop: In Hyperlift, click "Stop service" to halt traffic
The pipeline uses GitHub Actions cache to skip redundant builds:
- First build: ~2 minutes (installs all deps)
- Subsequent builds: ~30 seconds (uses cache layers)
To clear cache:
- In Hyperlift, click "Clear cache" before deploying
- Or re-run GitHub Actions workflow with cache disabled
SQLite lives at /data/spectra.db in Hyperlift. For large deployments:
-- Run periodically from inside the container
PRAGMA optimize;
VACUUM;Or upgrade to PostgreSQL for high-concurrency workloads.
# Clear Docker cache and rebuild
docker system prune -a
bash dev.sh
# Or rebuild without cache
docker compose build --no-cache# Check logs
docker compose logs app
# Common issues:
# - Missing .env (copy from .env.example)
# - Port 3001 already in use (change in docker-compose.yml)
# - Database permission error (ensure /data volume exists)# SSH into Hyperlift container and test manually
# Dashboard → Terminal tab
curl http://localhost:3001/api/health
# Check server logs
tail -f /data/spectra.log- Verify secret names match exactly (case-sensitive)
- Regenerate Docker Hub token (old ones expire)
- Ensure webhook URLs are correct
- Test locally:
bash dev.shand verify http://localhost:3001/api/health - Update secrets: Add
DOCKERHUB_USERNAME,DOCKERHUB_TOKEN,HYPERLIFT_DEPLOY_HOOKto GitHub - Merge this PR to enable automated CI/CD
- Push to main to trigger first production deployment
- Monitor: Check Hyperlift logs for any deployment issues
| File | Purpose |
|---|---|
.github/workflows/ci-cd.yml |
Main pipeline (security → test → build → deploy) |
.github/workflows/staging.yml |
Staging validation (develop → staging) |
docker-compose.yml |
Local dev with hot reload |
dev.sh |
Start development environment |
test-prod.sh |
Validate production build locally |
.dockerignore |
Optimized Docker builds (exclude unnecessary files) |
Sources: