Admin flag partner fraud#4089
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThe PR adds an admin partner-fraud flagging flow, updates fraud alert data contracts to include alert source information, centralizes fraud confirmation/reporting helpers, and refreshes fraud-alert admin views to show who flagged each alert. ChangesFraud alert workflow
Sequence Diagram(s)sequenceDiagram
participant AdminFraudPage
participant FlagPartnerFraudSheet
participant POSTRoute as POST /api/admin/partners/[partnerId]/flag-fraud
participant ConfirmPartnerFraudAlerts
participant ReportAdminFraudToPrograms
participant Prisma
AdminFraudPage->>FlagPartnerFraudSheet: open sheet and submit fraud reason
FlagPartnerFraudSheet->>POSTRoute: POST reason and reviewNote
POSTRoute->>Prisma: create fraudAlert and fetch enrollments
POSTRoute->>ConfirmPartnerFraudAlerts: confirm pending partner alerts
ConfirmPartnerFraudAlerts->>Prisma: update pending fraud alerts
POSTRoute->>ReportAdminFraudToPrograms: report fraud to active programs
ReportAdminFraudToPrograms->>Prisma: create fraud events
POSTRoute-->>FlagPartnerFraudSheet: success + alertedProgramsCount
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed: private package registry requires authentication. Disable ESLint in CodeRabbit settings or use public packages. 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 |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
apps/web/lib/zod/schemas/admin.ts (1)
97-108: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDerive
sourcefrom the Prisma enum
FRAUD_ALERT_SOURCESduplicatesFraudAlertSourcefrom Prisma; switchsourcetoz.enum(FraudAlertSource)so the allowed values stay in sync.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/lib/zod/schemas/admin.ts` around lines 97 - 108, The admin fraud schema is hardcoding the allowed source values instead of using the Prisma enum, so update `adminFraudAlertSchema` to derive `source` from `FraudAlertSource` rather than `FRAUD_ALERT_SOURCES`. Keep the existing `adminFraudAlertSchema` shape intact, but replace the `z.enum(...)` input for `source` so the validation stays aligned with Prisma’s `FraudAlertSource` definition and remove the duplicated source constant if it is no longer needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/app/`(ee)/api/admin/fraud-alerts/[id]/route.ts:
- Around line 62-68: The partner-level confirmation path in the fraud alert
route can return success even when the targeted alert is no longer pending,
because confirmPartnerFraudAlerts only checks alerts by fraudAlert.partnerId.
Before calling confirmPartnerFraudAlerts, verify the specific fraudAlert
referenced by the route parameter is still pending; if it has already been
reviewed, return the expected 409 instead of proceeding. Update the handler in
the route’s main function so the check happens against the targeted alert
record, not just the partner-wide batch.
In `@apps/web/app/`(ee)/api/admin/partners/[partnerId]/flag-fraud/route.ts:
- Around line 52-74: The flagging flow in the admin fraud route is not
idempotent after confirmation succeeds but reportAdminFraudToPrograms fails,
causing retries to create duplicate fraud alerts. Update the flow around
confirmPartnerFraudAlerts and reportAdminFraudToPrograms so a previously
committed admin fraud alert is reused or deduplicated for the same partner,
either by checking for an existing admin fraud alert before
prisma.fraudAlert.create, adding an idempotency key tied to the committed alert,
or moving the cross-program reporting into a retryable outbox/background step
keyed by that alert.
In `@apps/web/lib/api/fraud/confirm-partner-fraud-alerts.ts`:
- Around line 70-82: The confirmation flow in confirm-partner-fraud-alerts
currently awaits reportCrossProgramBanToNetwork via Promise.all, so a single
rejection can throw after the alerts have already been confirmed. Update the
helper to avoid failing the request once confirmation is committed:
capture/report network failures separately from the confirmation path, and keep
the success response based on the confirmation result even if some reporting
calls fail. Use the confirm-partner-fraud-alerts helper and
reportCrossProgramBanToNetwork call as the main locations to adjust.
- Around line 50-61: The confirmation result in confirmPartnerFraudAlerts is
using the pre-update pending list instead of the actual
prisma.fraudAlert.updateMany outcome. Capture the updateMany return value and
use its count as confirmedCount, then gate any reporting/side effects on that
count so confirmPartnerFraudAlerts only reports rows actually updated by this
call.
In `@apps/web/lib/api/fraud/report-admin-fraud-to-programs.ts`:
- Around line 15-22: The admin fraud targeting query in
report-admin-fraud-to-programs should exclude the network program so its own
enrollment does not get counted as an alert target and inflate
alertedProgramsCount. Update the prisma.programEnrollment.findMany filter inside
report-admin-fraud-to-programs to add a NETWORK_PROGRAM_ID exclusion alongside
the existing partnerId, status, and riskMonitoringDisabledAt conditions, and
make sure the later aggregation logic that builds the affected program
list/count uses the filtered results consistently.
---
Nitpick comments:
In `@apps/web/lib/zod/schemas/admin.ts`:
- Around line 97-108: The admin fraud schema is hardcoding the allowed source
values instead of using the Prisma enum, so update `adminFraudAlertSchema` to
derive `source` from `FraudAlertSource` rather than `FRAUD_ALERT_SOURCES`. Keep
the existing `adminFraudAlertSchema` shape intact, but replace the `z.enum(...)`
input for `source` so the validation stays aligned with Prisma’s
`FraudAlertSource` definition and remove the duplicated source constant if it is
no longer needed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 866db5fb-0669-42bc-9c14-17753918bbc6
📒 Files selected for processing (14)
apps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud/flag-partner-fraud-sheet.tsxapps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud/fraud-alert-reporter.tsxapps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud/page.tsxapps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud/review-fraud-alert-sheet.tsxapps/web/app/(ee)/api/admin/fraud-alerts/[id]/route.tsapps/web/app/(ee)/api/admin/partners/[partnerId]/flag-fraud/route.tsapps/web/app/(ee)/api/admin/partners/[partnerId]/route.tsapps/web/app/(ee)/api/admin/partners/fraud/route.tsapps/web/lib/api/fraud/confirm-partner-fraud-alerts.tsapps/web/lib/api/fraud/constants.tsapps/web/lib/api/fraud/report-admin-fraud-to-programs.tsapps/web/lib/api/fraud/report-cross-program-ban-to-network.tsapps/web/lib/zod/schemas/admin.tsapps/web/prisma/schema/fraud.prisma
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/lib/api/fraud/confirm-partner-fraud-alerts.ts`:
- Around line 74-79: The reporting re-fetch in confirm-partner-fraud-alerts
should only include rows updated by this specific call, not any later concurrent
confirmations. Reuse the exact reviewedAt value written in the
prisma.fraudAlert.updateMany call and add it to the fraudAlert.findMany filter
alongside status and reviewedById so only rows from this batch are re-fetched
for reporting.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8db6111b-ab64-413d-8b2c-38c6d8a3100a
📒 Files selected for processing (4)
apps/web/app/(ee)/api/admin/fraud-alerts/[id]/route.tsapps/web/app/(ee)/api/admin/partners/[partnerId]/flag-fraud/route.tsapps/web/lib/api/fraud/confirm-partner-fraud-alerts.tsapps/web/lib/api/fraud/report-admin-fraud-to-programs.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/web/app/(ee)/api/admin/fraud-alerts/[id]/route.ts
- apps/web/app/(ee)/api/admin/partners/[partnerId]/flag-fraud/route.ts
- apps/web/lib/api/fraud/report-admin-fraud-to-programs.ts
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/lib/api/fraud/confirm-partner-fraud-alerts.ts (1)
23-27: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winScope skipped reporting to the admin alert batch.
The admin flag route calls this helper with
skipCrossProgramReporting: true, but this query selects all pending alerts for the partner. If a program-sourced pending alert exists concurrently, it gets confirmed and Line 68 returns before its cross-program reporting runs.Proposed fix
export async function confirmPartnerFraudAlerts({ partnerId, reviewedById, reviewNote, skipCrossProgramReporting = false, + source, }: { partnerId: string; reviewedById: string; reviewNote?: string; skipCrossProgramReporting?: boolean; + source?: "program" | "admin"; }) { @@ where: { partnerId, status: "pending", + ...(source ? { source } : {}), },And pass
source: "admin"from the admin flag route when usingskipCrossProgramReporting: true.Also applies to: 68-73
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/lib/api/fraud/confirm-partner-fraud-alerts.ts` around lines 23 - 27, The pending alert lookup in confirmPartnerFraudAlerts is too broad and can consume program-sourced alerts when the admin path sets skipCrossProgramReporting, so narrow the prisma.fraudAlert.findMany filter to only the admin-sourced pending alert(s) for that flow. Then update the admin flag route to pass source: "admin" whenever skipCrossProgramReporting: true is used, and make sure the early return around the confirmation/reporting branch still preserves cross-program reporting for non-admin alerts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@apps/web/lib/api/fraud/confirm-partner-fraud-alerts.ts`:
- Around line 23-27: The pending alert lookup in confirmPartnerFraudAlerts is
too broad and can consume program-sourced alerts when the admin path sets
skipCrossProgramReporting, so narrow the prisma.fraudAlert.findMany filter to
only the admin-sourced pending alert(s) for that flow. Then update the admin
flag route to pass source: "admin" whenever skipCrossProgramReporting: true is
used, and make sure the early return around the confirmation/reporting branch
still preserves cross-program reporting for non-admin alerts.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b4fd6a07-fdcb-4ab2-b311-4b335816cf8c
📒 Files selected for processing (1)
apps/web/lib/api/fraud/confirm-partner-fraud-alerts.ts
|
@coderabbitai full review, any breaking changes? |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== Changed files vs main =="
git diff --name-only origin/main...HEAD
echo
echo "== Diff summary =="
git diff --stat origin/main...HEAD
echo
echo "== Outline: confirm-partner-fraud-alerts.ts =="
ast-grep outline 'apps/web/lib/api/fraud/confirm-partner-fraud-alerts.ts' --view expanded || true
echo
echo "== confirm-partner-fraud-alerts.ts =="
sed -n '1,260p' 'apps/web/lib/api/fraud/confirm-partner-fraud-alerts.ts'
echo
echo "== flag-fraud route =="
sed -n '1,260p' 'apps/web/app/(ee)/api/admin/partners/[partnerId]/flag-fraud/route.ts'
echo
echo "== fraud alert PATCH route =="
sed -n '1,260p' 'apps/web/app/(ee)/api/admin/fraud-alerts/[id]/route.ts'
echo
echo "== admin zod schemas =="
sed -n '1,260p' 'apps/web/lib/zod/schemas/admin.ts'
echo
echo "== admin partners route =="
sed -n '1,260p' 'apps/web/app/(ee)/api/admin/partners/[partnerId]/route.ts'
echo
echo "== fraud alerts list route =="
sed -n '1,220p' 'apps/web/app/(ee)/api/admin/partners/fraud/route.ts'
echo
echo "== fraud prisma schema =="
sed -n '1,220p' 'apps/web/prisma/schema/fraud.prisma'
echo
echo "== Search for confirmPartnerFraudAlerts call sites =="
rg -n -C2 '\bconfirmPartnerFraudAlerts\s*\(' apps/web
echo
echo "== Search for adminFraudAlertSchema call sites =="
rg -n -C2 '\badminFraudAlertSchema\b' apps/web
echo
echo "== Search for direct assumptions on fraudAlert.source =="
rg -n -C2 '\bsource\b' apps/web/app/(ee) apps/web/lib | sed -n '1,220p'Length of output: 32671 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== page.tsx =="
sed -n '1,260p' 'apps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud/page.tsx'
echo
echo "== review-fraud-alert-sheet.tsx =="
sed -n '1,320p' 'apps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud/review-fraud-alert-sheet.tsx'
echo
echo "== fraud-alert-reporter.tsx =="
sed -n '1,220p' 'apps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud/fraud-alert-reporter.tsx'
echo
echo "== report-admin-fraud-to-programs.ts =="
sed -n '1,260p' 'apps/web/lib/api/fraud/report-admin-fraud-to-programs.ts'
echo
echo "== report-cross-program-ban-to-network.ts =="
sed -n '1,260p' 'apps/web/lib/api/fraud/report-cross-program-ban-to-network.ts'
echo
echo "== constants.ts =="
sed -n '1,220p' 'apps/web/lib/api/fraud/constants.ts'
echo
echo "== flag-partner-fraud-sheet.tsx =="
sed -n '1,340p' 'apps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud/flag-partner-fraud-sheet.tsx'
echo
echo "== Check for Prisma migrations touching FraudAlertSource or FraudAlert.source =="
fd . 'apps/web/prisma' | sed -n '1,220p'
echo
rg -n -C2 'FraudAlertSource|source\s+FraudAlertSource|ALTER TABLE.*FraudAlert|CREATE TYPE.*FraudAlertSource' 'apps/web/prisma' || true
echo
echo "== Search for callers / consumers of /api/admin/partners/[partnerId] fraudAlerts payload =="
rg -n -C2 'fraudAlerts' 'apps/web/app' 'apps/web/lib' | sed -n '1,260p'
echo
echo "== Search for strict assumptions about FraudAlert fields/status/source in UI =="
rg -n -C2 'source|confirmed|dismissed|pending|Flagged by|Program' \
'apps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud' \
'apps/web/app/(ee)/api/admin/partners' \
'apps/web/app/(ee)/api/admin/fraud-alerts' | sed -n '1,260p'Length of output: 72746
Short answer: no obvious consumer-facing breaking API change inside this PR, since the updated routes, schemas, and admin UI were changed consistently together. Two things I’d still call out:
So my read is:
I’ll kick off the full re-review now. ✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/web/app/(ee)/api/admin/fraud-alerts/[id]/route.ts (1)
22-30: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winThis turns an id-scoped PATCH into a partner-wide review.
confirmPartnerFraudAlertsonly scopes bypartnerIdplus optionalsource(seeapps/web/lib/api/fraud/confirm-partner-fraud-alerts.ts, Lines 25-30), so this endpoint can confirm unrelated pending alerts for the same partner. It can also return 200 when the targeted alert lost the race but another pending alert was still available to batch-confirm. Keep this route id-scoped, or make the batch behavior explicit in the route/UI contract.Also applies to: 69-73
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/app/`(ee)/api/admin/fraud-alerts/[id]/route.ts around lines 22 - 30, The PATCH handler in the fraud alert route is unintentionally batching by partner instead of staying id-scoped, because it passes the alert’s partnerId into confirmPartnerFraudAlerts and can confirm other pending alerts for that partner. Update the route logic around fraudAlert lookup and confirmPartnerFraudAlerts so the endpoint only acts on the requested alert id, or explicitly change the route/UI contract to document partner-wide batch confirmation; if keeping batch behavior, make the success path and naming reflect that it may confirm a different pending alert for the same partner.apps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud/review-fraud-alert-sheet.tsx (1)
126-143: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winThe confirmation prompt no longer matches what this action does.
PATCH /api/admin/fraud-alerts/[id]now confirms all pending alerts for the same partner (and source), but the dialog still asks about confirming “this fraud alert”. That can bulk-confirm additional alerts without warning. Either restore single-alert confirmation on the server or update the copy/UX to disclose the wider scope before submit.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/app/`(ee)/admin.dub.co/(dashboard)/partners/fraud/review-fraud-alert-sheet.tsx around lines 126 - 143, The confirmation flow in handleReview no longer matches the PATCH /api/admin/fraud-alerts/[id] behavior, since it can confirm multiple pending alerts for the same partner/source while the dialog still says “this fraud alert.” Update the copy/UX in review-fraud-alert-sheet.tsx to clearly disclose the broader scope before submit, or change the API/server behavior back to single-alert confirmation. Make sure the user sees an accurate warning in the handleReview confirmation prompt before calling fetch.
♻️ Duplicate comments (1)
apps/web/app/(ee)/api/admin/partners/[partnerId]/flag-fraud/route.ts (1)
52-97: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftThe retry path still creates duplicate admin alerts.
If
reportAdminFraudToProgramsthrows after Line 72 confirms the alert, a retry will miss the existing row at Lines 52-59 because it is alreadyconfirmed, then create a second admin alert at Lines 61-69 for the same action. The read-then-create window is also racy under concurrent submissions. This needs an idempotent key/reuse strategy that survives post-confirmation failures, not just pending-row dedupe.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/app/`(ee)/api/admin/partners/[partnerId]/flag-fraud/route.ts around lines 52 - 97, The admin fraud route still creates duplicate alerts on retries because the lookup in the partner fraud handler only reuses a pending admin row, then creates a new one if the prior attempt was already confirmed; update the logic in the flag-fraud route to make alert creation idempotent across retries and concurrent submissions. Use the existing fraud alert lookup/create flow around prisma.fraudAlert.findFirst/create and confirmPartnerFraudAlerts to reuse any prior admin alert for the same partner/action (for example via a stable idempotency key or broader reuse criteria), so a failed reportAdminFraudToPrograms retry does not insert a second admin fraudAlert.
🧹 Nitpick comments (2)
apps/web/prisma/schema/fraud.prisma (1)
92-103: 🩺 Stability & Availability | 🔵 TrivialPlan an atomic rollout for
FraudAlert.source.This field is required here, and the updated admin API/schema now read it immediately. If app code rolls out before the migration and Prisma client regen, the first
sourceselect will fail at runtime. Deploy them together or gate the read path.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/prisma/schema/fraud.prisma` around lines 92 - 103, The new FraudAlert.source field is now read by the admin API/schema, so app code must not ship ahead of the database migration and Prisma client regeneration. Coordinate the rollout around FraudAlert and FraudAlertSource so the schema change, migration, and generated client are deployed together, or gate the read path until source is guaranteed to exist in all records and the client is updated.apps/web/lib/zod/schemas/admin.ts (1)
97-108: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAvoid duplicating the persisted fraud-source enum.
FRAUD_ALERT_SOURCESnow mirrors the PrismaFraudAlertSourcecontract, so a future enum change can make this parser reject valid rows even though the database and Prisma client are already updated. Zod 4 can validate the generated enum directly and keep this boundary single-sourced. ImportFraudAlertSourcealongsideFraudAlertStatus.♻️ Proposed refactor
-export const FRAUD_ALERT_SOURCES = ["program", "admin"] as const; - export const adminFlagFraudSchema = z.object({ reason: z.string().trim().min(1).max(MAX_FRAUD_REASON_LENGTH), reviewNote: z.string().trim().max(MAX_FRAUD_REASON_LENGTH).optional(), }); export const adminFraudAlertSchema = z.object({ id: z.string(), reason: z.string(), status: z.enum(FraudAlertStatus), - source: z.enum(FRAUD_ALERT_SOURCES), + source: z.enum(FraudAlertSource),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/lib/zod/schemas/admin.ts` around lines 97 - 108, `adminFraudAlertSchema` is duplicating the persisted fraud-source enum via `FRAUD_ALERT_SOURCES`, which can drift from Prisma and reject valid rows. Replace the local source array in `apps/web/lib/zod/schemas/admin.ts` with the generated `FraudAlertSource` enum imported alongside `FraudAlertStatus`, and update the `source` field in `adminFraudAlertSchema` to validate against that single source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@apps/web/app/`(ee)/admin.dub.co/(dashboard)/partners/fraud/flag-partner-fraud-sheet.tsx:
- Around line 100-115: The flag flow in flag-partner-fraud-sheet.tsx is showing
a success toast before the follow-up refresh via onFlagged() completes, so a
revalidation failure can trigger an unnecessary error toast after success.
Update the handler around the success toast and await onFlagged() so the refresh
is handled as a separate best-effort step, or move the toast.success call until
after onFlagged() succeeds; keep the error handling in the same flag submission
path.
---
Outside diff comments:
In
`@apps/web/app/`(ee)/admin.dub.co/(dashboard)/partners/fraud/review-fraud-alert-sheet.tsx:
- Around line 126-143: The confirmation flow in handleReview no longer matches
the PATCH /api/admin/fraud-alerts/[id] behavior, since it can confirm multiple
pending alerts for the same partner/source while the dialog still says “this
fraud alert.” Update the copy/UX in review-fraud-alert-sheet.tsx to clearly
disclose the broader scope before submit, or change the API/server behavior back
to single-alert confirmation. Make sure the user sees an accurate warning in the
handleReview confirmation prompt before calling fetch.
In `@apps/web/app/`(ee)/api/admin/fraud-alerts/[id]/route.ts:
- Around line 22-30: The PATCH handler in the fraud alert route is
unintentionally batching by partner instead of staying id-scoped, because it
passes the alert’s partnerId into confirmPartnerFraudAlerts and can confirm
other pending alerts for that partner. Update the route logic around fraudAlert
lookup and confirmPartnerFraudAlerts so the endpoint only acts on the requested
alert id, or explicitly change the route/UI contract to document partner-wide
batch confirmation; if keeping batch behavior, make the success path and naming
reflect that it may confirm a different pending alert for the same partner.
---
Duplicate comments:
In `@apps/web/app/`(ee)/api/admin/partners/[partnerId]/flag-fraud/route.ts:
- Around line 52-97: The admin fraud route still creates duplicate alerts on
retries because the lookup in the partner fraud handler only reuses a pending
admin row, then creates a new one if the prior attempt was already confirmed;
update the logic in the flag-fraud route to make alert creation idempotent
across retries and concurrent submissions. Use the existing fraud alert
lookup/create flow around prisma.fraudAlert.findFirst/create and
confirmPartnerFraudAlerts to reuse any prior admin alert for the same
partner/action (for example via a stable idempotency key or broader reuse
criteria), so a failed reportAdminFraudToPrograms retry does not insert a second
admin fraudAlert.
---
Nitpick comments:
In `@apps/web/lib/zod/schemas/admin.ts`:
- Around line 97-108: `adminFraudAlertSchema` is duplicating the persisted
fraud-source enum via `FRAUD_ALERT_SOURCES`, which can drift from Prisma and
reject valid rows. Replace the local source array in
`apps/web/lib/zod/schemas/admin.ts` with the generated `FraudAlertSource` enum
imported alongside `FraudAlertStatus`, and update the `source` field in
`adminFraudAlertSchema` to validate against that single source of truth.
In `@apps/web/prisma/schema/fraud.prisma`:
- Around line 92-103: The new FraudAlert.source field is now read by the admin
API/schema, so app code must not ship ahead of the database migration and Prisma
client regeneration. Coordinate the rollout around FraudAlert and
FraudAlertSource so the schema change, migration, and generated client are
deployed together, or gate the read path until source is guaranteed to exist in
all records and the client is updated.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1daae292-7ac0-4556-8c64-701cd4e104aa
📒 Files selected for processing (14)
apps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud/flag-partner-fraud-sheet.tsxapps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud/fraud-alert-reporter.tsxapps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud/page.tsxapps/web/app/(ee)/admin.dub.co/(dashboard)/partners/fraud/review-fraud-alert-sheet.tsxapps/web/app/(ee)/api/admin/fraud-alerts/[id]/route.tsapps/web/app/(ee)/api/admin/partners/[partnerId]/flag-fraud/route.tsapps/web/app/(ee)/api/admin/partners/[partnerId]/route.tsapps/web/app/(ee)/api/admin/partners/fraud/route.tsapps/web/lib/api/fraud/confirm-partner-fraud-alerts.tsapps/web/lib/api/fraud/constants.tsapps/web/lib/api/fraud/report-admin-fraud-to-programs.tsapps/web/lib/api/fraud/report-cross-program-ban-to-network.tsapps/web/lib/zod/schemas/admin.tsapps/web/prisma/schema/fraud.prisma
| toast.success( | ||
| alertedProgramsCount > 0 | ||
| ? `Fraud confirmed. ${alertedProgramsCount} program${alertedProgramsCount === 1 ? "" : "s"} alerted.` | ||
| : "Fraud confirmed. No other enrolled programs to alert.", | ||
| ); | ||
|
|
||
| setSearch(""); | ||
| setDebouncedSearch(""); | ||
| setReason(""); | ||
| setReviewNote(""); | ||
| setIsOpen(false); | ||
| await onFlagged(); | ||
| } catch (error) { | ||
| toast.error( | ||
| error instanceof Error ? error.message : "Something went wrong", | ||
| ); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Don’t show a failure toast after the flag already succeeded.
toast.success(...) runs before await onFlagged(), so a refresh/revalidation failure here will surface as a second error toast for an action that already completed. Split the follow-up refresh into its own best-effort path, or move the success toast after it.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@apps/web/app/`(ee)/admin.dub.co/(dashboard)/partners/fraud/flag-partner-fraud-sheet.tsx
around lines 100 - 115, The flag flow in flag-partner-fraud-sheet.tsx is showing
a success toast before the follow-up refresh via onFlagged() completes, so a
revalidation failure can trigger an unnecessary error toast after success.
Update the handler around the success toast and await onFlagged() so the refresh
is handled as a separate best-effort step, or move the toast.success call until
after onFlagged() succeeds; keep the error handling in the same flag submission
path.
Summary by CodeRabbit