feat: shop buy, forum replies, tickets, messages, sessions, and UX hardening
Deploy / release (push) Skipped
Deploy / deploy (push) Failing after 4m23s

Complete remaining product gaps: credit-based shop purchases, guild thread replies, help ticket detail/reply/close, offline message compose, sign-out-everywhere via JWT version, ads delete confirm, soft-fail feedback, rate limits, loading states, and single auth() in site layout.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-07-21 21:21:02 +02:00
1 parent ed7db6e048
commit 803e8f36c1
47 files changed
+2793 -358

No files matched your search

+18 -3
View File
@@ -17,7 +17,12 @@ import {
// ── User actions (authenticated, no admin perms needed) ──────────────
export const createTicket = authAction(
{ schema: createTicketSchema },
{
schema: createTicketSchema,
rateLimitKey: "ticket-create",
rateLimitMax: 5,
rateLimitWindowMs: 60_000,
},
async (ctx) => {
const ticket = await prisma.websiteTicket.create({
data: {
@@ -49,7 +54,12 @@ export const createTicket = authAction(
);
export const userReplyTicket = authAction(
{ schema: replyTicketSchema },
{
schema: replyTicketSchema,
rateLimitKey: "ticket-reply",
rateLimitMax: 10,
rateLimitWindowMs: 60_000,
},
async (ctx) => {
const ticket = await prisma.websiteTicket.findUnique({
where: { id: ctx.data.ticketId },
@@ -82,7 +92,12 @@ export const userReplyTicket = authAction(
);
export const closeTicketByUser = authAction(
{ schema: replyTicketSchema.pick({ ticketId: true }) },
{
schema: replyTicketSchema.pick({ ticketId: true }),
rateLimitKey: "ticket-close",
rateLimitMax: 10,
rateLimitWindowMs: 60_000,
},
async (ctx) => {
const ticket = await prisma.websiteTicket.findUnique({
where: { id: ctx.data.ticketId },