Problem
The toggleStarMarked server action uses db.starMark.create when starring a playground. If the user clicks the star button twice rapidly, the second create call hits a unique constraint violation (@@unique([userId, playgroundId])) because the first click already inserted the row. The error is caught and returned as { success: false }, but the UI receives no meaningful feedback — the user just sees the toggle not work on the second click.
Location
modules/playground/actions/index.ts (lines 22-28)
modules/dashboard/actions/index.ts (lines 22-28) — identical duplicate
Expected behavior
Starring should be idempotent: clicking star twice should not fail or produce a constraint error. Use upsert so the second click is a no-op rather than a failed create.
Actual behavior
db.starMark.create throws a PrismaClientKnownRequestError with code P2002 (unique constraint violation) on the second click. The catch block logs it and returns { success: false }, giving the user no indication of what went wrong. Additionally, the delete path has the inverse problem — deleting a non-existent row throws P2025 (record not found), which is also swallowed.
Suggested fix
Replace the create/delete branch with upsert for starring and deleteMany for unstarring:
if (isChecked) {
await db.starMark.upsert({
where: { userId_playgroundId: { userId, playgroundId } },
update: { isMarked: true },
create: { userId, playgroundId, isMarked: true },
});
} else {
await db.starMark.deleteMany({
where: { userId, playgroundId },
});
}
Problem
The
toggleStarMarkedserver action usesdb.starMark.createwhen starring a playground. If the user clicks the star button twice rapidly, the secondcreatecall hits a unique constraint violation (@@unique([userId, playgroundId])) because the first click already inserted the row. The error is caught and returned as{ success: false }, but the UI receives no meaningful feedback — the user just sees the toggle not work on the second click.Location
modules/playground/actions/index.ts(lines 22-28)modules/dashboard/actions/index.ts(lines 22-28) — identical duplicateExpected behavior
Starring should be idempotent: clicking star twice should not fail or produce a constraint error. Use
upsertso the second click is a no-op rather than a failedcreate.Actual behavior
db.starMark.createthrows aPrismaClientKnownRequestErrorwith codeP2002(unique constraint violation) on the second click. The catch block logs it and returns{ success: false }, giving the user no indication of what went wrong. Additionally, thedeletepath has the inverse problem — deleting a non-existent row throwsP2025(record not found), which is also swallowed.Suggested fix
Replace the
create/deletebranch withupsertfor starring anddeleteManyfor unstarring: