- Configure workspace Git repository with comprehensive .gitignore - Add Odoo as submodule for ERP reference code - Include documentation: SETUP.md, GIT-STRUCTURE.md - Add gitignore templates for projects (backend, frontend, database) - Structure supports independent repos per project/subproject level Workspace includes: - core/ - Reusable patterns, modules, orchestration system - projects/ - Active projects (erp-suite, gamilit, trading-platform, etc.) - knowledge-base/ - Reference code and patterns (includes Odoo submodule) - devtools/ - Development tools and templates - customers/ - Client implementations template 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
516 lines
14 KiB
Bash
Executable File
516 lines
14 KiB
Bash
Executable File
#!/bin/bash
|
|
##############################################################################
|
|
# GAMILIT Platform - Deployment Script
|
|
#
|
|
# Propósito: Script completo de deployment para desarrollo y producción
|
|
#
|
|
# Uso:
|
|
# ./deploy.sh --env dev # Desarrollo local
|
|
# ./deploy.sh --env prod # Producción
|
|
# ./deploy.sh --env dev --skip-db # Sin inicializar BD
|
|
# ./deploy.sh --env prod --dry-run # Simular deployment
|
|
#
|
|
# Funcionalidades:
|
|
# 1. Validación de prerequisitos (Node, npm, PM2, PostgreSQL)
|
|
# 2. Inicialización de base de datos (opcional)
|
|
# 3. Build de backend y frontend
|
|
# 4. Deployment con PM2
|
|
# 5. Validación de health checks
|
|
# 6. Rollback automático en caso de error
|
|
#
|
|
##############################################################################
|
|
|
|
set -e
|
|
|
|
# Colores
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
MAGENTA='\033[0;35m'
|
|
NC='\033[0m'
|
|
|
|
# Configuración de rutas
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
DEVOPS_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
APPS_ROOT="$(cd "$DEVOPS_ROOT/.." && pwd)"
|
|
GAMILIT_ROOT="$(cd "$APPS_ROOT/.." && pwd)"
|
|
BACKEND_DIR="$APPS_ROOT/backend"
|
|
FRONTEND_DIR="$APPS_ROOT/frontend"
|
|
DATABASE_DIR="$APPS_ROOT/database"
|
|
|
|
# Variables de configuración
|
|
ENVIRONMENT=""
|
|
SKIP_DB=false
|
|
DRY_RUN=false
|
|
SKIP_TESTS=false
|
|
|
|
# ============================================================================
|
|
# FUNCIONES AUXILIARES
|
|
# ============================================================================
|
|
|
|
print_header() {
|
|
echo ""
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}$1${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo ""
|
|
}
|
|
|
|
print_step() {
|
|
echo -e "${CYAN}▶ $1${NC}"
|
|
}
|
|
|
|
print_success() {
|
|
echo -e "${GREEN}✓ $1${NC}"
|
|
}
|
|
|
|
print_error() {
|
|
echo -e "${RED}✗ $1${NC}"
|
|
}
|
|
|
|
print_warning() {
|
|
echo -e "${YELLOW}⚠ $1${NC}"
|
|
}
|
|
|
|
print_info() {
|
|
echo " $1"
|
|
}
|
|
|
|
show_help() {
|
|
cat << EOF
|
|
GAMILIT Platform - Deployment Script
|
|
|
|
Uso: $0 [OPCIONES]
|
|
|
|
Opciones:
|
|
--env dev|prod Ambiente (dev o prod) [REQUERIDO]
|
|
--skip-db No inicializar base de datos
|
|
--skip-tests Omitir tests
|
|
--dry-run Simular deployment sin ejecutar
|
|
--help Mostrar ayuda
|
|
|
|
Ejemplos:
|
|
$0 --env dev
|
|
$0 --env prod --skip-db
|
|
$0 --env dev --dry-run
|
|
|
|
Prerequisitos:
|
|
- Node.js >= 18.0.0
|
|
- npm >= 9.0.0
|
|
- PM2 (global)
|
|
- PostgreSQL >= 14
|
|
|
|
EOF
|
|
}
|
|
|
|
# ============================================================================
|
|
# VALIDACIÓN DE PREREQUISITOS
|
|
# ============================================================================
|
|
|
|
check_prerequisites() {
|
|
print_step "Validando prerequisitos..."
|
|
|
|
# Node.js
|
|
if ! command -v node &> /dev/null; then
|
|
print_error "Node.js no encontrado"
|
|
exit 1
|
|
fi
|
|
local node_version=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
|
|
if [ "$node_version" -lt 18 ]; then
|
|
print_error "Node.js >= 18.0.0 requerido (actual: $(node -v))"
|
|
exit 1
|
|
fi
|
|
print_success "Node.js $(node -v)"
|
|
|
|
# npm
|
|
if ! command -v npm &> /dev/null; then
|
|
print_error "npm no encontrado"
|
|
exit 1
|
|
fi
|
|
print_success "npm $(npm -v)"
|
|
|
|
# PM2
|
|
if ! command -v pm2 &> /dev/null; then
|
|
print_warning "PM2 no encontrado"
|
|
read -p "¿Instalar PM2 globalmente? (y/n): " install_pm2
|
|
if [ "$install_pm2" = "y" ]; then
|
|
npm install -g pm2
|
|
print_success "PM2 instalado"
|
|
else
|
|
print_error "PM2 es requerido para deployment"
|
|
exit 1
|
|
fi
|
|
else
|
|
print_success "PM2 $(pm2 -v)"
|
|
fi
|
|
|
|
# PostgreSQL (solo si no se salta DB)
|
|
if [ "$SKIP_DB" = false ]; then
|
|
if ! command -v psql &> /dev/null; then
|
|
print_error "PostgreSQL no encontrado"
|
|
exit 1
|
|
fi
|
|
print_success "PostgreSQL encontrado"
|
|
fi
|
|
|
|
# Verificar directorios
|
|
if [ ! -d "$BACKEND_DIR" ]; then
|
|
print_error "Backend no encontrado: $BACKEND_DIR"
|
|
exit 1
|
|
fi
|
|
print_success "Backend encontrado"
|
|
|
|
if [ ! -d "$FRONTEND_DIR" ]; then
|
|
print_error "Frontend no encontrado: $FRONTEND_DIR"
|
|
exit 1
|
|
fi
|
|
print_success "Frontend encontrado"
|
|
|
|
if [ ! -d "$DATABASE_DIR" ] && [ "$SKIP_DB" = false ]; then
|
|
print_error "Database no encontrado: $DATABASE_DIR"
|
|
exit 1
|
|
fi
|
|
[ "$SKIP_DB" = false ] && print_success "Database encontrado"
|
|
}
|
|
|
|
# ============================================================================
|
|
# INICIALIZACIÓN DE BASE DE DATOS
|
|
# ============================================================================
|
|
|
|
initialize_database() {
|
|
if [ "$SKIP_DB" = true ]; then
|
|
print_warning "Inicialización de BD omitida (--skip-db)"
|
|
return 0
|
|
fi
|
|
|
|
print_step "Inicializando base de datos..."
|
|
|
|
local db_script="$DATABASE_DIR/scripts/init-database.sh"
|
|
if [ ! -f "$db_script" ]; then
|
|
print_error "Script de BD no encontrado: $db_script"
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_info "[DRY-RUN] Ejecutaría: $db_script --env $ENVIRONMENT --force"
|
|
return 0
|
|
fi
|
|
|
|
# Ejecutar script de inicialización
|
|
if bash "$db_script" --env "$ENVIRONMENT" --force; then
|
|
print_success "Base de datos inicializada"
|
|
else
|
|
print_error "Error al inicializar base de datos"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# INSTALACIÓN DE DEPENDENCIAS
|
|
# ============================================================================
|
|
|
|
install_dependencies() {
|
|
print_step "Instalando dependencias..."
|
|
|
|
# Backend
|
|
print_info "Backend..."
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_info "[DRY-RUN] Ejecutaría: cd $BACKEND_DIR && npm install"
|
|
else
|
|
cd "$BACKEND_DIR"
|
|
if npm install --production=false; then
|
|
print_success "Dependencias de backend instaladas"
|
|
else
|
|
print_error "Error al instalar dependencias de backend"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Frontend
|
|
print_info "Frontend..."
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_info "[DRY-RUN] Ejecutaría: cd $FRONTEND_DIR && npm install"
|
|
else
|
|
cd "$FRONTEND_DIR"
|
|
if npm install; then
|
|
print_success "Dependencias de frontend instaladas"
|
|
else
|
|
print_error "Error al instalar dependencias de frontend"
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# TESTS
|
|
# ============================================================================
|
|
|
|
run_tests() {
|
|
if [ "$SKIP_TESTS" = true ]; then
|
|
print_warning "Tests omitidos (--skip-tests)"
|
|
return 0
|
|
fi
|
|
|
|
print_step "Ejecutando tests..."
|
|
|
|
# Backend tests
|
|
print_info "Tests de backend..."
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_info "[DRY-RUN] Ejecutaría: cd $BACKEND_DIR && npm test"
|
|
else
|
|
cd "$BACKEND_DIR"
|
|
if npm test; then
|
|
print_success "Tests de backend pasados"
|
|
else
|
|
print_warning "Tests de backend fallaron (continuando...)"
|
|
fi
|
|
fi
|
|
|
|
# Frontend tests
|
|
print_info "Tests de frontend..."
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_info "[DRY-RUN] Ejecutaría: cd $FRONTEND_DIR && npm run test:run"
|
|
else
|
|
cd "$FRONTEND_DIR"
|
|
if npm run test:run; then
|
|
print_success "Tests de frontend pasados"
|
|
else
|
|
print_warning "Tests de frontend fallaron (continuando...)"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# BUILD
|
|
# ============================================================================
|
|
|
|
build_applications() {
|
|
print_step "Building aplicaciones..."
|
|
|
|
# Backend
|
|
print_info "Building backend..."
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_info "[DRY-RUN] Ejecutaría: cd $BACKEND_DIR && npm run build"
|
|
else
|
|
cd "$BACKEND_DIR"
|
|
if npm run build; then
|
|
print_success "Backend built exitosamente"
|
|
else
|
|
print_error "Error al hacer build de backend"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Frontend
|
|
print_info "Building frontend..."
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_info "[DRY-RUN] Ejecutaría: cd $FRONTEND_DIR && npm run build:prod"
|
|
else
|
|
cd "$FRONTEND_DIR"
|
|
if npm run build:prod; then
|
|
print_success "Frontend built exitosamente"
|
|
else
|
|
print_error "Error al hacer build de frontend"
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# DEPLOYMENT CON PM2
|
|
# ============================================================================
|
|
|
|
deploy_with_pm2() {
|
|
print_step "Deploying con PM2..."
|
|
|
|
cd "$GAMILIT_ROOT"
|
|
|
|
# Crear directorio de logs
|
|
mkdir -p logs
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_info "[DRY-RUN] Ejecutaría: pm2 startOrRestart ecosystem.config.js --env $ENVIRONMENT"
|
|
return 0
|
|
fi
|
|
|
|
# Verificar si el ecosystem config existe
|
|
if [ ! -f "ecosystem.config.js" ]; then
|
|
print_error "ecosystem.config.js no encontrado"
|
|
exit 1
|
|
fi
|
|
|
|
# Deployment según ambiente
|
|
if [ "$ENVIRONMENT" = "prod" ] || [ "$ENVIRONMENT" = "production" ]; then
|
|
# Producción - solo backend
|
|
print_info "Iniciando backend en producción..."
|
|
pm2 startOrRestart ecosystem.config.js --only gamilit-backend --env production
|
|
|
|
print_success "Backend deployed con PM2"
|
|
|
|
print_info "Para servir el frontend en producción, usar Nginx/Apache"
|
|
print_info "O ejecutar: pm2 start ecosystem.config.js --only gamilit-frontend-preview --env production"
|
|
|
|
else
|
|
# Desarrollo - backend + frontend
|
|
print_info "Iniciando backend y frontend en desarrollo..."
|
|
pm2 startOrRestart ecosystem.config.js --env development
|
|
|
|
print_success "Backend y Frontend deployed con PM2"
|
|
fi
|
|
|
|
# Guardar configuración PM2
|
|
pm2 save
|
|
|
|
print_success "Deployment completado"
|
|
}
|
|
|
|
# ============================================================================
|
|
# HEALTH CHECKS
|
|
# ============================================================================
|
|
|
|
health_check() {
|
|
print_step "Validando health checks..."
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_info "[DRY-RUN] Omitiría health checks"
|
|
return 0
|
|
fi
|
|
|
|
# Esperar a que el servidor inicie
|
|
print_info "Esperando 10 segundos para que los servicios inicien..."
|
|
sleep 10
|
|
|
|
# Backend health check
|
|
print_info "Verificando backend..."
|
|
local backend_port=3006
|
|
if curl -s http://localhost:$backend_port/api/health > /dev/null 2>&1; then
|
|
print_success "Backend respondiendo en puerto $backend_port"
|
|
else
|
|
print_warning "Backend no responde en puerto $backend_port"
|
|
print_info "Verificar con: pm2 logs gamilit-backend"
|
|
fi
|
|
|
|
# Frontend health check (solo en dev)
|
|
if [ "$ENVIRONMENT" = "dev" ] || [ "$ENVIRONMENT" = "development" ]; then
|
|
print_info "Verificando frontend..."
|
|
local frontend_port=3005
|
|
if curl -s http://localhost:$frontend_port > /dev/null 2>&1; then
|
|
print_success "Frontend respondiendo en puerto $frontend_port"
|
|
else
|
|
print_warning "Frontend no responde en puerto $frontend_port"
|
|
print_info "Verificar con: pm2 logs gamilit-frontend-dev"
|
|
fi
|
|
fi
|
|
|
|
# Mostrar status de PM2
|
|
echo ""
|
|
pm2 status
|
|
}
|
|
|
|
# ============================================================================
|
|
# RESUMEN
|
|
# ============================================================================
|
|
|
|
show_summary() {
|
|
print_header "✅ DEPLOYMENT COMPLETADO"
|
|
|
|
echo -e "${CYAN}Ambiente:${NC} $ENVIRONMENT"
|
|
echo -e "${CYAN}Servidor de base de datos:${NC} localhost:5432"
|
|
echo ""
|
|
|
|
echo -e "${CYAN}Servicios desplegados:${NC}"
|
|
echo -e " ${GREEN}✓${NC} Backend API: http://localhost:3006"
|
|
echo -e " ${GREEN}✓${NC} API Docs: http://localhost:3006/api/docs"
|
|
|
|
if [ "$ENVIRONMENT" = "dev" ] || [ "$ENVIRONMENT" = "development" ]; then
|
|
echo -e " ${GREEN}✓${NC} Frontend: http://localhost:3005"
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${CYAN}Comandos útiles:${NC}"
|
|
echo -e " pm2 status # Ver status de procesos"
|
|
echo -e " pm2 logs # Ver logs en tiempo real"
|
|
echo -e " pm2 logs gamilit-backend # Logs del backend"
|
|
echo -e " pm2 restart all # Reiniciar todos los procesos"
|
|
echo -e " pm2 stop all # Detener todos los procesos"
|
|
echo -e " pm2 monit # Monitor interactivo"
|
|
echo ""
|
|
}
|
|
|
|
# ============================================================================
|
|
# MAIN
|
|
# ============================================================================
|
|
|
|
main() {
|
|
# Parsear argumentos
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--env)
|
|
ENVIRONMENT="$2"
|
|
shift 2
|
|
;;
|
|
--skip-db)
|
|
SKIP_DB=true
|
|
shift
|
|
;;
|
|
--skip-tests)
|
|
SKIP_TESTS=true
|
|
shift
|
|
;;
|
|
--dry-run)
|
|
DRY_RUN=true
|
|
shift
|
|
;;
|
|
--help)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
*)
|
|
print_error "Opción desconocida: $1"
|
|
show_help
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Validar argumentos
|
|
if [ -z "$ENVIRONMENT" ]; then
|
|
print_error "Debe especificar --env dev|prod"
|
|
show_help
|
|
exit 1
|
|
fi
|
|
|
|
# Normalizar ambiente
|
|
if [ "$ENVIRONMENT" = "production" ]; then
|
|
ENVIRONMENT="prod"
|
|
elif [ "$ENVIRONMENT" = "development" ]; then
|
|
ENVIRONMENT="dev"
|
|
fi
|
|
|
|
if [ "$ENVIRONMENT" != "dev" ] && [ "$ENVIRONMENT" != "prod" ]; then
|
|
print_error "Ambiente debe ser 'dev' o 'prod'"
|
|
exit 1
|
|
fi
|
|
|
|
# Mostrar banner
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_header "🚀 GAMILIT DEPLOYMENT (DRY-RUN) - $ENVIRONMENT"
|
|
else
|
|
print_header "🚀 GAMILIT DEPLOYMENT - $ENVIRONMENT"
|
|
fi
|
|
|
|
# Ejecutar pasos
|
|
check_prerequisites
|
|
initialize_database
|
|
install_dependencies
|
|
run_tests
|
|
build_applications
|
|
deploy_with_pm2
|
|
health_check
|
|
show_summary
|
|
}
|
|
|
|
main "$@"
|