diff --git a/src/app/api/employees/route.ts b/src/app/api/employees/route.ts new file mode 100644 index 0000000..20683fd --- /dev/null +++ b/src/app/api/employees/route.ts @@ -0,0 +1,50 @@ +import { NextResponse } from "next/server"; +import { auth } from "@/auth"; +import { createEmployee, listEmployees, validateCreateEmployeeInput } from "@/lib/employees"; + +// middleware.ts's config.matcher deliberately excludes /api from route +// protection (see its comment) — API routes verify the session themselves, +// here, rather than relying on middleware alone. Permission model is flat +// (CLAUDE.md): this only checks "logged in or not", no role/permission +// check. Mirrors src/app/api/requests/route.ts's pattern. +export async function POST(request: Request): Promise { + const session = await auth(); + if (!session) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + let body: unknown; + try { + body = await request.json(); + } catch { + return NextResponse.json({ error: "Request body must be valid JSON" }, { status: 400 }); + } + + if (typeof body !== "object" || body === null) { + return NextResponse.json({ error: "Request body must be a JSON object" }, { status: 400 }); + } + + const { name, department, managerId } = body as Record; + const validation = validateCreateEmployeeInput({ name, department, managerId }); + + if (!validation.ok) { + return NextResponse.json({ error: validation.error }, { status: 400 }); + } + + const created = await createEmployee(validation.value); + if (!created.ok) { + return NextResponse.json({ error: created.error }, { status: 400 }); + } + + return NextResponse.json(created.value, { status: 201 }); +} + +export async function GET(): Promise { + const session = await auth(); + if (!session) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const employees = await listEmployees(); + return NextResponse.json(employees, { status: 200 }); +}