feat: Añadir configuración de Nginx para el API de LMS y ajustar las rutas en el frontend de OpenCCB
This commit is contained in:
@@ -20,6 +20,7 @@ services:
|
|||||||
- html:/usr/share/nginx/html
|
- html:/usr/share/nginx/html
|
||||||
- ./nginx/proxy.conf:/etc/nginx/conf.d/proxy.conf:ro
|
- ./nginx/proxy.conf:/etc/nginx/conf.d/proxy.conf:ro
|
||||||
- ./nginx/studio.conf:/etc/nginx/vhost.d/studio.norteamericano.com:ro
|
- ./nginx/studio.conf:/etc/nginx/vhost.d/studio.norteamericano.com:ro
|
||||||
|
- ./nginx/learning.conf:/etc/nginx/vhost.d/learning.norteamericano.com:ro
|
||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
- openccb-network
|
- openccb-network
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Custom nginx configuration for OpenCCB Learning
|
||||||
|
# Keep the learning frontend on port 3003 and expose LMS API via same-origin /lms-api.
|
||||||
|
|
||||||
|
location /lms-api/ {
|
||||||
|
rewrite ^/lms-api/(.*)$ /$1 break;
|
||||||
|
proxy_pass http://openccb-experience:3002;
|
||||||
|
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;
|
||||||
|
}
|
||||||
+41
-2
@@ -15,6 +15,17 @@ location /cms-api/ {
|
|||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /lms-api/ {
|
||||||
|
rewrite ^/lms-api/(.*)$ /$1 break;
|
||||||
|
proxy_pass http://openccb-experience:3002;
|
||||||
|
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),
|
# 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/*)
|
# while the auth API endpoints (POST /auth/login, POST /auth/register, /auth/me, /auth/sso/*)
|
||||||
# must continue to go to the CMS backend (3001).
|
# must continue to go to the CMS backend (3001).
|
||||||
@@ -222,8 +233,28 @@ location /grading/ {
|
|||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location = /question-bank {
|
||||||
|
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 = /question-bank/ {
|
||||||
|
proxy_pass http://openccb-studio:3000/question-bank;
|
||||||
|
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 /question-bank/ {
|
location /question-bank/ {
|
||||||
proxy_pass http://openccb-studio:3001;
|
proxy_pass http://openccb-studio:3000;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
@@ -252,8 +283,16 @@ location = /admin/ {
|
|||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location = /admin/organizations {
|
||||||
|
return 302 /admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /admin/organizations/ {
|
||||||
|
return 302 /admin;
|
||||||
|
}
|
||||||
|
|
||||||
location /admin/ {
|
location /admin/ {
|
||||||
proxy_pass http://openccb-studio:3001;
|
proxy_pass http://openccb-studio:3000;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|||||||
@@ -10,7 +10,12 @@ const getApiBaseUrl = (defaultPort: string, envVar?: string) => {
|
|||||||
return `http://localhost:${defaultPort}`;
|
return `http://localhost:${defaultPort}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getLmsApiUrl = () => getApiBaseUrl("3002", process.env.NEXT_PUBLIC_LMS_API_URL);
|
export const getLmsApiUrl = () => {
|
||||||
|
if (typeof window !== 'undefined' && window.location.hostname === 'learning.norteamericano.com') {
|
||||||
|
return `${window.location.protocol}//learning.norteamericano.com/lms-api`;
|
||||||
|
}
|
||||||
|
return getApiBaseUrl("3002", process.env.NEXT_PUBLIC_LMS_API_URL);
|
||||||
|
};
|
||||||
export const getCmsApiUrl = () => getApiBaseUrl("3001", process.env.NEXT_PUBLIC_CMS_API_URL);
|
export const getCmsApiUrl = () => getApiBaseUrl("3001", process.env.NEXT_PUBLIC_CMS_API_URL);
|
||||||
|
|
||||||
export const getImageUrl = (path?: string) => {
|
export const getImageUrl = (path?: string) => {
|
||||||
|
|||||||
@@ -25,7 +25,12 @@ const nextConfig = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
async rewrites() {
|
async rewrites() {
|
||||||
return [
|
// Using `fallback` ensures Next.js pages (including dynamic routes like
|
||||||
|
// /courses/[id]) are matched BEFORE these proxy rewrites. Without this,
|
||||||
|
// `afterFiles` rewrites (the default for arrays) would intercept RSC
|
||||||
|
// prefetch requests to dynamic pages and proxy them to Rust instead.
|
||||||
|
return {
|
||||||
|
fallback: [
|
||||||
{
|
{
|
||||||
source: '/assets/:path*',
|
source: '/assets/:path*',
|
||||||
destination: 'http://localhost:3001/assets/:path*',
|
destination: 'http://localhost:3001/assets/:path*',
|
||||||
@@ -143,7 +148,8 @@ const nextConfig = {
|
|||||||
source: '/health',
|
source: '/health',
|
||||||
destination: 'http://localhost:3001/health',
|
destination: 'http://localhost:3001/health',
|
||||||
},
|
},
|
||||||
];
|
],
|
||||||
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default function AdminLayout({ children }: { children: React.ReactNode })
|
|||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{ icon: LayoutDashboard, label: "Dashboard", href: "/admin" },
|
{ icon: LayoutDashboard, label: "Dashboard", href: "/admin" },
|
||||||
{ icon: Building2, label: "Organizations", href: "/admin/organizations" },
|
{ icon: Building2, label: "Organizations", href: "/admin" },
|
||||||
{ icon: Users, label: "Users", href: "/admin/users" },
|
{ icon: Users, label: "Users", href: "/admin/users" },
|
||||||
{ icon: Mic, label: "Audio Evaluations", href: "/admin/audio-evaluations" },
|
{ icon: Mic, label: "Audio Evaluations", href: "/admin/audio-evaluations" },
|
||||||
{ icon: ClipboardList, label: "Audit Logs", href: "/admin/audit" },
|
{ icon: ClipboardList, label: "Audit Logs", href: "/admin/audit" },
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export default function AuthHeader() {
|
|||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
{user?.role === 'admin' && (
|
{user?.role === 'admin' && (
|
||||||
<>
|
<>
|
||||||
<Link href="/admin/organizations" className="text-xs font-bold uppercase tracking-widest text-gray-400 hover:text-white transition-colors flex items-center gap-2" title="Organizations">
|
<Link href="/admin" className="text-xs font-bold uppercase tracking-widest text-gray-400 hover:text-white transition-colors flex items-center gap-2" title="Organizations">
|
||||||
<Building2 size={16} /> <span className="hidden md:inline">Org</span>
|
<Building2 size={16} /> <span className="hidden md:inline">Org</span>
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="/admin/audit" className="text-xs font-bold uppercase tracking-widest text-gray-400 hover:text-white transition-colors flex items-center gap-2" title="Audit Logs">
|
<Link href="/admin/audit" className="text-xs font-bold uppercase tracking-widest text-gray-400 hover:text-white transition-colors flex items-center gap-2" title="Audit Logs">
|
||||||
|
|||||||
@@ -26,7 +26,14 @@ const getApiBaseUrl = (defaultPort: string, envVar?: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const API_BASE_URL = getApiBaseUrl("3001", process.env.NEXT_PUBLIC_CMS_API_URL);
|
export const API_BASE_URL = getApiBaseUrl("3001", process.env.NEXT_PUBLIC_CMS_API_URL);
|
||||||
export const LMS_API_BASE_URL = getApiBaseUrl("3002", process.env.NEXT_PUBLIC_LMS_API_URL);
|
const getLmsBaseUrl = (envVar?: string) => {
|
||||||
|
if (typeof window !== 'undefined' && window.location.hostname === 'studio.norteamericano.com') {
|
||||||
|
return `${window.location.protocol}//studio.norteamericano.com/lms-api`;
|
||||||
|
}
|
||||||
|
return getApiBaseUrl("3002", envVar);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const LMS_API_BASE_URL = getLmsBaseUrl(process.env.NEXT_PUBLIC_LMS_API_URL);
|
||||||
|
|
||||||
// Polyfill for crypto.randomUUID() for non-HTTPS contexts
|
// Polyfill for crypto.randomUUID() for non-HTTPS contexts
|
||||||
export function generateUUID(): string {
|
export function generateUUID(): string {
|
||||||
|
|||||||
Reference in New Issue
Block a user