Files
alpenwerk-hr/proxy.ts
Maximilian Stubhan ef9852b09c Phase 1: project foundation for Alpenwerk HR
Scaffolds the Next.js 16 / TypeScript strict / Tailwind v3 app per
NEXTJS_REBUILD_SUPERPROMPT.md, and implements the Foundation slice from
the Phase 1 plan:

- Corrected Supabase schema (supabase/schema.sql): org units, employees,
  history, positions, hire drafts, saved reports, audit log, reorg
  scenarios, role-based profiles, salary-masking view, RLS policies,
  auto-derivation triggers, position-number generator.
- Seed script (supabase/seed.ts): ~800 realistic Austrian employees across
  9 divisions / 16 departments / 35 teams, history, 8 open positions, and
  hr_admin/manager test accounts.
- Supabase clients (lib/supabase/*), design tokens (tailwind.config.ts),
  format/color helpers (lib/format.ts, lib/colors.ts).
- Shared UI kit (components/ui): Avatar, StatusChip, Toast, Modal,
  SlideOver, SegmentedControl, Lookup.
- Auth (login page, Server Actions) and proxy.ts (Next 16's replacement
  for middleware) guarding the authenticated route group.
- Shell (Sidebar, Topbar, NewHireButton stub) and the Dashboard page,
  reading live data via employees_directory.

Employees list/detail, hire wizard, action panels, org chart, positions,
reports, and audit log are deferred to later phases per the plan.
2026-07-13 21:44:28 +02:00

52 lines
1.5 KiB
TypeScript

import { createServerClient } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";
// Next.js 16 renamed Middleware to Proxy (same mechanism, new filename/export).
// This performs the optimistic auth check: redirect unauthenticated users to
// /login, and signed-in users away from /login. Real authorization (hr_admin
// vs manager) is enforced server-side via RLS, not here.
export async function proxy(request: NextRequest) {
let response = NextResponse.next({ request });
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll();
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value));
response = NextResponse.next({ request });
cookiesToSet.forEach(({ name, value, options }) => response.cookies.set(name, value, options));
},
},
}
);
const {
data: { user },
} = await supabase.auth.getUser();
const isLoginRoute = request.nextUrl.pathname.startsWith("/login");
if (!user && !isLoginRoute) {
const url = request.nextUrl.clone();
url.pathname = "/login";
return NextResponse.redirect(url);
}
if (user && isLoginRoute) {
const url = request.nextUrl.clone();
url.pathname = "/";
return NextResponse.redirect(url);
}
return response;
}
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};