CI/CD Pipeline
Current State
No automated CI/CD pipeline is configured yet. Deployment is done manually via SSH.
This document defines the target pipeline to implement.
Manual Deployment (Current)
# SSH to production server
ssh [email protected]
# Pull and rebuild
cd /opt/platform-v2
git pull origin main
docker-compose -f docker-compose.prod.yml up -d --build
# Run migrations (always before starting new backend)
docker-compose -f docker-compose.prod.yml exec backend alembic upgrade head
# Verify
docker-compose -f docker-compose.prod.yml logs -f backend
Target Pipeline (GitLab CI)
Pipeline Stages
lint → test → build → deploy
On Merge Request
1. Lint
- Python: flake8 / ruff on backend/
- Frontend: ESLint on frontend/
2. Tests
- Python: pytest backend/ (when tests exist)
- Migration check: alembic upgrade head → alembic downgrade -1 → alembic upgrade head
On Merge to Main
3. Build
- docker build backend image
- docker build frontend image (npm run build inside)
4. Deploy to Production
- SSH to 77.42.82.4
- git pull
- docker-compose -f docker-compose.prod.yml up -d --build
- alembic upgrade head (migrations before restart)
- Health check: curl https://mvp-api.zafarsaidov.uz/health
Environment Variables in CI
| Variable | Purpose |
|---|---|
PROD_SSH_KEY | Private key for SSH to 77.42.82.4 |
PROD_SERVER_HOST | 77.42.82.4 |
PROD_SERVER_USER | root |
Store sensitive values as masked CI variables (never in .gitlab-ci.yml).
Docker Images
backend/Dockerfile # Multi-stage: python:3.11 base → final image
frontend/Dockerfile # Multi-stage: node:20 build → nginx serve
nginx/Dockerfile # nginx with custom config
docker-compose.prod.yml # Production compose (postgres, redis, backend, frontend, nginx)
Frontend VITE_API_URL is set in frontend/.env.production (committed to repo) and baked in at build time — no CI variable needed.
Rules
- Migrations run before deploy — never embedded in application startup
- Build once, deploy the artifact — don't rebuild images on the server
- Rollback = previous image tag — keep
:latestand:shatags - Health check after deploy — verify backend responds before closing pipeline
- Never push secrets — use CI masked variables for credentials