fix(referrals): normalize invite email dedupe#280
Conversation
Greptile SummaryThis PR fixes invite email deduplication by normalizing (trim + lowercase) the raw email list into a
Confidence Score: 5/5The change is narrowly scoped to the normalization pipeline and carries a direct regression test; no data-loss or auth paths are touched. All downstream operations (rate-limit count, DB duplicate query, insert, email send) now use the same canonical address produced by a single trim().toLowerCase() + Set pass. The logic is straightforward and the new test exercises the exact failure mode the fix addresses. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[POST /api/referrals] --> B[Auth check]
B --> C[Parse emails array]
C --> D{Validate: array,\nnon-empty, ≤20}
D -- invalid --> E[400]
D -- ok --> F["Normalize once:\ntrim + lowercase → Set → filter regex\n= validEmails"]
F --> G{validEmails empty?}
G -- yes --> H[400 No valid emails]
G -- no --> I[Rate-limit check\nhourly / daily\nusing validEmails.length]
I -- exceeded --> J[429]
I -- ok --> K["DB: .in(referred_email, validEmails)\n= existingInvites"]
K --> L["newValidEmails =\nvalidEmails - alreadyInvited"]
L --> M{newValidEmails empty?}
M -- yes --> N[400 Already invited]
M -- no --> O[Insert referralRows]
O --> P[Send emails]
P --> Q[200 response]
Reviews (2): Last reviewed commit: "chore(referrals): remove redundant invit..." | Re-trigger Greptile |
|
Follow-up pushed in 1a6a082: removed the redundant insert-row normalization that Greptile flagged. newValidEmails is already the canonical trimmed/lowercased source from the shared normalization pipeline, so inserts now use that value directly.\n\nValidation run locally:\n- corepack pnpm test -- src/app/api/referrals/route.test.ts |
Summary
Fixes #279
Payment
Test plan
npx.cmd vitest run src/app/api/referrals/route.test.tsgit diff --check -- src/app/api/referrals/route.ts src/app/api/referrals/route.test.ts