diff --git a/projects/gamilit/.gitignore b/projects/gamilit/.gitignore index 58e51ca..08f62d0 100644 --- a/projects/gamilit/.gitignore +++ b/projects/gamilit/.gitignore @@ -1,148 +1,106 @@ # GAMILIT Monorepo - .gitignore # Generado: 2025-11-01 (RFC-0001) -# Actualizado: 2025-12-05 -# ============================================ -# NODE.JS - DEPENDENCIAS (GLOBAL) -# ============================================ -# Ignorar node_modules en CUALQUIER nivel de anidación -**/node_modules/ - -# Lock files de otros package managers (mantener solo package-lock.json) -yarn.lock -pnpm-lock.yaml -bun.lockb - -# Logs de npm/yarn/pnpm +# === NODE.JS === +node_modules/ npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* .pnpm-debug.log* -# Directorios de dependencias alternativas +# Dependency directories jspm_packages/ -bower_components/ -# Cache de npm -.npm/ -.npmrc.local +# Optional npm cache directory +.npm -# Cache de eslint/stylelint +# Optional eslint cache .eslintcache + +# Optional stylelint cache .stylelintcache -# ============================================ -# TYPESCRIPT / BUILD ARTIFACTS (GLOBAL) -# ============================================ -# Ignorar dist/build en CUALQUIER nivel -**/dist/ -**/build/ -**/out/ -**/.next/ -**/.nuxt/ -**/.turbo/ - -# TypeScript +# === TYPESCRIPT === *.tsbuildinfo -**/*.tsbuildinfo +dist/ +build/ *.js.map -# ============================================ -# FRAMEWORKS ESPECÍFICOS -# ============================================ -# Angular / NX +# === ANGULAR / NX === .angular/ -.nx/ -**/.nx/ +.nx/cache/ +.nx/workspace-data/ -# Vite -**/.vite/ +# === NESTJS === +/apps/backend/dist/ +/apps/backend/build/ -# Webpack -.webpack/ -**/.webpack/ - -# ============================================ -# ENVIRONMENT FILES - SECRETS -# ============================================ -# CRÍTICO: Nunca commitear secrets +# === ENVIRONMENT FILES === +# IMPORTANTE: Nunca commitear secrets reales .env .env.local .env.*.local .env.production .env.development .env.test -.env.staging +# Permitir archivos de ejemplo (sin secrets) +!.env.*.example +!.env.example -# Archivos con secrets -**/secrets.json -**/credentials.json +# Archivos de configuración con secrets +config/secrets.json +config/credentials.json **/*secrets*.json **/*credentials*.json -**/*.secret -**/*.secrets -# Configuración de base de datos con credenciales -**/database.config.ts -!**/database.config.example.ts -**/ormconfig.json -!**/ormconfig.example.json - -# ============================================ -# DATABASES -# ============================================ -# Backups y dumps +# === DATABASES === +# PostgreSQL *.sql.backup *.dump *.pgdata -*.sql.gz -# Bases de datos locales +# Local database files *.sqlite *.sqlite3 *.db -*.db-journal -# Redis -dump.rdb +# Database connection strings (excepción: ejemplos con .example) +database.config.ts +!database.config.example.ts -# ============================================ -# LOGS (GLOBAL) -# ============================================ -**/logs/ -**/*.log -**/pm2-logs/ -**/*.pm2.log +# === LOGS === +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* -# ============================================ -# TESTING (GLOBAL) -# ============================================ -**/coverage/ -**/.nyc_output/ +# PM2 logs +pm2-logs/ +*.pm2.log + +# === TESTING === +coverage/ +.nyc_output/ *.lcov # Jest -**/jest-cache/ -.jest/ +jest-cache/ # Cypress -**/cypress/screenshots/ -**/cypress/videos/ -**/cypress/downloads/ - -# Playwright -**/playwright-report/ -**/playwright/.cache/ -**/test-results/ +cypress/screenshots/ +cypress/videos/ +cypress/downloads/ # E2E reports -**/e2e-reports/ +e2e-reports/ +test-results/ -# ============================================ -# IDEs and EDITORS -# ============================================ -# VSCode - mantener configuración compartida +# === IDEs and EDITORS === +# VSCode .vscode/* !.vscode/settings.json !.vscode/tasks.json @@ -161,117 +119,92 @@ dump.rdb *.sublime-workspace *.sublime-project -# Vim/Neovim +# Vim *.swp *.swo *~ -.netrwhist -Session.vim # Emacs +*~ \#*\# .\#* -*.elc -auto-save-list/ -# ============================================ -# OS FILES -# ============================================ +# === OS FILES === # macOS .DS_Store .AppleDouble .LSOverride ._* -.Spotlight-V100 -.Trashes # Linux *~ .directory -.Trash-* # Windows Thumbs.db -Thumbs.db:encryptable ehthumbs.db -ehthumbs_vista.db Desktop.ini $RECYCLE.BIN/ -*.lnk -# ============================================ -# DOCKER -# ============================================ +# === DOCKER === +# No ignorar Dockerfiles, solo archivos temporales docker-compose.override.yml -docker-compose.local.yml .dockerignore.local -**/*.dockerignore.local -# ============================================ -# DEPLOYMENT & SECURITY -# ============================================ +# === BUILD ARTIFACTS === +/apps/*/dist/ +/apps/*/build/ +/libs/*/dist/ + +# Webpack +.webpack/ + +# === DEPLOYMENT === # PM2 ecosystem.config.js.local pm2.config.js.local -# Claves y certificados +# Deploy keys (excepción: .example files) *.pem *.key -*.p12 -*.pfx !*.example.pem !*.example.key -# SSL certificates +# SSL certificates (excepción: self-signed para dev) *.crt *.cer !dev-cert.crt -!*.example.crt -# SSH keys -id_rsa* -id_ed25519* -*.pub -!*.example.pub +# === TEMP FILES === +tmp/ +temp/ +*.tmp +*.temp +*.cache -# ============================================ -# TEMP FILES (GLOBAL) -# ============================================ -**/tmp/ -**/temp/ -**/.tmp/ -**/.temp/ -**/*.tmp -**/*.temp -**/*.cache -**/.cache/ - -# ============================================ -# ARTIFACTS -# ============================================ +# === ARTIFACTS (parcial) === +# Mantener reportes importantes, ignorar temporales /artifacts/temp/ /artifacts/cache/ /artifacts/**/*.tmp -/artifacts/**/*.cache -# ============================================ -# CLAUDE CODE / AI -# ============================================ -# Configuración local de Claude Code +# === CLAUDE CODE === +# Excluir toda la carpeta .claude (configuración local de IA) .claude/ -# Pero NO ignorar orchestration (necesario para Claude Code cloud) -# Solo ignorar temporales dentro de orchestration +# === ORCHESTRATION === +# IMPORTANTE: orchestration/ DEBE estar en el repo para Claude Code cloud +# Contiene: prompts, directivas, trazas, inventarios, templates +# Solo ignorar subcarpetas temporales específicas y archivos comprimidos orchestration/.archive/ orchestration/.tmp/ orchestration/**/*.tmp orchestration/**/*.cache -# ============================================ -# REFERENCE (Código de Referencia) -# ============================================ -# reference/ DEBE estar en el repo -# Solo ignorar build/dependencias dentro +# === REFERENCE (Código de Referencia) === +# IMPORTANTE: reference/ DEBE estar en el repo para Claude Code cloud +# Contiene: proyectos de referencia para análisis y desarrollo +# Ignorar solo carpetas de build/dependencias dentro de reference/ reference/**/node_modules/ reference/**/dist/ reference/**/build/ @@ -286,9 +219,16 @@ reference/**/*.tmp reference/**/*.cache reference/**/.DS_Store -# ============================================ -# PACKAGE MANAGERS -# ============================================ +# === MIGRATION (temporal) === +# Durante migración, mantener docs de análisis +# Descomentar después de migración completa: +# /docs-analysis/ + +# === ARCHIVOS ESPECÍFICOS GRANDES === +# Si hay archivos markdown extremadamente grandes (>50MB), considerarlos para LFS +# *.large.md + +# === PACKAGE MANAGERS === # Yarn .yarn/* !.yarn/patches @@ -301,102 +241,33 @@ reference/**/.DS_Store # PNPM .pnpm-store/ -# ============================================ -# MONITORING & OBSERVABILITY -# ============================================ +# === MONITORING === +# Application monitoring newrelic_agent.log .monitors/ -**/.sentry/ -**/sentry-debug.log -# ============================================ -# BACKUPS (GLOBAL) -# ============================================ -# Archivos +# === MISC === +# Backups - Archivos *.backup *.bak *.old -*.orig -# Carpetas -**/*_old/ -**/*_bckp/ -**/*_bkp/ -**/*_backup/ -**/*.old/ -**/*.bak/ -**/*.backup/ +# Backups - Carpetas +*_old/ +*_bckp/ +*_bkp/ +*_backup/ +*.old/ +*.bak/ +*.backup/ -# Específicos del proyecto +# Backups específicos (carpetas identificadas en workspace) orchestration_old/ orchestration_bckp/ docs_bkp/ -# ============================================ -# COMPRESSED FILES -# ============================================ +# Compressed files (si no son assets del proyecto) *.zip *.tar.gz -*.tar *.rar -*.7z -# Excepto assets !assets/**/*.zip -!public/**/*.zip - -# ============================================ -# MISCELÁNEOS -# ============================================ -# Archivos de debug -**/*.debug -**/debug.log - -# Archivos de error -**/*.error -**/error.log - -# Storybook -**/storybook-static/ - -# Parcel -.parcel-cache/ - -# Serverless -.serverless/ - -# FuseBox -.fusebox/ - -# DynamoDB Local -.dynamodb/ - -# TernJS -.tern-port - -# Archivos generados por IDEs -*.code-workspace - -# Archivos de licencia generados -LICENSE.txt.bak - -# ============================================ -# APPS ESPECÍFICAS DEL MONOREPO -# ============================================ -# Backend NestJS -apps/backend/dist/ -apps/backend/build/ -apps/backend/.nest/ - -# Frontend React/Vite -apps/frontend/dist/ -apps/frontend/build/ -apps/frontend/.vite/ - -# Database - mantener DDL, ignorar generados -apps/database/*.dump -apps/database/*.backup -apps/database/data/ - -# DevOps - ignorar logs y temp -apps/devops/logs/ -apps/devops/tmp/ diff --git a/projects/gamilit/apps/backend/.env.production.example b/projects/gamilit/apps/backend/.env.production.example new file mode 100644 index 0000000..4179c93 --- /dev/null +++ b/projects/gamilit/apps/backend/.env.production.example @@ -0,0 +1,137 @@ +# ============================================================================ +# GAMILIT Backend - Production Environment Variables (EXAMPLE) +# ============================================================================ +# INSTRUCCIONES: +# 1. Copiar este archivo a .env.production +# 2. Reemplazar todos los valores <...> con valores reales +# 3. Configurar como variables de entorno del sistema (recomendado) +# O usar archivo .env.production (asegurar permisos restrictivos) + +# ==================== SERVER ==================== +NODE_ENV=production +PORT=3006 +API_PREFIX=api + +# ==================== DATABASE ==================== +# IMPORTANTE: Usar credenciales seguras en producción +DB_HOST=localhost +DB_PORT=5432 +DB_NAME=gamilit_platform +DB_USER=gamilit_user +DB_PASSWORD= +DB_SYNCHRONIZE=false +DB_LOGGING=false + +# ==================== JWT ==================== +# IMPORTANTE: NUNCA usar valores de ejemplo en producción +# Generar secret seguro con: openssl rand -base64 32 +JWT_SECRET= +JWT_EXPIRES_IN=15m +JWT_REFRESH_EXPIRES_IN=7d + +# ==================== CORS ==================== +# CRÍTICO: Configurar orígenes permitidos correctamente +# +# ============================================================================ +# ADVERTENCIA: HEADERS CORS DUPLICADOS +# ============================================================================ +# Si usas Nginx como proxy SSL, NO agregar headers CORS en Nginx. +# NestJS maneja CORS internamente en main.ts. +# Headers duplicados causan error: +# "The 'Access-Control-Allow-Origin' header contains multiple values" +# +# SOLUCION: Solo NestJS maneja CORS, Nginx solo hace proxy sin headers CORS. +# Ver: docs/95-guias-desarrollo/GUIA-CORS-PRODUCCION.md +# ============================================================================ +# +# Servidor actual: 74.208.126.102 +# Frontend puerto: 3005 +# +# CONFIGURACION RECOMENDADA CON SSL: +# Incluye HTTPS y HTTP para compatibilidad durante transición +CORS_ORIGIN=https://74.208.126.102:3005,https://74.208.126.102,http://74.208.126.102:3005,http://74.208.126.102 +ENABLE_CORS=true +ENABLE_SWAGGER=false + +# ==================== LOGGING ==================== +LOG_LEVEL=warn +LOG_TO_FILE=true + +# ==================== RATE LIMITING ==================== +RATE_LIMIT_TTL=60 +RATE_LIMIT_MAX=100 + +# ==================== SESSION ==================== +# Generar secret con: openssl rand -base64 32 +SESSION_SECRET= +SESSION_MAX_AGE=86400000 + +# ==================== EMAIL ==================== +# Configurar si se usa envío de emails +EMAIL_FROM=noreply@gamilit.com +EMAIL_REPLY_TO=support@gamilit.com + +# ==================== FRONTEND URL ==================== +# URL del frontend para redirects, links en emails, etc. +# IMPORTANTE: Usar HTTPS si el servidor tiene SSL configurado +FRONTEND_URL=https://74.208.126.102:3005 + +# ==================== WEB PUSH NOTIFICATIONS (VAPID) ==================== +# Web Push API nativo - No requiere servicios externos (Firebase, etc.) +# IMPORTANTE: Generar claves VAPID con el comando: +# npx web-push generate-vapid-keys +# +# VAPID (Voluntary Application Server Identification): +# - Public Key: Se comparte con el frontend para crear subscripciones +# - Private Key: Se mantiene secreta en backend para firmar notificaciones +# - Subject: Email de contacto o URL del sitio (mailto: o https:) +# +# Ejemplo de generación: +# $ npx web-push generate-vapid-keys +# Public Key: BN4GvZtEZiZuqaaObWga7lEP-S1WCv7L1c... +# Private Key: aB3cDefGh4IjKlM5nOpQr6StUvWxYz... +# +# Compatible con: Chrome, Firefox, Edge, Safari 16.4+ +# NOTA: Si no se configuran, push notifications quedarán deshabilitadas (graceful degradation) +# +VAPID_PUBLIC_KEY= +VAPID_PRIVATE_KEY= +VAPID_SUBJECT=mailto:admin@gamilit.com + +# ==================== OPCIONALES ==================== +# Descomentar y configurar si se usan + +# Uploads +# MAX_FILE_SIZE=5242880 +# UPLOAD_DESTINATION=./uploads +# ALLOWED_MIME_TYPES=image/jpeg,image/png,image/gif,application/pdf + +# Mantenimiento +# MAINTENANCE_MODE=false + +# ============================================================================ +# NOTAS DE SEGURIDAD +# ============================================================================ +# +# 1. JWT_SECRET: DEBE ser diferente al de desarrollo, usar 32+ caracteres aleatorios +# 2. DB_PASSWORD: NUNCA commitear credenciales reales al repositorio +# 3. SESSION_SECRET: Generar valor único y seguro +# 4. CORS_ORIGIN: Solo incluir orígenes confiables, NUNCA usar "*" +# 5. ENABLE_SWAGGER: DEBE estar en false en producción +# 6. Permisos archivo: chmod 600 .env.production (solo owner puede leer) +# 7. Logs: Verificar que LOG_TO_FILE no exponga datos sensibles +# +# ============================================================================ +# VALIDACIÓN PRE-DEPLOY +# ============================================================================ +# +# Antes de deploy, verificar: +# [ ] JWT_SECRET cambiado de valor de ejemplo +# [ ] DB_PASSWORD configurado correctamente +# [ ] CORS_ORIGIN incluye origen del frontend en producción +# [ ] ENABLE_SWAGGER=false +# [ ] FRONTEND_URL apunta a URL correcta +# [ ] Todas las variables <...> reemplazadas +# [ ] VAPID_* configuradas si se requieren push notifications (generar con npx web-push generate-vapid-keys) +# +# ============================================================================ diff --git a/projects/gamilit/apps/backend/.gitignore b/projects/gamilit/apps/backend/.gitignore index 763b2d2..862f668 100644 --- a/projects/gamilit/apps/backend/.gitignore +++ b/projects/gamilit/apps/backend/.gitignore @@ -33,13 +33,11 @@ coverage/ logs/ *.log -# Uploads (keep directory structure but ignore files) -uploads/exercises/* -!uploads/exercises/.gitkeep - .env* .flaskenv* !.env.project !.env.vault +!.env.*.example +!.env.example # Backups de scripts automáticos **/*.backup-* diff --git a/projects/gamilit/apps/frontend/.env.production.example b/projects/gamilit/apps/frontend/.env.production.example new file mode 100644 index 0000000..c31d58c --- /dev/null +++ b/projects/gamilit/apps/frontend/.env.production.example @@ -0,0 +1,53 @@ +# ============================================================================ +# GAMILIT Frontend - Production Environment EXAMPLE +# ============================================================================ +# COPIAR A .env.production +# Fecha: 2025-12-18 +# Server: 74.208.126.102 +# ============================================================================ + +# ==================== APPLICATION ==================== +VITE_APP_NAME=GAMILIT Platform +VITE_APP_VERSION=1.0.0 +VITE_APP_ENV=production +VITE_ENV=production + +# ==================== API CONFIGURATION ==================== +# IMPORTANTE: Usar HTTPS/WSS si el servidor tiene SSL configurado +# ============================================================================ +# SSL CONFIGURADO - Usar HTTPS/WSS +# ============================================================================ +VITE_API_HOST=74.208.126.102:3006 +VITE_API_PROTOCOL=https +VITE_API_VERSION=v1 +VITE_API_TIMEOUT=30000 + +# WebSocket configuration (WSS para conexiones seguras) +VITE_WS_HOST=74.208.126.102:3006 +VITE_WS_PROTOCOL=wss + +# ==================== AUTHENTICATION ==================== +VITE_JWT_EXPIRATION=7d + +# ==================== FEATURE FLAGS ==================== +VITE_ENABLE_GAMIFICATION=true +VITE_ENABLE_SOCIAL_FEATURES=true +VITE_ENABLE_ANALYTICS=true +VITE_ENABLE_DEBUG=false +VITE_ENABLE_STORYBOOK=false +VITE_MOCK_API=false + +# ==================== EXTERNAL SERVICES ==================== +# Configurar en produccion si se usan +VITE_GOOGLE_ANALYTICS_ID= +VITE_SENTRY_DSN= +VITE_AI_SERVICE_URL= + +# ==================== PRODUCTION ==================== +VITE_ENABLE_DEBUG=false +VITE_LOG_LEVEL=error + +# ==================== TESTING ==================== +# NO usar credenciales en produccion +VITE_TEST_USER_EMAIL= +VITE_TEST_USER_PASSWORD= diff --git a/projects/gamilit/docs/95-guias-desarrollo/GUIA-CORS-PRODUCCION.md b/projects/gamilit/docs/95-guias-desarrollo/GUIA-CORS-PRODUCCION.md new file mode 100644 index 0000000..e222f8d --- /dev/null +++ b/projects/gamilit/docs/95-guias-desarrollo/GUIA-CORS-PRODUCCION.md @@ -0,0 +1,157 @@ +# GUIA-CORS-PRODUCCION.md + +## Configuración CORS para Producción - GAMILIT + +**Fecha**: 2025-12-18 +**Problema resuelto**: Error `Access-Control-Allow-Origin contains multiple values` + +--- + +## 1. Descripción del Problema + +Al hacer requests desde el frontend (puerto 3005) al backend (puerto 3006) en producción con HTTPS, se recibe el error: + +``` +Access to XMLHttpRequest at 'https://74.208.126.102:3006/api/v1/auth/register' +from origin 'https://74.208.126.102:3005' has been blocked by CORS policy: +The 'Access-Control-Allow-Origin' header contains multiple values +'https://74.208.126.102:3005, https://74.208.126.102:3005', but only one is allowed. +``` + +--- + +## 2. Causa Raíz + +El header `Access-Control-Allow-Origin` se está enviando **DOS VECES**: + +1. **Nginx** (proxy SSL) agrega headers CORS +2. **NestJS** (backend) también agrega headers CORS via `app.enableCors()` + +Cuando ambos envían el header, el navegador ve valores duplicados y rechaza la respuesta. + +--- + +## 3. Solución Definitiva + +### Regla de Oro: **Solo NestJS maneja CORS** + +Nginx debe actuar únicamente como proxy SSL sin agregar headers CORS. + +### 3.1 Configuración Backend (.env.production) + +```bash +# CORS - CONFIGURACIÓN CRÍTICA +# ============================================================================ +# ADVERTENCIA: HEADERS CORS DUPLICADOS +# ============================================================================ +# Si usas Nginx como proxy SSL, NO agregar headers CORS en Nginx. +# NestJS maneja CORS internamente en main.ts. +# Headers duplicados causan error: +# "The 'Access-Control-Allow-Origin' header contains multiple values" +# ============================================================================ + +# Incluye HTTPS y HTTP para compatibilidad durante transición +CORS_ORIGIN=https://74.208.126.102:3005,https://74.208.126.102,http://74.208.126.102:3005,http://74.208.126.102 +ENABLE_CORS=true +``` + +### 3.2 Configuración Frontend (.env.production) + +```bash +# SSL CONFIGURADO - Usar HTTPS/WSS +VITE_API_HOST=74.208.126.102:3006 +VITE_API_PROTOCOL=https +VITE_WS_HOST=74.208.126.102:3006 +VITE_WS_PROTOCOL=wss +``` + +### 3.3 Configuración Nginx (SIN CORS) + +```nginx +# /etc/nginx/sites-available/gamilit-backend +server { + listen 3006 ssl; + server_name 74.208.126.102; + + ssl_certificate /etc/ssl/certs/gamilit.crt; + ssl_certificate_key /etc/ssl/private/gamilit.key; + + location / { + proxy_pass http://127.0.0.1:3007; # PM2 cluster interno + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + + # ⚠️ NO AGREGAR headers CORS aquí + # NestJS los maneja internamente + } +} +``` + +--- + +## 4. Verificación + +### 4.1 Verificar headers con curl + +```bash +# Verificar que solo hay UN header Access-Control-Allow-Origin +curl -I -X OPTIONS \ + -H "Origin: https://74.208.126.102:3005" \ + -H "Access-Control-Request-Method: POST" \ + https://74.208.126.102:3006/api/v1/auth/register + +# Salida esperada (UN solo header): +# Access-Control-Allow-Origin: https://74.208.126.102:3005 +# Access-Control-Allow-Credentials: true +# Access-Control-Allow-Methods: GET,POST,PUT,PATCH,DELETE,OPTIONS +``` + +### 4.2 Verificar configuración Nginx + +```bash +# Buscar headers CORS duplicados en configuración +grep -r "Access-Control" /etc/nginx/ +``` + +Si encuentra líneas como `add_header Access-Control-Allow-Origin`, elimínelas. + +--- + +## 5. Pasos de Deploy + +1. **Backend**: Actualizar `.env.production` con HTTPS origins +2. **Frontend**: Actualizar `.env.production` con HTTPS/WSS +3. **Nginx**: Remover cualquier header CORS +4. **Reiniciar servicios**: + ```bash + sudo systemctl reload nginx + pm2 restart gamilit-backend + cd /path/to/frontend && npm run build + ``` + +--- + +## 6. Troubleshooting + +### Error persiste después de la configuración +1. Verificar que Nginx no tenga headers CORS en ningún include +2. Revisar si hay otro proxy (CloudFlare, etc.) agregando headers +3. Limpiar cache del navegador (F12 > Network > Disable cache) + +### Error "CORS blocked request" en logs +- El origen que hace la petición no está en CORS_ORIGIN +- Verificar que el protocolo coincide (https vs http) + +--- + +## 7. Referencias + +- **Backend CORS**: `apps/backend/src/main.ts` líneas 27-46 +- **Config CORS**: `apps/backend/src/config/app.config.ts` +- **Ejemplo .env**: `apps/backend/.env.production.example`