-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Fraud cleanups #3201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fraud cleanups #3201
Conversation
β¦hema for required properties
WalkthroughUpdated fraud event creation and logging, removed several migration/cleanup scripts and the group-key helper, tightened the Prisma FraudEvent model, added a debug log before creating events, and adjusted a resolved-fraud-group table rendering case. Changes
Estimated code review effortπ― 3 (Moderate) | β±οΈ ~30 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touchesβ Failed checks (1 warning, 1 inconclusive)
β Passed checks (1 passed)
β¨ Finishing touches
π§ͺ Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
π§Ή Nitpick comments (2)
apps/web/lib/api/fraud/create-fraud-events.ts (2)
113-115: Make thefinalGroupLookup.get(...)!invariant explicit or guardedThe
!onfinalGroupLookup.get(createGroupCompositeKey(e))!relies on the assumption that everynewEventstriple (programId, partnerId, type) is present infinalGroups. Thatβs currently true given howexistingGroups,groupsToCreate, andnewGroupsare built, but if grouping logic orcreateGroupCompositeKeychanges later this will fail at runtime in a non-obvious way.Consider adding a small guard to make the invariant explicit:
- fraudEventGroupId: finalGroupLookup.get(createGroupCompositeKey(e))!, + fraudEventGroupId: (() => { + const groupId = finalGroupLookup.get(createGroupCompositeKey(e)); + if (!groupId) { + throw new Error( + `[createFraudEvents] Missing group for event ${e.programId}:${e.partnerId}:${e.type}`, + ); + } + return groupId; + })(),(or a shared helper/assert) so failures surface with a clear error message if this assumption is ever broken.
Also applies to: 121-121
16-18: TightencreateFraudEventslogging to reduce noise and limit payload exposureThe new logs are useful, but as written they will emit on every call (including the "no events" paths) and, for successful writes, log the full
newEventsWithGrouppayload viaprettyPrint. Even thoughsanitizeFraudEventMetadatahas strippedduplicatePartnerIdandpayoutMethodHash, these logs still include internal identifiers (program/partner/link/customer/event ids) and full metadata for every new fraud event, which can be both noisy and sensitive in high-volume environments.Consider:
- Keeping concise info-level summaries, and
- Moving detailed payload logs behind a debug flag or nonβproduction check.
For example:
- if (fraudEvents.length === 0) { - console.log(`[createFraudEvents] No fraud events to create`); + if (fraudEvents.length === 0) { + console.debug(`[createFraudEvents] No fraud events to create`); @@ - if (newEvents.length === 0) { - console.log(`[createFraudEvents] No new fraud events to create`); + if (newEvents.length === 0) { + console.debug(`[createFraudEvents] No new fraud events to create`); @@ - console.info( - `[createFraudEvents] Created ${createdEvents.count} fraud events ${prettyPrint( - newEventsWithGroup, - )}`, - ); + console.info( + `[createFraudEvents] Created ${createdEvents.count} fraud events`, + ); + if (process.env.NODE_ENV !== "production") { + console.debug( + `[createFraudEvents] Created events payload: ${prettyPrint( + newEventsWithGroup, + )}`, + ); + } @@ - const endTime = performance.now(); - console.info( - `[createFraudEvents] completed in ${(endTime - startTime).toFixed(2)}ms`, - ); + const endTime = performance.now(); + console.info( + `[createFraudEvents] completed in ${(endTime - startTime).toFixed(2)}ms`, + );(Adjust log levels / gating to match whatever logging policy youβre following.)
Also applies to: 55-57, 135-137, 156-159
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
π Files selected for processing (3)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolved/resolved-fraud-group-table.tsx(2 hunks)apps/web/lib/api/fraud/create-fraud-events.ts(4 hunks)apps/web/lib/api/fraud/detect-record-fraud-event.ts(2 hunks)
π§° Additional context used
π§ Learnings (6)
π Common learnings
Learnt from: devkiran
Repo: dubinc/dub PR: 3200
File: apps/web/lib/api/fraud/detect-duplicate-payout-method-fraud.ts:55-73
Timestamp: 2025-12-08T09:44:28.429Z
Learning: In apps/web/lib/api/fraud/detect-duplicate-payout-method-fraud.ts, the fraud event creation logic intentionally generates self-referential fraud events (where partnerId equals duplicatePartnerId) for partners with duplicate payout methods. This is by design to create raw events for all partners involved in a duplicate payout method scenario, regardless of whether they reference themselves.
Learnt from: devkiran
Repo: dubinc/dub PR: 3175
File: apps/web/lib/actions/partners/bulk-reject-partner-applications.ts:14-21
Timestamp: 2025-12-03T09:19:48.164Z
Learning: In apps/web/lib/actions/partners/bulk-reject-partner-applications.ts, the bulkRejectPartnerApplicationsAction does not need explicit plan capability checks for fraud operations (when reportFraud is true) because the authorization is handled automatically by the underlying fraud operation functions (resolveFraudGroups, createFraudEvents) or through other automated mechanisms in the system.
Learnt from: devkiran
Repo: dubinc/dub PR: 3089
File: apps/web/app/(ee)/api/fraud-rules/route.ts:71-87
Timestamp: 2025-11-24T08:55:31.332Z
Learning: In apps/web/app/(ee)/api/fraud-rules/route.ts, fraud rules cannot be created in a disabled state. When using prisma.fraudRule.upsert, the create branch intentionally omits the disabledAt field (defaulting to null, meaning enabled), while the update branch allows toggling enabled/disabled state via the disabledAt field. This is a business logic constraint.
π Learning: 2025-10-15T01:05:43.266Z
Learnt from: steven-tey
Repo: dubinc/dub PR: 2958
File: apps/web/app/app.dub.co/(dashboard)/[slug]/settings/members/page-client.tsx:432-457
Timestamp: 2025-10-15T01:05:43.266Z
Learning: In apps/web/app/app.dub.co/(dashboard)/[slug]/settings/members/page-client.tsx, defer refactoring the custom MenuItem component (lines 432-457) to use the shared dub/ui MenuItem component to a future PR, as requested by steven-tey.
Applied to files:
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolved/resolved-fraud-group-table.tsx
π Learning: 2025-11-24T09:10:12.536Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3089
File: apps/web/lib/api/fraud/fraud-rules-registry.ts:17-25
Timestamp: 2025-11-24T09:10:12.536Z
Learning: In apps/web/lib/api/fraud/fraud-rules-registry.ts, the fraud rules `partnerCrossProgramBan` and `partnerDuplicatePayoutMethod` intentionally have stub implementations that return `{ triggered: false }` because they are partner-scoped rules handled separately during partner application/onboarding flows (e.g., in detect-record-fraud-application.ts), rather than being evaluated per conversion event like other rules in the registry. The stubs exist only to satisfy the `Record<FraudRuleType, ...>` type constraint.
Applied to files:
apps/web/lib/api/fraud/detect-record-fraud-event.tsapps/web/lib/api/fraud/create-fraud-events.ts
π Learning: 2025-12-08T09:44:28.429Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3200
File: apps/web/lib/api/fraud/detect-duplicate-payout-method-fraud.ts:55-73
Timestamp: 2025-12-08T09:44:28.429Z
Learning: In apps/web/lib/api/fraud/detect-duplicate-payout-method-fraud.ts, the fraud event creation logic intentionally generates self-referential fraud events (where partnerId equals duplicatePartnerId) for partners with duplicate payout methods. This is by design to create raw events for all partners involved in a duplicate payout method scenario, regardless of whether they reference themselves.
Applied to files:
apps/web/lib/api/fraud/detect-record-fraud-event.tsapps/web/lib/api/fraud/create-fraud-events.ts
π Learning: 2025-12-03T09:19:48.164Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3175
File: apps/web/lib/actions/partners/bulk-reject-partner-applications.ts:14-21
Timestamp: 2025-12-03T09:19:48.164Z
Learning: In apps/web/lib/actions/partners/bulk-reject-partner-applications.ts, the bulkRejectPartnerApplicationsAction does not need explicit plan capability checks for fraud operations (when reportFraud is true) because the authorization is handled automatically by the underlying fraud operation functions (resolveFraudGroups, createFraudEvents) or through other automated mechanisms in the system.
Applied to files:
apps/web/lib/api/fraud/detect-record-fraud-event.tsapps/web/lib/api/fraud/create-fraud-events.ts
π Learning: 2025-11-24T08:55:31.332Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3089
File: apps/web/app/(ee)/api/fraud-rules/route.ts:71-87
Timestamp: 2025-11-24T08:55:31.332Z
Learning: In apps/web/app/(ee)/api/fraud-rules/route.ts, fraud rules cannot be created in a disabled state. When using prisma.fraudRule.upsert, the create branch intentionally omits the disabledAt field (defaulting to null, meaning enabled), while the update branch allows toggling enabled/disabled state via the disabledAt field. This is a business logic constraint.
Applied to files:
apps/web/lib/api/fraud/detect-record-fraud-event.tsapps/web/lib/api/fraud/create-fraud-events.ts
𧬠Code graph analysis (2)
apps/web/lib/api/fraud/detect-record-fraud-event.ts (1)
packages/utils/src/functions/pretty-print.ts (1)
prettyPrint(1-15)
apps/web/lib/api/fraud/create-fraud-events.ts (3)
apps/web/lib/api/fraud/utils.ts (3)
createGroupCompositeKey(123-127)getPartnerIdForFraudEvent(131-141)sanitizeFraudEventMetadata(107-120)packages/prisma/index.ts (1)
prisma(3-9)packages/utils/src/functions/pretty-print.ts (1)
prettyPrint(1-15)
β° Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
π Additional comments (1)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolved/resolved-fraud-group-table.tsx (1)
154-160: Nice improvement to data visibility.The updated logic now displays the resolution date even when the user information is unavailable, which is more informative than showing just "-". This properly handles the case where a resolution timestamp exists but the associated user record might be missing or inaccessible.
Summary by CodeRabbit
Chores
Refactor
Improvements
User-facing
βοΈ Tip: You can customize this high-level summary in your review settings.