Files
Epicure/apps/web/app/api/v1/admin/users/[id]/route.ts
T
Arnaud cba5d9c3ac feat(admin): admin panel with overview, users, audit logs, storage, AI config, settings
Sticky sidebar with back-to-app link. Overview: user counts, recipe photos, AI calls/month.
User management with role/tier editing. Audit log (all admin actions).
Storage page with photo breakdown by tier. AI config showing DB vs .env key source.
Site settings page to override .env values at runtime (encrypted in DB).
2026-07-01 08:10:59 +02:00

57 lines
1.8 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { requireAdmin } from "@/lib/api-auth";
import { db, users, auditLogs, eq } from "@epicure/db";
import { randomUUID } from "crypto";
interface RouteContext {
params: Promise<{ id: string }>;
}
export async function PATCH(req: NextRequest, { params }: RouteContext) {
const { session, response } = await requireAdmin();
if (response) return response;
const { id } = await params;
const body = await req.json() as { role?: string; tier?: string };
const { role, tier } = body;
const validRoles = ["user", "moderator", "admin"] as const;
const validTiers = ["free", "pro"] as const;
if (role !== undefined && !validRoles.includes(role as typeof validRoles[number])) {
return NextResponse.json({ error: "Invalid role" }, { status: 400 });
}
if (tier !== undefined && !validTiers.includes(tier as typeof validTiers[number])) {
return NextResponse.json({ error: "Invalid tier" }, { status: 400 });
}
const updateData: Partial<{ role: "user" | "moderator" | "admin"; tier: "free" | "pro"; updatedAt: Date }> = {
updatedAt: new Date(),
};
if (role) updateData.role = role as "user" | "moderator" | "admin";
if (tier) updateData.tier = tier as "free" | "pro";
const [updated] = await db
.update(users)
.set(updateData)
.where(eq(users.id, id))
.returning({ id: users.id, role: users.role, tier: users.tier });
if (!updated) {
return NextResponse.json({ error: "User not found" }, { status: 404 });
}
// Write audit log
await db.insert(auditLogs).values({
id: randomUUID(),
userId: session!.user.id,
action: "admin.user.update",
targetType: "user",
targetId: id,
metadata: JSON.stringify({ role, tier }),
createdAt: new Date(),
});
return NextResponse.json({ user: updated });
}