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.
This commit is contained in:
Mireya Cueto Garrido
2026-06-02 10:25:53 +02:00
parent 98dedfb6b8
commit 7f32380e0a
11 changed files with 58 additions and 20 deletions
+38
View File
@@ -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
+6 -6
View File
@@ -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 <token>`
**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"
+1 -1
View File
@@ -31,7 +31,7 @@ docker compose up --build
La API queda disponible en:
```text
http://localhost:8074
http://sinbad2.ujaen.es:8074
```
## Configuración
+2 -2
View File
@@ -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
LLM_TIMEOUT_SECONDS=180
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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)
+2 -2
View File
@@ -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"
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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
+4 -4
View File
@@ -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
+1 -1
View File
@@ -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";