From 7f32380e0aaaed1dbf27cf6667bda5a41128c606 Mon Sep 17 00:00:00 2001 From: Mireya Cueto Garrido Date: Tue, 2 Jun 2026 10:25:53 +0200 Subject: [PATCH] Adapt CI/CD and endpoint defaults for Sinbad2 production. Configure GitLab deploy pipeline for this app and switch backend/frontend endpoint defaults from localhost to sinbad2.ujaen.es, including Docker, env files, API client, CORS, and docs. --- .gitlab-ci.yml | 38 ++++++++++++++++++++++++++++++++++++++ GUIA_API_Y_FLUJO.md | 12 ++++++------ README.md | 2 +- backend/.env | 4 ++-- backend/.env.example | 2 +- backend/app/core/config.py | 2 +- docker-compose.yml | 4 ++-- frontend/.env.example | 2 +- frontend/Dockerfile | 2 +- frontend/README.md | 8 ++++---- frontend/src/api/client.js | 2 +- 11 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..0362ccf --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,38 @@ +stages: + - deploy + +variables: + APP_NAME: "generadorexamenesllms" + BACKEND_PORT: "8074" + FRONTEND_PORT: "8075" + +deploy_to_sinbad2: + stage: deploy + + before_script: + - eval $(ssh-agent -s) + - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - ssh-keyscan $SSH_HOST >> ~/.ssh/known_hosts + + script: + - echo "Enviando código a Sinbad2..." + - ssh $REMOTE_USER@$SSH_HOST "mkdir -p ~/deploy_$APP_NAME" + + - scp -r ./* $REMOTE_USER@$SSH_HOST:~/deploy_$APP_NAME/ + + - echo "Levantando contenedores con Docker Compose..." + - ssh $REMOTE_USER@$SSH_HOST " + cd ~/deploy_$APP_NAME && + docker compose down --remove-orphans && + docker compose build --no-cache frontend backend && + docker compose up -d + " + + - echo "Despliegue completado." + - echo "Backend -> http://sinbad2.ujaen.es:$BACKEND_PORT" + - echo "Frontend -> http://sinbad2.ujaen.es:$FRONTEND_PORT" + + only: + - branches \ No newline at end of file diff --git a/GUIA_API_Y_FLUJO.md b/GUIA_API_Y_FLUJO.md index 3444973..f717f78 100644 --- a/GUIA_API_Y_FLUJO.md +++ b/GUIA_API_Y_FLUJO.md @@ -2,7 +2,7 @@ Documento resumen para entender **qué hace el usuario en cada paso**, **qué endpoint usar**, **cabeceras**, **cuerpos**, **ejemplos de respuesta** y **errores típicos**. -**Base URL de ejemplo:** `http://localhost:8074` +**Base URL de ejemplo:** `http://sinbad2.ujaen.es:8074` --- @@ -131,7 +131,7 @@ Detalle de cuerpos, respuestas y errores: **sección 4** de esta guía. **Ejemplo:** ```bash -curl -s http://localhost:8074/health +curl -s http://sinbad2.ujaen.es:8074/health ``` **Respuesta OK (200):** @@ -165,7 +165,7 @@ curl -s http://localhost:8074/health **Ejemplo:** ```bash -curl -s -X POST http://localhost:8074/auth/register \ +curl -s -X POST http://sinbad2.ujaen.es:8074/auth/register \ -H "Content-Type: application/json" \ -d '{"email":"profesor@ejemplo.com","password":"ClaveSegura1","full_name":"María"}' ``` @@ -303,7 +303,7 @@ Todas requieren: `Authorization: Bearer ` **Ejemplo mínimo:** ```bash -curl -s -X POST http://localhost:8074/exam/templates \ +curl -s -X POST http://sinbad2.ujaen.es:8074/exam/templates \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ @@ -415,7 +415,7 @@ Sirven para **texto** que la IA puede usar al generar (PDF, DOCX, TXT, MD; imág **Ejemplo:** ```bash -curl -s -X POST "http://localhost:8074/exam/templates/TEMPLATE_UUID/materials" \ +curl -s -X POST "http://sinbad2.ujaen.es:8074/exam/templates/TEMPLATE_UUID/materials" \ -H "Authorization: Bearer $TOKEN" \ -F "file=@./apuntes.pdf" ``` @@ -468,7 +468,7 @@ Solo para **mostrar en la pregunta** (Moodle); no rellenan el contexto de texto **Ejemplo:** ```bash -curl -s -X POST "http://localhost:8074/exam/templates/TEMPLATE_UUID/images" \ +curl -s -X POST "http://sinbad2.ujaen.es:8074/exam/templates/TEMPLATE_UUID/images" \ -H "Authorization: Bearer $TOKEN" \ -F "file=@./diagrama.png" \ -F "caption=Diagrama del modelo ER" diff --git a/README.md b/README.md index 5c38df6..6dd5402 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ docker compose up --build La API queda disponible en: ```text -http://localhost:8074 +http://sinbad2.ujaen.es:8074 ``` ## Configuración diff --git a/backend/.env b/backend/.env index 29dca11..d0ed64e 100644 --- a/backend/.env +++ b/backend/.env @@ -6,7 +6,7 @@ API_KEY=change-me-in-production-min-16-chars # --- Base de datos (Docker: host "db") --- DATABASE_URL=postgresql+psycopg://genexamenes:genexamenes@db:5432/genexamenes # --- CORS (orígenes del frontend, separados por coma) --- -ALLOWED_ORIGINS=http://localhost:8075 +ALLOWED_ORIGINS=http://sinbad2.ujaen.es,http://sinbad2.ujaen.es:8075 # --- Rate limiting y tamaño de petición --- RATE_LIMIT_REQUESTS=60 RATE_LIMIT_WINDOW_SECONDS=60 @@ -20,4 +20,4 @@ GOOGLE_CLIENT_ID=123456789012-abcdefghijklmnopqrstuvwxyz123456.apps.googleuserco # --- LLM (Sinbad2IA UJA — sin clave) --- LLM_BASE_URL= LLM_MODEL=qwen3.5:35b -LLM_TIMEOUT_SECONDS=180 \ No newline at end of file +LLM_TIMEOUT_SECONDS=180 diff --git a/backend/.env.example b/backend/.env.example index af09411..87db385 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -9,7 +9,7 @@ API_KEY=change-me-in-production-min-16-chars DATABASE_URL=postgresql+psycopg://genexamenes:genexamenes@db:5432/genexamenes # --- CORS (orígenes del frontend, separados por coma) --- -ALLOWED_ORIGINS=http://localhost:8075 +ALLOWED_ORIGINS=http://sinbad2.ujaen.es,http://sinbad2.ujaen.es:8075 # --- Rate limiting y tamaño de petición --- RATE_LIMIT_REQUESTS=60 diff --git a/backend/app/core/config.py b/backend/app/core/config.py index 4d5f827..daaa2aa 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -10,7 +10,7 @@ class Settings(BaseSettings): api_prefix: str = "" api_key: str = Field(min_length=16) database_url: str = "postgresql+psycopg://genexamenes:genexamenes@localhost:5432/genexamenes" - allowed_origins: str = "http://localhost:8075" + allowed_origins: str = "http://sinbad2.ujaen.es,http://sinbad2.ujaen.es:8075" rate_limit_requests: int = Field(default=60, ge=1) rate_limit_window_seconds: int = Field(default=60, ge=1) max_request_bytes: int = Field(default=1_048_576, ge=1_024) diff --git a/docker-compose.yml b/docker-compose.yml index 8aada33..c860b23 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: environment: DATABASE_URL: postgresql+psycopg://genexamenes:genexamenes@db:5432/genexamenes # Sobrescribe backend/.env con el puerto actual del frontend. - ALLOWED_ORIGINS: http://localhost:8075 + ALLOWED_ORIGINS: http://sinbad2.ujaen.es,http://sinbad2.ujaen.es:8075 LLM_BASE_URL: LLM_MODEL: qwen3.5:35b LLM_TIMEOUT_SECONDS: "180" @@ -24,7 +24,7 @@ services: build: context: ./frontend args: - VITE_API_URL: ${VITE_API_URL:-http://localhost:8074} + VITE_API_URL: ${VITE_API_URL:-http://sinbad2.ujaen.es:8074} VITE_GOOGLE_CLIENT_ID: ${VITE_GOOGLE_CLIENT_ID:-} ports: - "8075:80" diff --git a/frontend/.env.example b/frontend/.env.example index 952b12d..c77d877 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -1,5 +1,5 @@ # URL base del backend (accesible desde el navegador) -VITE_API_URL=http://localhost:8074 +VITE_API_URL=http://sinbad2.ujaen.es:8074 # (Opcional) Client ID de Google para "Iniciar sesión con Google". # Debe coincidir con GOOGLE_CLIENT_ID del backend. diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 9664897..db038d7 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -2,7 +2,7 @@ FROM node:20-alpine AS build WORKDIR /app -ARG VITE_API_URL=http://localhost:8074 +ARG VITE_API_URL=http://sinbad2.ujaen.es:8074 ARG VITE_GOOGLE_CLIENT_ID= ENV VITE_API_URL=$VITE_API_URL ENV VITE_GOOGLE_CLIENT_ID=$VITE_GOOGLE_CLIENT_ID diff --git a/frontend/README.md b/frontend/README.md index fdcc233..23561c4 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -25,20 +25,20 @@ src/ ## Desarrollo local -Requisitos: Node 20+ y el backend corriendo en `http://localhost:8074`. +Requisitos: Node 20+ y el backend corriendo en `http://sinbad2.ujaen.es:8074`. ```bash cd frontend cp .env.example .env # ajusta VITE_API_URL si es necesario npm install -npm run dev # http://localhost:8075 +npm run dev # http://sinbad2.ujaen.es:8075 ``` ## Variables de entorno | Variable | Descripción | | ----------------------- | -------------------------------------------------------- | -| `VITE_API_URL` | URL base del backend (por defecto `http://localhost:8074`). | +| `VITE_API_URL` | URL base del backend (por defecto `http://sinbad2.ujaen.es:8074`). | | `VITE_GOOGLE_CLIENT_ID` | (Opcional) Client ID de Google. Si está vacío, se oculta el botón de Google. | > Las variables `VITE_*` se incrustan en el build, por lo que apuntan al backend @@ -54,7 +54,7 @@ npm run preview # sirve el build localmente ## Docker El `docker-compose.yml` de la raíz construye el frontend con un build multi-stage -(Node → Nginx) y lo publica en `http://localhost:8075`: +(Node → Nginx) y lo publica en `http://sinbad2.ujaen.es:8075`: ```bash docker compose up --build diff --git a/frontend/src/api/client.js b/frontend/src/api/client.js index e4ec5ec..a91a29f 100644 --- a/frontend/src/api/client.js +++ b/frontend/src/api/client.js @@ -1,7 +1,7 @@ import axios from "axios"; export const API_URL = - import.meta.env.VITE_API_URL?.replace(/\/$/, "") || "http://localhost:8074"; + import.meta.env.VITE_API_URL?.replace(/\/$/, "") || "http://sinbad2.ujaen.es:8074"; const TOKEN_KEY = "genex_token";