Skip to content

Bug: Achievement rewards destructively overwrite paid Stripe purchases in audit trail #405

@basantnema31

Description

@basantnema31

Description

In src/lib/achievements.ts, when a user unlocks an achievement that grants an item (
eward_type === "unlock_item"), the system inserts the reward into the purchases table using an upsert:

typescript await sb .from("purchases") .upsert(purchaseRows, { onConflict: "developer_id,item_id" });

The purchaseRows specify provider: "achievement" and �mount_cents: 0. If a user previously purchased this exact item legitimately through Stripe, they will already have a record in purchases with provider: "stripe", �mount_cents: >0, and their Stripe transaction ID.

Because of the onConflict: "developer_id,item_id" instruction, this upsert will destructively overwrite the original paid purchase record, permanently erasing the financial transaction audit trail for that item.

Recommendation

Change the upsert to an insert and catch the 23505 unique constraint violation, or check if the user already owns the item before attempting to insert the achievement reward.

Metadata

Metadata

Assignees

Labels

Gssoc 26Part of GirlScript Summer of Code 2026backendBackend/API relatedgood first issueGood for newcomersgssoc:approvedApproved GSSoC contributionlevel:intermediateIntermediate difficulty leveltype:bugSomething isn't working as expected

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions