ADR-002: GitHub Actions como plataforma de CI/CD
Fecha: 2026-06-25
Estado: Aprobado
Responsable: Orchestrator
Contexto
Venuo tiene tres capas de riesgo que justifican integración continua desde el Sprint 0:
- Aislamiento multi-tenant — un bug en el middleware de routing puede filtrar datos entre tenants sin que el desarrollador lo note.
- Migraciones de django-tenants — más delicadas que en proyectos estándar. Requieren validación en entorno limpio en cada PR.
- Cierre de caja ciego — regla crítica de negocio. El endpoint nunca debe retornar el saldo esperado al cajero. Debe verificarse automáticamente en cada PR.
Se necesita una plataforma que ejecute tests, linting y builds automáticamente en cada PR, y que pueda desplegar a producción al mergear a main.
Decisión
GitHub Actions como plataforma de CI/CD.
- CI activo desde Sprint 0: corre en cada push y PR contra
main. - CD preparado en Sprint 0 pero desactivado hasta que el VPS de producción esté definido.
- Workflows definidos en
.github/workflows/dentro del mismo repositorio. - Imágenes Docker publicadas en GitHub Container Registry (GHCR) — gratuito e integrado.
Alternativas consideradas
| Alternativa | Ventajas | Desventajas |
|---|---|---|
| GitHub Actions (elegida) | Integrado con GitHub, gratuito hasta 2.000 min/mes, workflows en el repo, ecosistema amplio | Dependencia de disponibilidad de GitHub |
| GitLab CI | Potente, runners self-hosted | El repo está en GitHub — requeriría migración o mirror |
| Sin CI/CD | Cero configuración | Sin red de seguridad — insostenible con reglas críticas como cierre ciego y aislamiento multi-tenant |
Workflows definidos
CI — ci.yml (ejecuta en cada push y PR)
1. Checkout del código
2. Levantar PostgreSQL 16 + Redis 7 como servicios
3. Instalar dependencias Python (pip + requirements.txt)
4. Correr migraciones: migrate_schemas --shared + migrate_schemas
5. Ruff (linter Python)
6. Black (formato Python)
7. Pytest — incluyendo tests de aislamiento multi-tenant y cierre ciego
8. Build del frontend (verifica errores TypeScript)
9. ESLint + Prettier
PR bloqueado para merge si cualquier paso falla.
CD — cd.yml (ejecuta al mergear a main)
1. Build imagen Docker backend (python:3.11-slim)
2. Build imagen Docker frontend (node:20-alpine — multi-stage)
3. Push de imágenes a GHCR (ghcr.io/cn-10/venuo)
4. SSH al VPS
5. docker compose pull + docker compose up -d --remove-orphans
6. Correr migraciones en producción
7. Notificar resultado
El workflow de CD permanece desactivado (if: false) hasta que el VPS esté configurado. Al activarlo solo se cambia esa condición y se agregan los secrets del servidor.
Secrets requeridos en GitHub
| Secret | Descripción |
|---|---|
DJANGO_SECRET_KEY |
Clave de Django para entorno de CI |
POSTGRES_PASSWORD |
Password de PostgreSQL para entorno de CI |
VPS_HOST |
IP o dominio del servidor de producción (CD) |
VPS_USER |
Usuario SSH del VPS (CD) |
VPS_SSH_KEY |
Clave privada SSH para deploy (CD) |
GHCR_TOKEN |
Token para push de imágenes a GitHub Container Registry (CD) |
Los secrets de CI (primeros dos) se configuran en Sprint 0. Los secrets de CD (últimos cuatro) se configuran al momento del deploy de producción.
Consecuencias
Positivas
- Cada PR tiene validación automática antes del merge.
- Las reglas críticas de negocio (cierre ciego, aislamiento multi-tenant) se testean en cada cambio.
- El deploy a producción es reproducible y documentado en el workflow.
- GHCR es gratuito para repos privados — sin costo adicional de registry.
Negativas / trade-offs
- Los primeros 2.000 minutos/mes son gratuitos. Con tests pesados y muchos PRs, puede agotarse en el plan Free — evaluar plan Team si ocurre.
- Requiere configurar secrets en GitHub antes de que el CI funcione.
Impacto en el sistema
- Backend: los tests deben cubrir aislamiento multi-tenant y cierre ciego como prioridad.
- Frontend: el build de TypeScript debe pasar sin errores — ningún PR con errores de tipo puede mergearse.
- DevOps: crear
.github/workflows/ci.ymly.github/workflows/cd.ymlen Sprint 0. - Seguridad: los secrets nunca se hardcodean en los workflows — siempre via
${{ secrets.NOMBRE }}.
Documentos actualizados
docs/adr/ADR_INDEX.mddocs/STACK.mddocs/ARCHITECTURE.mdagents/DEVOPS_AGENT.md
Revisión futura
Revisar si los minutos gratuitos de GitHub Actions se agotan consistentemente. En ese caso evaluar runners self-hosted en el mismo VPS de producción — elimina el límite de minutos sin costo adicional.