feat: jwt cache, redis health, help-ticket admin, and write rate limits
Deploy / release (push) Skipped
Deploy / deploy (push) Successful in 1m33s

Cut Auth.js DB load with cached jwtVersion checks, surface Redis in /api/health and deploy warnings, add admin help-center ticket reply UI, rate-limit API tickets/reactions/referral claims, and revoke PATs on sign-out-everywhere.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-07-21 21:58:48 +02:00
1 parent 3bb96eb6f3
commit 968ca15c27
23 files changed
+1344 -205

No files matched your search

+136
View File
@@ -0,0 +1,136 @@
"use server";
import { revalidatePath } from "next/cache";
import { z } from "zod";
import { PERMS } from "@/lib/permissions";
import { prisma } from "@/lib/prisma";
import { adminAction } from "@/lib/safe-action";
import { ActionError, actionOk } from "@/lib/safe-action-shared";
import { logAudit } from "@/lib/services/audit";
const ticketIdField = z
.union([z.string(), z.number(), z.bigint()])
.transform((v) => BigInt(String(v)));
const replyHelpCenterTicketSchema = z.object({
ticketId: ticketIdField,
content: z.string().min(1).max(5000),
});
const helpCenterTicketIdSchema = z.object({
ticketId: ticketIdField,
});
function revalidateHelpCenterTicketPaths(ticketId: bigint) {
const id = String(ticketId);
revalidatePath("/admin/help-tickets");
revalidatePath(`/admin/help-tickets/${id}`);
revalidatePath("/help/tickets");
revalidatePath(`/help/tickets/${id}`);
}
export const replyHelpCenterTicket = adminAction(
{ permission: PERMS.TICKETS_EDIT, schema: replyHelpCenterTicketSchema },
async (ctx) => {
const ticketId = ctx.data.ticketId;
const ticket = await prisma.websiteHelpCenterTickets.findUnique({
where: { id: ticketId },
select: { id: true, open: true },
});
if (!ticket) throw new ActionError("Ticket not found");
const now = new Date();
const staffId = Number(ctx.session.user.id);
await prisma.$transaction([
prisma.websiteHelpCenterTicketReplies.create({
data: {
ticketId,
userId: staffId,
content: ctx.data.content.trim(),
createdAt: now,
updatedAt: now,
},
}),
prisma.websiteHelpCenterTickets.update({
where: { id: ticketId },
data: { updatedAt: now },
}),
]);
logAudit({
userId: staffId,
action: "help_center_ticket_reply",
target: "WebsiteHelpCenterTickets",
targetId: Number(ticketId),
});
revalidateHelpCenterTicketPaths(ticketId);
return actionOk();
},
);
export const closeHelpCenterTicket = adminAction(
{ permission: PERMS.TICKETS_EDIT, schema: helpCenterTicketIdSchema },
async (ctx) => {
const ticketId = ctx.data.ticketId;
const ticket = await prisma.websiteHelpCenterTickets.findUnique({
where: { id: ticketId },
select: { id: true, open: true },
});
if (!ticket) throw new ActionError("Ticket not found");
if (!ticket.open) throw new ActionError("Ticket is already closed");
const now = new Date();
await prisma.websiteHelpCenterTickets.update({
where: { id: ticketId },
data: { open: false, updatedAt: now },
});
logAudit({
userId: Number(ctx.session.user.id),
action: "help_center_ticket_close",
target: "WebsiteHelpCenterTickets",
targetId: Number(ticketId),
before: { open: true },
after: { open: false },
});
revalidateHelpCenterTicketPaths(ticketId);
return actionOk();
},
);
export const reopenHelpCenterTicket = adminAction(
{ permission: PERMS.TICKETS_EDIT, schema: helpCenterTicketIdSchema },
async (ctx) => {
const ticketId = ctx.data.ticketId;
const ticket = await prisma.websiteHelpCenterTickets.findUnique({
where: { id: ticketId },
select: { id: true, open: true },
});
if (!ticket) throw new ActionError("Ticket not found");
if (ticket.open) throw new ActionError("Ticket is already open");
const now = new Date();
await prisma.websiteHelpCenterTickets.update({
where: { id: ticketId },
data: { open: true, updatedAt: now },
});
logAudit({
userId: Number(ctx.session.user.id),
action: "help_center_ticket_reopen",
target: "WebsiteHelpCenterTickets",
targetId: Number(ticketId),
before: { open: false },
after: { open: true },
});
revalidateHelpCenterTicketPaths(ticketId);
return actionOk();
},
);