feat: add invite system with payment-gated reward and abuse guards - #36
Open
abhishakenp wants to merge 1 commit into
Open
feat: add invite system with payment-gated reward and abuse guards#36abhishakenp wants to merge 1 commit into
abhishakenp wants to merge 1 commit into
Conversation
Adds a referral invite system on top of LinkForty's existing deferred deep linking infrastructure. The system is designed for invite-based growth where the reward is gated on the invitee making a payment (not just signing up), making fake-account farming economically irrational. Three guards enforce the abuse-prevention policy at the payment event: 1. Self-invite: inviterId === inviteeUserId → reject (deterministic) 2. Already-on-platform: inviteeCreatedAt < invite.createdAt → reject 3. Single consumption: WHERE status='pending' in UPDATE prevents double-reward even under concurrent requests (DB-level atomicity) New endpoints: - POST /api/invites — create a pending invite - POST /api/invites/:id/consume — consume on payment (runs all guards) - POST /api/invites/:id/expire — manually expire (no reward) - GET /api/invites/:inviterId — list invites for an inviter - GET /api/invites/id/:id — get single invite On successful consumption, an `invite_consumed_event` webhook fires to the inviter's registered webhook endpoints, carrying the payment amount, reward amount, and both user identities. 37 new tests (22 unit + 15 integration) cover every guard, guard ordering, race conditions, boundary cases, and the full create→consume→verify lifecycle. Full suite: 176 tests passing. Deductive proof of correctness in docs/invite-system-proof.md. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a referral invite system on top of LinkForty's existing deferred deep linking infrastructure. Designed for invite-based growth where the reward is gated on the invitee making a payment (not just signing up), making fake-account farming economically irrational.
Three abuse-prevention guards (at the payment event)
inviterId === inviteeUserId→ reject (deterministic, unbeatable)inviteeCreatedAt < invite.createdAt→ reject (invite is for NEW users only)WHERE status = 'pending'in the UPDATE prevents double-reward even under concurrent requests (DB-level atomicity)New endpoints
POST/api/invitesPOST/api/invites/:id/consumePOST/api/invites/:id/expireGET/api/invites/:inviterIdGET/api/invites/id/:idOn successful consumption, an
invite_consumed_eventwebhook fires to the inviter's registered webhook endpoints.Schema
New
invitestable withstatus(pending→consumed|expired),inviter_id,invitee_user_id,payment_amount,reward_issued, andmetadataJSONB. Migration is idempotent (CREATE TABLE IF NOT EXISTS+CREATE INDEX IF NOT EXISTS), consistent with the existing migration pattern indatabase.ts.Design decisions (per user requirements)
paymentAmount > 0is provided. Signup alone triggers nothing.consumedand all future attempts are rejected. No separate device-dedup logic needed.Deductive proof
docs/invite-system-proof.mdcontains a formal proof of correctness for each invariant, with code citations and test evidence mapping.Test plan
src/lib/invite.test.ts— every guard function, boundary cases, guard ordering, race conditionssrc/routes/invites.test.ts— full HTTP flow, webhook firing, lifecycletsc --noEmittypecheck cleanGenerated with Devin