fix: make gamification calls non-blocking so errors don't fail core mutations
Some checks failed
Build and Push Backend Image / build (push) Successful in 43s
Build and Push Frontend Image / build (push) Has been cancelled

awardPoints/checkAchievements were awaited inline, so any gamification error
(DB constraint, missing table, etc.) would propagate as INTERNAL_SERVER_ERROR
on comment creation, recording plays, etc. Now they run fire-and-forget with
error logging, so the core action always succeeds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-07 11:16:27 +01:00
parent dcf2fbd3d4
commit 9ba848372a
2 changed files with 24 additions and 23 deletions

View File

@@ -59,9 +59,10 @@ builder.mutationField("createCommentForVideo", (t) =>
}) })
.returning(); .returning();
// Gamification // Gamification (non-blocking)
await awardPoints(ctx.db, ctx.currentUser.id, "COMMENT_CREATE"); awardPoints(ctx.db, ctx.currentUser.id, "COMMENT_CREATE")
await checkAchievements(ctx.db, ctx.currentUser.id, "social"); .then(() => checkAchievements(ctx.db, ctx.currentUser!.id, "social"))
.catch((e) => console.error("Gamification error on comment:", e));
const user = await ctx.db const user = await ctx.db
.select({ .select({

View File

@@ -122,10 +122,11 @@ builder.mutationField("createRecording", (t) =>
const recording = newRecording[0]; const recording = newRecording[0];
// Gamification: award points if published // Gamification (non-blocking)
if (recording.status === "published") { if (recording.status === "published") {
await awardPoints(ctx.db, ctx.currentUser.id, "RECORDING_CREATE", recording.id); awardPoints(ctx.db, ctx.currentUser.id, "RECORDING_CREATE", recording.id)
await checkAchievements(ctx.db, ctx.currentUser.id, "recordings"); .then(() => checkAchievements(ctx.db, ctx.currentUser!.id, "recordings"))
.catch((e) => console.error("Gamification error on recording create:", e));
} }
return recording; return recording;
@@ -179,14 +180,15 @@ builder.mutationField("updateRecording", (t) =>
const recording = updated[0]; const recording = updated[0];
// Gamification: if newly published // Gamification (non-blocking)
if (args.status === "published" && existing[0].status !== "published") { if (args.status === "published" && existing[0].status !== "published") {
await awardPoints(ctx.db, ctx.currentUser.id, "RECORDING_CREATE", recording.id); awardPoints(ctx.db, ctx.currentUser.id, "RECORDING_CREATE", recording.id)
await checkAchievements(ctx.db, ctx.currentUser.id, "recordings"); .then(() => checkAchievements(ctx.db, ctx.currentUser!.id, "recordings"))
} .catch((e) => console.error("Gamification error on recording publish:", e));
if (args.status === "published" && recording.featured && !existing[0].featured) { } else if (args.status === "published" && recording.featured && !existing[0].featured) {
await awardPoints(ctx.db, ctx.currentUser.id, "RECORDING_FEATURED", recording.id); awardPoints(ctx.db, ctx.currentUser.id, "RECORDING_FEATURED", recording.id)
await checkAchievements(ctx.db, ctx.currentUser.id, "recordings"); .then(() => checkAchievements(ctx.db, ctx.currentUser!.id, "recordings"))
.catch((e) => console.error("Gamification error on recording feature:", e));
} }
return recording; return recording;
@@ -288,10 +290,11 @@ builder.mutationField("recordRecordingPlay", (t) =>
}) })
.returning({ id: recording_plays.id }); .returning({ id: recording_plays.id });
// Gamification // Gamification (non-blocking)
if (ctx.currentUser && recording[0].user_id !== ctx.currentUser.id) { if (ctx.currentUser && recording[0].user_id !== ctx.currentUser.id) {
await awardPoints(ctx.db, ctx.currentUser.id, "RECORDING_PLAY", args.recordingId); awardPoints(ctx.db, ctx.currentUser.id, "RECORDING_PLAY", args.recordingId)
await checkAchievements(ctx.db, ctx.currentUser.id, "playback"); .then(() => checkAchievements(ctx.db, ctx.currentUser!.id, "playback"))
.catch((e) => console.error("Gamification error on recording play:", e));
} }
return { success: true, play_id: play[0].id }; return { success: true, play_id: play[0].id };
@@ -326,14 +329,11 @@ builder.mutationField("updateRecordingPlay", (t) =>
}) })
.where(eq(recording_plays.id, args.playId)); .where(eq(recording_plays.id, args.playId));
// Gamification (non-blocking)
if (args.completed && !wasCompleted && ctx.currentUser) { if (args.completed && !wasCompleted && ctx.currentUser) {
await awardPoints( awardPoints(ctx.db, ctx.currentUser.id, "RECORDING_COMPLETE", existing[0].recording_id)
ctx.db, .then(() => checkAchievements(ctx.db, ctx.currentUser!.id, "playback"))
ctx.currentUser.id, .catch((e) => console.error("Gamification error on recording complete:", e));
"RECORDING_COMPLETE",
existing[0].recording_id,
);
await checkAchievements(ctx.db, ctx.currentUser.id, "playback");
} }
return true; return true;