diff --git a/backend/src/app/admin/layout.tsx b/backend/src/app/admin/layout.tsx
new file mode 100644
index 0000000..4697705
--- /dev/null
+++ b/backend/src/app/admin/layout.tsx
@@ -0,0 +1,63 @@
+'use client';
+import { usePathname, useRouter } from 'next/navigation';
+import { useEffect, useState } from 'react';
+
+const NAV = [
+ { href: '/admin', label: 'Dashboard' },
+ { href: '/admin/players', label: 'Players' },
+ { href: '/admin/battlepass', label: 'Battle Pass' },
+ { href: '/admin/matches', label: 'Matches' },
+ { href: '/admin/promocodes', label: 'Promo Codes' },
+ { href: '/admin/store', label: 'Store' },
+ { href: '/admin/contracts', label: 'Contracts' },
+ { href: '/admin/arsenal', label: 'Arsenal' },
+];
+
+export default function AdminLayout({ children }: { children: React.ReactNode }) {
+ const pathname = usePathname();
+ const router = useRouter();
+ const [authed, setAuthed] = useState(false);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ if (pathname === '/admin/login') {
+ setLoading(false);
+ return;
+ }
+ fetch('/api/admin/check')
+ .then(r => r.json())
+ .then(d => {
+ if (d.authenticated) setAuthed(true);
+ else router.push('/admin/login');
+ })
+ .catch(() => router.push('/admin/login'))
+ .finally(() => setLoading(false));
+ }, [pathname, router]);
+
+ if (loading) return
Loading...
;
+ if (pathname === '/admin/login') return <>{children}>;
+ if (!authed) return null;
+
+ return (
+
+
+
{children}
+
+ );
+}
diff --git a/backend/src/app/admin/login/page.tsx b/backend/src/app/admin/login/page.tsx
new file mode 100644
index 0000000..c3c3dbc
--- /dev/null
+++ b/backend/src/app/admin/login/page.tsx
@@ -0,0 +1,42 @@
+'use client';
+import { useState } from 'react';
+import { useRouter } from 'next/navigation';
+
+export default function LoginPage() {
+ const [password, setPassword] = useState('');
+ const [error, setError] = useState('');
+ const router = useRouter();
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setError('');
+ const res = await fetch('/api/admin/login', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ password }),
+ });
+ const data = await res.json();
+ if (data.success) router.push('/admin');
+ else setError(data.error || 'Login failed');
+ };
+
+ return (
+
+ );
+}
diff --git a/backend/src/app/api/admin/check/route.ts b/backend/src/app/api/admin/check/route.ts
new file mode 100644
index 0000000..2f38224
--- /dev/null
+++ b/backend/src/app/api/admin/check/route.ts
@@ -0,0 +1,8 @@
+import { NextResponse } from 'next/server';
+import { cookies } from 'next/headers';
+
+export async function GET() {
+ const store = cookies();
+ const authed = store.get('admin_session')?.value === 'authenticated';
+ return NextResponse.json({ authenticated: !!authed });
+}
diff --git a/backend/src/app/api/admin/login/route.ts b/backend/src/app/api/admin/login/route.ts
new file mode 100644
index 0000000..7429ce6
--- /dev/null
+++ b/backend/src/app/api/admin/login/route.ts
@@ -0,0 +1,14 @@
+import { NextRequest, NextResponse } from 'next/server';
+
+export async function POST(request: NextRequest) {
+ const { password } = await request.json();
+ const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || 'admin';
+ if (password !== ADMIN_PASSWORD) {
+ return NextResponse.json({ success: false, error: 'Invalid password' }, { status: 401 });
+ }
+ const response = NextResponse.json({ success: true });
+ response.cookies.set('admin_session', 'authenticated', {
+ httpOnly: true, secure: false, sameSite: 'lax', path: '/admin', maxAge: 86400,
+ });
+ return response;
+}
diff --git a/backend/src/app/api/admin/logout/route.ts b/backend/src/app/api/admin/logout/route.ts
new file mode 100644
index 0000000..bf49cb2
--- /dev/null
+++ b/backend/src/app/api/admin/logout/route.ts
@@ -0,0 +1,7 @@
+import { NextResponse } from 'next/server';
+
+export async function GET() {
+ const response = NextResponse.json({ success: true });
+ response.cookies.delete('admin_session');
+ return response;
+}