Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@devkiran
Copy link
Collaborator

@devkiran devkiran commented Dec 8, 2025

Summary by CodeRabbit

  • Chores

    • Removed multiple obsolete fraud-event migration and cleanup scripts.
  • Refactor

    • Simplified fraud event data model: removed deprecated fields, made group reference and hash required, and consolidated partner relation.
    • Removed an unused grouping helper and streamlined event grouping/creation.
  • Improvements

    • More informative and standardized logging around event creation and rule triggers.
  • User-facing

    • Resolved-fraud list now shows a resolution date when present even if the resolver is missing.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 8, 2025

Walkthrough

Updated 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

Cohort / File(s) Summary
Fraud event creation logic
apps/web/lib/api/fraud/create-fraud-events.ts
Removed createFraudEventGroupKey import; used non-null assertion on group lookup (...get(...)!); dropped deprecated payload fields (type, groupKey); added early-exit logs for no events/no new events; unconditional creation summary log; updated group records' lastEventAt and eventCount; standardized completion log prefix [createFraudEvents].
Fraud detection debug log
apps/web/lib/api/fraud/detect-record-fraud-event.ts
Added prettyPrint import and a new debug log that prints triggered rule count/details when triggers exist (executes only when triggeredRules.length > 0).
Frontend rendering tweak
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolved/resolved-fraud-group-table.tsx
Changed import to include formatDate; resolvedAt cell now shows a formatted date when resolvedAt exists even if user is missing (previously rendered -).
Deleted migration & cleanup scripts
apps/web/scripts/migrations/...
apps/web/scripts/remove-duplicate-fraud-events.ts
Removed multiple standalone migration/cleanup scripts: backfill-fraud-event-hashes.ts, backfill-fraud-event-metadata.ts, backfill-fraud-group-events-count.ts, cleanup-fraud-events.ts, migrate-duplicate-payout-fraud-events.ts, migrate-fraud-events.ts, and remove-duplicate-fraud-events.ts.
Prisma schema (fraud)
packages/prisma/schema/fraud.prisma
Made fraudEventGroupId and hash non-nullable; removed deprecated fields from FraudEvent (commissionId, type, groupKey, userId, resolutionReason, resolvedAt, status); removed indices on userId, commissionId, and groupKey; made fraudEventGroup relation required and normalized partner relation with onDelete: Cascade.
Fraud utilities
apps/web/lib/api/fraud/utils.ts
Deleted exported helper createFraudEventGroupKey(input: CreateGroupKeyInput) (group-key hashing helper).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

  • Review create-fraud-events.ts for safety of the non-null assertion and correctness of updated group counts/timestamps.
  • Verify Prisma migrations and schema alignment for non-null fields and relation changes.
  • Search for any remaining references to removed fields or the deleted helper across the codebase.

Possibly related PRs

Poem

πŸ‡
I hopped through code both neat and spry,
Nibbled old keys and waved them bye.
Groups now counted, logs aglow,
Scripts trimmed down β€” my burrow's so.
✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Fraud cleanups' is vague and generic, using non-descriptive language that doesn't convey specific details about the changeset despite significant structural changes. Consider using a more specific title that highlights the main changes, such as 'Refactor fraud event handling: remove deprecated fields and migration scripts' or similar.
βœ… Passed checks (1 passed)
Check name Status Explanation
Description Check βœ… Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • πŸ“ Generate docstrings
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fraud-cleanups

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.

❀️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@vercel
Copy link
Contributor

vercel bot commented Dec 8, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
dub Ready Ready Preview Dec 11, 2025 0:59am

Base automatically changed from fraud-improvements to main December 8, 2025 22:54
@devkiran devkiran marked this pull request as ready for review December 9, 2025 17:58
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 the finalGroupLookup.get(...)! invariant explicit or guarded

The ! on finalGroupLookup.get(createGroupCompositeKey(e))! relies on the assumption that every newEvents triple (programId, partnerId, type) is present in finalGroups. That’s currently true given how existingGroups, groupsToCreate, and newGroups are built, but if grouping logic or createGroupCompositeKey changes 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: Tighten createFraudEvents logging to reduce noise and limit payload exposure

The 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 newEventsWithGroup payload via prettyPrint. Even though sanitizeFraudEventMetadata has stripped duplicatePartnerId and payoutMethodHash, 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

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 3e6961d and f5056d0.

πŸ“’ 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.ts
  • apps/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.ts
  • apps/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.ts
  • apps/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.ts
  • apps/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.

@steven-tey steven-tey merged commit 2a03885 into main Dec 11, 2025
6 of 8 checks passed
@steven-tey steven-tey deleted the fraud-cleanups branch December 11, 2025 01:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants