multi zone systum

This commit is contained in:
Om Lanke
2025-09-23 19:51:22 +05:30
parent afedb8df6c
commit 6d7efc5b8a
6 changed files with 74 additions and 21 deletions

View File

@@ -74,7 +74,7 @@ export default function MainLayout({ children }: { children: React.ReactNode })
<div className="flex items-center gap-3 group"> <div className="flex items-center gap-3 group">
<div className="relative"> <div className="relative">
<img <img
src="/favicon.ico" src="favicon.ico"
alt="Logo" alt="Logo"
className="w-10 h-10 rounded-xl shadow-lg group-hover:shadow-xl transition-all duration-300 group-hover:scale-110" className="w-10 h-10 rounded-xl shadow-lg group-hover:shadow-xl transition-all duration-300 group-hover:scale-110"
/> />

View File

@@ -18,7 +18,7 @@ export default async function Page() {
<div className="relative z-10 backdrop-blur-md bg-white/70 rounded-2xl shadow-2xl p-10 flex flex-col items-center gap-8 border border-white/30 max-w-sm w-full transition-all duration-300 hover:shadow-[0_0_32px_4px_rgba(239,68,68,0.25)] hover:border-red-400/60"> <div className="relative z-10 backdrop-blur-md bg-white/70 rounded-2xl shadow-2xl p-10 flex flex-col items-center gap-8 border border-white/30 max-w-sm w-full transition-all duration-300 hover:shadow-[0_0_32px_4px_rgba(239,68,68,0.25)] hover:border-red-400/60">
<div className="flex flex-col items-center gap-2"> <div className="flex flex-col items-center gap-2">
{/* Animated logo */} {/* Animated logo */}
<img src="/favicon.ico" alt="Logo" className="w-14 h-14 mb-2 drop-shadow-lg animate-bounce-slow" /> <img src="favicon.ico" alt="Logo" className="w-14 h-14 mb-2 drop-shadow-lg animate-bounce-slow" />
<h1 className="text-2xl font-bold text-gray-800 tracking-tight">Placement Portal Admin</h1> <h1 className="text-2xl font-bold text-gray-800 tracking-tight">Placement Portal Admin</h1>
<p className="text-gray-500 text-sm text-center">Sign in to manage placements and students</p> <p className="text-gray-500 text-sm text-center">Sign in to manage placements and students</p>
<p className="text-xs text-red-500 font-semibold italic mt-1 animate-fade-in">Empower your journey. Shape the future.</p> <p className="text-xs text-red-500 font-semibold italic mt-1 animate-fade-in">Empower your journey. Shape the future.</p>

View File

@@ -1,21 +1,42 @@
// apps/admin/middleware.ts
import { auth } from '@/auth'; import { auth } from '@/auth';
import { NextResponse, NextRequest } from 'next/server'; import { NextResponse, NextRequest } from 'next/server';
import path from 'path';
export default auth((req: NextRequest) => { export default auth((req: NextRequest) => {
if (!req.auth) { const { pathname } = req.nextUrl;
return NextResponse.redirect(new URL('/login', req.url)); // console.log('admin middleware requested path:', pathname);
}
if (req.auth.user?.role === 'ADMIN') { const bypassRegex = /^\/(api|_next\/static|_next\/image|favicon\.ico|login|signup|admin-static).*$/;
// console.log("Bypass regex test:", bypassRegex.test(pathname));
if (bypassRegex.test(pathname)) {
// console.log("Bypassing admin middleware for path:", pathname);
return NextResponse.next(); return NextResponse.next();
} }
// Otherwise, redirect to the student app. if (!req.auth) {
const studentUrl = process.env.STUDENT_URL ?? 'http://localhost:3000'; // admin login page should be under /admin/login so we stay on the same origin
return NextResponse.redirect(new URL('/admin/login', req.url));
}
// console.log("ROLE: ", req.auth.user?.role)
if (req.auth.user?.role !== 'ADMIN') {
// Non-admins must go back to the student app at /
return NextResponse.redirect(new URL('/', req.url));
}
return NextResponse.redirect(new URL(studentUrl, req.url)); return NextResponse.next();
}); });
export const config = { // export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico|login).*)'], // // only run admin middleware for /admin and its subpaths
}; // matcher: ['/admin/:path*'],
// };
// export const config = {
// matcher: [
// // run for everything except api, _next static/image, favicon, login, signup
// '/((?!api|_next/static|_next/image|favicon.ico|login|signup).*)',
// ],
// };

View File

@@ -7,6 +7,8 @@ const nextConfig = {
transpilePackages: ['@workspace/ui', '@workspace/db'], transpilePackages: ['@workspace/ui', '@workspace/db'],
output: 'standalone', output: 'standalone',
outputFileTracingRoot: path.join(__dirname, '../../'), outputFileTracingRoot: path.join(__dirname, '../../'),
assetPrefix: '/admin-static',
basePath: '/admin',
}; };
export default nextConfig; export default nextConfig;

View File

@@ -1,25 +1,39 @@
// apps/student/middleware.ts
import { auth } from '@/auth'; import { auth } from '@/auth';
import { NextResponse, NextRequest } from 'next/server'; import { NextResponse, NextRequest } from 'next/server';
export default auth((req: NextRequest) => { export default auth((req: NextRequest) => {
const { pathname } = req.nextUrl;
// console.log('student middleware requested path:', pathname);
// If not authenticated -> login (student side)
if (!req.auth) { if (!req.auth) {
return NextResponse.redirect(new URL('/login', req.url)); return NextResponse.redirect(new URL('/login', req.url));
} }
if (req.auth.user?.role === 'USER') { const role = req.auth.user?.role;
if (!req.auth.user?.completedProfile && !req.nextUrl.pathname.startsWith('/signup')) {
const signupUrl = process.env.STUDENT_PROFILE_URL ?? 'http://localhost:3000/signup';
return NextResponse.redirect(new URL(signupUrl, req.url));
}
// If user is an ADMIN, prefer sending them to the admin area on the same origin
if (role === 'ADMIN') {
return NextResponse.redirect(new URL('/admin', req.url));
}
// Normal student flow
if (role === 'USER') {
if (!req.auth.user?.completedProfile && !pathname.startsWith('/signup')) {
return NextResponse.redirect(new URL('/signup', req.url));
}
return NextResponse.next(); return NextResponse.next();
} }
const adminUrl = process.env.ADMIN_URL ?? 'http://localhost:3001'; // Fallback
return NextResponse.redirect(new URL('/login', req.url));
return NextResponse.redirect(new URL(adminUrl, req.url));
}); });
// IMPORTANT: exclude /admin from this matcher so student middleware never runs for /admin
export const config = { export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico|login).*)'], matcher: [
// run for everything except api, _next static/image, favicon, login, signup, or admin
'/((?!api|_next/static|_next/image|favicon.ico|login|signup|admin).*)',
],
}; };

View File

@@ -7,6 +7,22 @@ const nextConfig = {
transpilePackages: ['@workspace/ui', '@workspace/db'], transpilePackages: ['@workspace/ui', '@workspace/db'],
output: 'standalone', output: 'standalone',
outputFileTracingRoot: path.join(__dirname, '../../'), outputFileTracingRoot: path.join(__dirname, '../../'),
async rewrites() {
return [
{
source: '/admin',
destination: `${process.env.ADMIN_DOMAIN}/admin`,
},
{
source: '/admin/:path+',
destination: `${process.env.ADMIN_DOMAIN}/admin/:path+`,
},
{
source: '/admin-static/:path+',
destination: `${process.env.ADMIN_DOMAIN}/admin-static/:path+`,
}
];
}
}; };
export default nextConfig; export default nextConfig;