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

Skip to content

Conversation

@steven-tey
Copy link
Collaborator

@steven-tey steven-tey commented Sep 3, 2025

Summary by CodeRabbit

  • New Features

    • Automatic background workflows now trigger after sales and new leads for eligible partner programs across Stripe checkouts, invoices, and Shopify sales.
    • Sale events consistently trigger automations; lead events trigger when applicable for new leads.
  • Refactor

    • Parallelized event handling to improve responsiveness and reduce processing time for post-sale and lead workflows.
  • Chores

    • Enhanced logging for partner commissions with clearer earnings details to aid monitoring and support.

@vercel
Copy link
Contributor

vercel bot commented Sep 3, 2025

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

Project Deployment Preview Updated (UTC)
dub Ready Ready Preview Sep 3, 2025 6:43pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 3, 2025

Walkthrough

Adds workflow triggers for saleRecorded and leadRecorded across Stripe webhooks, Shopify sale handling, and commission creation. Removes prior gating on commission results. Introduces parallel execution via Promise.allSettled and schedules background workflows with waitUntil. Adds detailed logging after partner commission creation.

Changes

Cohort / File(s) Summary of changes
Stripe webhooks: sale/lead workflow triggering
apps/web/app/(ee)/api/stripe/integration/webhook/checkout-session-completed.ts, apps/web/app/(ee)/api/stripe/integration/webhook/invoice-paid.ts
Always trigger saleRecorded workflows; leadRecorded added conditionally for new leads. Uses Promise.allSettled to run saleRecorded (always) and leadRecorded (conditional) in parallel. Removes gating based on commission result.
Commission actions: parallel workflow triggers
apps/web/lib/actions/partners/create-commission.ts
After recording lead/sale and creating commissions, triggers executeWorkflows for leadRecorded/saleRecorded in parallel with existing tasks using Promise.allSettled. No signature changes.
Shopify: post-sale workflow
apps/web/lib/integrations/shopify/create-sale.ts
After processing a sale with programId/partnerId, schedules background executeWorkflows with trigger saleRecorded via waitUntil. Core sale logic unchanged.
Partner commission logging
apps/web/lib/partners/create-partner-commission.ts
Adds detailed console log after commission creation using currencyFormatter; no behavioral changes to returns or errors.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant SRC as Source Event<br/>(Stripe/Shopify)
  participant H as Handler
  participant PC as Commission Creation
  participant WF as Workflow Engine

  Note over SRC,H: Sale or checkout completion received
  SRC->>H: HTTP request / event payload
  H->>PC: createPartnerCommission(...) (as applicable)
  PC-->>H: commission created (async)

  rect rgb(240,248,255)
    Note over H,WF: Parallel workflow triggers
    par Always
      H->>WF: executeWorkflows(trigger: saleRecorded,<br/>programId, partnerId)
      WF-->>H: enqueued/settled
    and New lead only
      alt clickEvent exists AND not existingCustomer
        H->>WF: executeWorkflows(trigger: leadRecorded,<br/>programId, partnerId)
        WF-->>H: enqueued/settled
      else No lead workflow
        H-->>H: skip leadRecorded
      end
    end
  end
Loading
sequenceDiagram
  autonumber
  participant SH as Shopify
  participant HS as create-sale handler
  participant WF as Workflow Engine

  SH->>HS: Sale processed
  alt link has programId & partnerId
    HS->>WF: waitUntil(executeWorkflows(saleRecorded,...))
    WF-->>HS: scheduled (non-blocking)
  else no link
    HS-->>HS: skip workflow
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • TWilson023

Poem

I thump the queue with gentle paws,
Two triggers leap without a pause—
A sale, a lead, both neatly set,
In parallel, no bottleneck.
Logs sparkle like a carrot’s sheen—
Workflows hop where they’ve not been. 🥕🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add-missing-workflows

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 2

🧹 Nitpick comments (2)
apps/web/lib/actions/partners/create-commission.ts (1)

19-19: Standardize WorkflowTrigger import path

Match the rest of the codebase by importing from "@dub/prisma/client".

Apply:

-import { WorkflowTrigger } from "@prisma/client";
+import { WorkflowTrigger } from "@dub/prisma/client";
apps/web/app/(ee)/api/stripe/integration/webhook/checkout-session-completed.ts (1)

365-383: Minor: avoid non-Promise entries in Promise.allSettled for clarity

Passing a falsy value is fine (it settles immediately), but building the tasks array reads cleaner.

Apply:

-    waitUntil(
-      Promise.allSettled([
-        executeWorkflows({
-          trigger: WorkflowTrigger.saleRecorded,
-          programId: link.programId,
-          partnerId: link.partnerId,
-        }),
-        // same logic as lead.created webhook below:
-        // if the clickEvent variable exists and there was no existing customer before,
-        // we need to trigger the leadRecorded workflow
-        clickEvent &&
-          !existingCustomer &&
-          executeWorkflows({
-            trigger: WorkflowTrigger.leadRecorded,
-            programId: link.programId,
-            partnerId: link.partnerId,
-          }),
-      ]),
-    );
+    waitUntil(
+      (async () => {
+        const tasks: Promise<unknown>[] = [
+          executeWorkflows({
+            trigger: WorkflowTrigger.saleRecorded,
+            programId: link.programId,
+            partnerId: link.partnerId,
+          }),
+        ];
+        if (clickEvent && !existingCustomer) {
+          tasks.push(
+            executeWorkflows({
+              trigger: WorkflowTrigger.leadRecorded,
+              programId: link.programId,
+              partnerId: link.partnerId,
+            }),
+          );
+        }
+        await Promise.allSettled(tasks);
+      })(),
+    );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d30d076 and 3e5cb59.

📒 Files selected for processing (5)
  • apps/web/app/(ee)/api/stripe/integration/webhook/checkout-session-completed.ts (2 hunks)
  • apps/web/app/(ee)/api/stripe/integration/webhook/invoice-paid.ts (1 hunks)
  • apps/web/lib/actions/partners/create-commission.ts (4 hunks)
  • apps/web/lib/integrations/shopify/create-sale.ts (3 hunks)
  • apps/web/lib/partners/create-partner-commission.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: devkiran
PR: dubinc/dub#2736
File: apps/web/app/(ee)/api/stripe/integration/webhook/invoice-paid.ts:12-12
Timestamp: 2025-08-25T17:33:45.072Z
Learning: The WorkflowTrigger enum in packages/prisma/schema/workflow.prisma contains three values: leadRecorded, saleRecorded, and commissionEarned. All three are properly used throughout the codebase.
📚 Learning: 2025-08-25T17:33:45.072Z
Learnt from: devkiran
PR: dubinc/dub#2736
File: apps/web/app/(ee)/api/stripe/integration/webhook/invoice-paid.ts:12-12
Timestamp: 2025-08-25T17:33:45.072Z
Learning: The WorkflowTrigger enum in packages/prisma/schema/workflow.prisma contains three values: leadRecorded, saleRecorded, and commissionEarned. All three are properly used throughout the codebase.

Applied to files:

  • apps/web/lib/partners/create-partner-commission.ts
  • apps/web/app/(ee)/api/stripe/integration/webhook/checkout-session-completed.ts
  • apps/web/lib/integrations/shopify/create-sale.ts
  • apps/web/lib/actions/partners/create-commission.ts
🧬 Code graph analysis (5)
apps/web/lib/partners/create-partner-commission.ts (1)
packages/utils/src/functions/currency-formatter.ts (1)
  • currencyFormatter (5-16)
apps/web/app/(ee)/api/stripe/integration/webhook/checkout-session-completed.ts (2)
apps/web/lib/partners/create-partner-commission.ts (1)
  • createPartnerCommission (25-341)
apps/web/lib/api/workflows/execute-workflows.ts (1)
  • executeWorkflows (17-122)
apps/web/lib/integrations/shopify/create-sale.ts (2)
apps/web/lib/api/workflows/execute-workflows.ts (1)
  • executeWorkflows (17-122)
packages/prisma/client.ts (1)
  • WorkflowTrigger (25-25)
apps/web/lib/actions/partners/create-commission.ts (2)
apps/web/lib/api/workflows/execute-workflows.ts (1)
  • executeWorkflows (17-122)
packages/prisma/client.ts (1)
  • WorkflowTrigger (25-25)
apps/web/app/(ee)/api/stripe/integration/webhook/invoice-paid.ts (1)
apps/web/lib/api/workflows/execute-workflows.ts (1)
  • executeWorkflows (17-122)
⏰ 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). (2)
  • GitHub Check: Vade Review
  • GitHub Check: build
🔇 Additional comments (5)
apps/web/app/(ee)/api/stripe/integration/webhook/invoice-paid.ts (1)

212-218: Good call: always enqueue saleRecorded workflows in the background

Non-blocking trigger via waitUntil aligns with the PR goal and avoids coupling to commission creation.

apps/web/lib/integrations/shopify/create-sale.ts (1)

160-166: LGTM: non-blocking saleRecorded workflow trigger

Scheduling executeWorkflows with waitUntil keeps Shopify sale handling fast while ensuring workflows run.

apps/web/lib/actions/partners/create-commission.ts (2)

206-211: LGTM: trigger leadRecorded in parallel with lead recording/commission

Parallelizing with Promise.allSettled is appropriate here.


250-255: LGTM: trigger saleRecorded in parallel with sale recording/commission

Consistent with the rest of the PR and resilient via Promise.allSettled.

apps/web/app/(ee)/api/stripe/integration/webhook/checkout-session-completed.ts (1)

344-363: Decoupling from commission result is correct

Awaiting createPartnerCommission without gating subsequent steps matches the intent to always trigger workflows.

import { transformSaleEventData } from "@/lib/webhook/transform";
import { prisma } from "@dub/prisma";
import { nanoid } from "@dub/utils";
import { WorkflowTrigger } from "@prisma/client";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Standardize WorkflowTrigger import path

Other files import WorkflowTrigger from "@dub/prisma/client". For consistency (and to avoid dual-type/enums across modules), import from the same path here.

Apply:

-import { WorkflowTrigger } from "@prisma/client";
+import { WorkflowTrigger } from "@dub/prisma/client";

Run to check inconsistent imports across the repo:


🏁 Script executed:

#!/bin/bash
# Show all WorkflowTrigger import sources with context
rg -nP -C1 'import\s+{?\s*WorkflowTrigger\s*}?\s+from\s+["\'](@dub/prisma/client|@prisma/client)["\']'

Length of output: 285


🏁 Script executed:

#!/bin/bash
# List all import statements of WorkflowTrigger and their source modules
rg -nP 'import\s+{[^}]*WorkflowTrigger[^}]*}\s+from\s+["\']([^"\']+)["\']'

Length of output: 257


🏁 Script executed:

#!/bin/bash
# List all import statements of WorkflowTrigger in TypeScript files
grep -RIn --include \*.ts "import.*WorkflowTrigger" .

Length of output: 1072


Standardize WorkflowTrigger import path
In apps/web/lib/integrations/shopify/create-sale.ts, change the import to match other modules and avoid dual‐type/enums:

-import { WorkflowTrigger } from "@prisma/client";
+import { WorkflowTrigger } from "@dub/prisma/client";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { WorkflowTrigger } from "@prisma/client";
import { WorkflowTrigger } from "@dub/prisma/client";
🤖 Prompt for AI Agents
In apps/web/lib/integrations/shopify/create-sale.ts around line 12, replace the
direct import from "@prisma/client" with the project's shared export for Prisma
enums/types to match other modules (for example: import { WorkflowTrigger } from
"db"), so you consistently consume the single re-exported WorkflowTrigger and
avoid dual-type/enum mismatches across bundles.

Comment on lines +241 to +243
console.log(
`Created a ${event} commission ${commission.id} (${currencyFormatter(commission.earnings)}) for ${partnerId}: ${JSON.stringify(commission)}`,
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid logging full commission object (PII risk) and format in the correct currency

console.log(JSON.stringify(commission)) may leak customer PII and sensitive metadata. Also, currencyFormatter defaults to USD, which can misrepresent non-USD commissions. Log a concise, non-PII message and pass the commission currency.

Apply:

-    console.log(
-      `Created a ${event} commission ${commission.id} (${currencyFormatter(commission.earnings)}) for ${partnerId}: ${JSON.stringify(commission)}`,
-    );
+    console.log(
+      `Created ${event} commission ${commission.id} for ${partnerId} — ${currencyFormatter(commission.earnings, { currency: (commission.currency ?? "usd").toUpperCase() })}.`,
+    );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log(
`Created a ${event} commission ${commission.id} (${currencyFormatter(commission.earnings)}) for ${partnerId}: ${JSON.stringify(commission)}`,
);
console.log(
`Created ${event} commission ${commission.id} for ${partnerId} — ${currencyFormatter(
commission.earnings,
{ currency: (commission.currency ?? "usd").toUpperCase() }
)}.`,
);
🤖 Prompt for AI Agents
In apps/web/lib/partners/create-partner-commission.ts around lines 241 to 243,
the current console.log prints the entire commission object (risking PII
exposure) and calls currencyFormatter without the commission currency; replace
this with a concise, non-PII log that only includes safe identifiers
(commission.id, partnerId, event) and the earnings formatted with the
commission's currency (e.g., currencyFormatter(commission.earnings,
commission.currency)), and ensure you do not stringify or print any customer or
sensitive fields from the commission object.

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