admin roadmap csv export, adminactionlog, global search

This commit is contained in:
2026-05-18 20:09:22 +07:00
parent 244a6da9bb
commit ea63f56e97
25 changed files with 1330 additions and 158 deletions
@@ -0,0 +1,74 @@
import { NextRequest, NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { isAdminEmail } from "@/lib/admin";
import { organizerRepo } from "@/server/repositories/organizer.repo";
import { buildCsv, csvDateJakarta, csvResponse } from "@/lib/csv";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
const VALID_STATUS = new Set(["PENDING", "APPROVED", "REJECTED"]);
function parseDate(value: string | null): Date | undefined {
if (!value) return undefined;
const d = new Date(value);
return Number.isNaN(d.getTime()) ? undefined : d;
}
export async function GET(req: NextRequest) {
const session = await getServerSession(authOptions);
if (!session?.user || !isAdminEmail(session.user.email)) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const params = req.nextUrl.searchParams;
const statusParam = params.get("status");
const status =
statusParam && VALID_STATUS.has(statusParam)
? (statusParam as "PENDING" | "APPROVED" | "REJECTED")
: undefined;
const rows = await organizerRepo.listByStatus(status, {
dateFrom: parseDate(params.get("dateFrom")),
dateTo: parseDate(params.get("dateTo")),
reviewerEmail: params.get("reviewer") || undefined,
});
// SENGAJA tidak ekspor: NIK plaintext (encrypted), ktpImageKey, livenessKey,
// bankAccountNumber. Export ini hanya untuk metadata audit — KYC sensitive
// info tetap di DB & cuma diakses lewat admin UI dengan auth gate.
const csv = buildCsv(
[
"Verification ID",
"Status",
"Nama (KTP)",
"User nama",
"User email",
"Bank nama",
"Bank atas nama",
"Dibuat",
"Reviewed at",
"Verified at",
"Rejection reason",
"Reviewer email",
],
rows.map((v) => [
v.id,
v.status,
v.fullName,
v.user.name,
v.user.email,
v.bankName,
v.bankAccountName,
csvDateJakarta(v.createdAt),
csvDateJakarta(v.reviewedAt),
csvDateJakarta(v.verifiedAt),
v.rejectionReason ?? "",
v.reviewedBy?.email ?? "",
])
);
const today = new Date().toISOString().slice(0, 10);
return csvResponse(`verifications-${status ?? "all"}-${today}.csv`, csv);
}