diff --git a/nginx/studio.conf b/nginx/studio.conf index b0a8d50..d5f4431 100644 --- a/nginx/studio.conf +++ b/nginx/studio.conf @@ -2,7 +2,83 @@ # This overrides the default location block to route API requests correctly # API routes that need to go to port 3001 +# Prefer the explicit `/cms-api/*` prefix for frontend fetches. This avoids collisions +# with Next.js pages like `/courses` and `/admin` that share the same host. +location /cms-api/ { + rewrite ^/cms-api/(.*)$ /$1 break; + proxy_pass http://openccb-studio:3001; + 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 $http_x_forwarded_proto; + proxy_set_header Connection ""; + proxy_http_version 1.1; +} + +# Auth pages like GET /auth/login and GET /auth/register must be served by Next.js (3000), +# while the auth API endpoints (POST /auth/login, POST /auth/register, /auth/me, /auth/sso/*) +# must continue to go to the CMS backend (3001). +location @studio_frontend_auth { + proxy_pass http://openccb-studio:3000; + 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 $http_x_forwarded_proto; + proxy_set_header Connection ""; + proxy_http_version 1.1; +} + location = /auth/login { + error_page 418 = @studio_frontend_auth; + if ($request_method != POST) { + return 418; + } + + proxy_pass http://openccb-studio:3001; + 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 $http_x_forwarded_proto; + proxy_set_header Connection ""; + proxy_http_version 1.1; +} + +location = /auth/register { + error_page 418 = @studio_frontend_auth; + if ($request_method != POST) { + return 418; + } + + proxy_pass http://openccb-studio:3001; + 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 $http_x_forwarded_proto; + proxy_set_header Connection ""; + proxy_http_version 1.1; +} + +location = /auth/callback { + proxy_pass http://openccb-studio:3000; + 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 $http_x_forwarded_proto; + proxy_set_header Connection ""; + proxy_http_version 1.1; +} + +location = /auth/me { + proxy_pass http://openccb-studio:3001; + 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 $http_x_forwarded_proto; + proxy_set_header Connection ""; + proxy_http_version 1.1; +} + +location /auth/sso/ { proxy_pass http://openccb-studio:3001; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -52,7 +128,21 @@ location = /branding { proxy_http_version 1.1; } -location /courses/ { +# `GET /courses` is ambiguous: the dashboard API uses it for JSON, but the Studio frontend +# also uses `/courses` as a page route and for RSC/prefetch requests. +# Route page/navigation-style requests to Next.js (3000), and keep API fetches on the CMS backend (3001). +location = /courses { + error_page 418 = @studio_frontend_auth; + if ($http_accept ~* "text/html|text/x-component") { + return 418; + } + if ($http_rsc != "") { + return 418; + } + if ($http_next_router_state_tree != "") { + return 418; + } + proxy_pass http://openccb-studio:3001; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -62,6 +152,26 @@ location /courses/ { proxy_http_version 1.1; } +location = /courses/ { + proxy_pass http://openccb-studio:3000; + 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 $http_x_forwarded_proto; + proxy_set_header Connection ""; + proxy_http_version 1.1; +} + +location /courses/ { + proxy_pass http://openccb-studio:3000; + 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 $http_x_forwarded_proto; + proxy_set_header Connection ""; + proxy_http_version 1.1; +} + location /modules/ { proxy_pass http://openccb-studio:3001; proxy_set_header Host $host; @@ -122,6 +232,26 @@ location /question-bank/ { proxy_http_version 1.1; } +location = /admin { + proxy_pass http://openccb-studio:3000; + 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 $http_x_forwarded_proto; + proxy_set_header Connection ""; + proxy_http_version 1.1; +} + +location = /admin/ { + proxy_pass http://openccb-studio:3000; + 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 $http_x_forwarded_proto; + proxy_set_header Connection ""; + proxy_http_version 1.1; +} + location /admin/ { proxy_pass http://openccb-studio:3001; proxy_set_header Host $host; diff --git a/web/experience/src/lib/api.ts b/web/experience/src/lib/api.ts index 0a12a95..b31070e 100644 --- a/web/experience/src/lib/api.ts +++ b/web/experience/src/lib/api.ts @@ -1,10 +1,13 @@ const getApiBaseUrl = (defaultPort: string, envVar?: string) => { + if (envVar && envVar.trim() !== '') { + return envVar; + } if (typeof window !== 'undefined') { const hostname = window.location.hostname; const protocol = window.location.protocol; return `${protocol}//${hostname}:${defaultPort}`; } - return envVar || `http://localhost:${defaultPort}`; + return `http://localhost:${defaultPort}`; }; export const getLmsApiUrl = () => getApiBaseUrl("3002", process.env.NEXT_PUBLIC_LMS_API_URL); diff --git a/web/studio/src/lib/api.ts b/web/studio/src/lib/api.ts index c837803..3f67970 100644 --- a/web/studio/src/lib/api.ts +++ b/web/studio/src/lib/api.ts @@ -1,27 +1,28 @@ const getApiBaseUrl = (defaultPort: string, envVar?: string) => { - // Producción - dominios específicos + // Prefer explicit environment configuration when available. This allows production + // deployments to use a dedicated API prefix like `/cms-api` and avoids collisions + // between Next.js pages (e.g. `/courses`) and backend endpoints with the same path. + if (envVar && envVar.trim() !== '') { + return envVar; + } + if (typeof window !== 'undefined') { const hostname = window.location.hostname; const protocol = window.location.protocol; - - // Forzar URLs correctas para producción (sin puerto) + + // Producción - dominios específicos (fallback sin prefijo) if (hostname === 'studio.norteamericano.com') { return `${protocol}//studio.norteamericano.com`; } if (hostname === 'learning.norteamericano.com') { return `${protocol}//learning.norteamericano.com`; } - - // Usar variable de entorno si está definida - if (envVar && envVar.trim() !== '') { - return envVar; - } - + // Desarrollo local return `${protocol}//${hostname}:${defaultPort}`; } - - return envVar || `http://localhost:${defaultPort}`; + + return `http://localhost:${defaultPort}`; }; export const API_BASE_URL = getApiBaseUrl("3001", process.env.NEXT_PUBLIC_CMS_API_URL);