8000 Account for legacy Business plans by steven-tey · Pull Request #2521 · dubinc/dub · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Account for legacy Business plans #2521

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

Account for legacy Business plans #2521

wants to merge 5 commits into from

Conversation

steven-tey
Copy link
Collaborator
@steven-tey steven-tey commented Jun 12, 2025

Summary by CodeRabbit

  • New Features

    • Added support for the "business legacy" plan across various API endpoints, allowing users with this plan to access folders, webhooks, customers, events, Shopify and Stripe integrations, and lead/sale tracking features.
    • Introduced a script to export partner link data to CSV for reporting purposes.
  • Changes

    • Adjusted the order of plans in access control for some partner-related API endpoints.
  • Bug Fixes

    • Updated plan capability logic to exclude "business legacy" from certain program management features.
  • Chores

    • Updated internal plan lists to include "business legacy".
  • Revert

    • Removed the PATCH endpoint for updating partner sale commissions.

Copy link
vercel bot commented Jun 12, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
dub ✅ Ready (Inspect) Visit Preview Jun 15, 2025 3:48am

Copy link
bug0-qa-agent bot commented Jun 12, 2025

🤖 Bug0 QA Agent

Here are the results of the automated tests for PR #2521:

To re-run the tests, please comment /bug0 run or push a new commit to this PR.

Copy link
Contributor
coderabbitai bot commented Jun 12, 2025

Walkthrough

The changes primarily add the "business legacy" plan to the list of allowed or required plans for various API endpoints, access control checks, and capability logic throughout the codebase. Some files adjust the order of plan names, and a PATCH endpoint for partner sales is removed. Additionally, a new script for exporting partner links to CSV is introduced.

Changes

File(s) Change Summary
.../api/customers/route.ts
.../api/customers/[id]/route.ts
.../api/events/route.ts
.../api/events/export/route.ts
.../api/track/lead/route.ts
.../api/track/sale/route.ts
.../api/shopify/integration/callback/route.ts
.../api/stripe/integration/route.ts
.../api/webhooks/route.ts
.../api/webhooks/[webhookId]/route.ts
.../api/webhooks/[webhookId]/events/route.ts
.../api/folders/route.ts
.../api/folders/[folderId]/route.ts
.../api/folders/[folderId]/users/route.ts
.../api/folders/access-requests/route.ts
.../api/folders/permissions/route.ts
Added "business legacy" plan to required/allowed plans for various API endpoints.
.../api/partners/route.ts
.../api/partners/count/route.ts
.../api/partners/export/route.ts
Adjusted the order of "business plus" in the requiredPlan array; no plans added or removed.
.../api/partners/sales/route.ts Removed PATCH endpoint for updating partner sale commissions.
.../lib/auth/workspace.ts Included "business legacy" in workspace plan validation logic.
.../lib/types.ts Added "business legacy" to exported plans array.
.../lib/plan-capabilities.ts Updated canManageProgram to exclude "business legacy" plan as well.
.../scripts/framer/export-links.ts Added new script to export partner links to CSV using Prisma and papaparse.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant API_Endpoint
    participant Auth_Middleware

    User->>API_Endpoint: Request (e.g., GET /api/customers)
    API_Endpoint->>Auth_Middleware: Check requiredPlan (includes "business legacy")
    Auth_Middleware-->>API_Endpoint: Allow or deny based on plan
    API_Endpoint-->>User: Response (data or error)
Loading
sequenceDiagram
    participant Script
    participant Prisma_DB
    participant FileSystem

    Script->>Prisma_DB: Query links (by programId, partnerId)
    Prisma_DB-->>Script: Return link records
    Script->>FileSystem: Write CSV (via, partner_id)
    FileSystem-->>Script: File written (framer_partner_links.csv)
Loading

Poem

In the meadow of plans, a legacy hops in,
APIs now welcome this bunny kin.
Old sales PATCHes bid a gentle goodbye,
While partner links to CSV fly.
Plans reshuffled, permissions anew—
A rabbit’s work is never through!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9c712ea and 9a0b072.

📒 Files selected for processing (1)
  • apps/web/app/(ee)/api/partners/count/route.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/(ee)/api/partners/count/route.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
✨ Finishing Touches
  • 📝 Generate Docstrings

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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai 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

Documentation and Community

  • 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: 1

🔭 Outside diff range comments (1)
apps/web/scripts/framer/export-links.ts (1)

6-34: 🛠️ Refactor suggestion

Add error handling & ensure Prisma disconnect

main() is invoked without a .catch, and the Prisma client is never disconnected—Node processes can hang on open connections.

 async function main() {
   const links = await prisma.link.findMany({
     ...
   });
   ...
   fs.writeFileSync(
     "framer_partner_links.csv",
     ...
   );
+
+  await prisma.$disconnect();
 }
 
-main();
+main().catch((err) => {
+  console.error(err);
+  prisma.$disconnect().finally(() => process.exit(1));
+});

This guarantees clean shutdown and surfaces failures in CI.

♻️ Duplicate comments (3)
apps/web/app/api/folders/[folderId]/route.ts (2)

99-107: Same concern as above – see earlier comment.


170-178: Same concern as above – see earlier comment.

apps/web/app/(ee)/api/track/lead/route.ts (1)

308-316: Plan list mirrors the earlier events route; same centralization suggestion applies.

🧹 Nitpick comments (14)
apps/web/app/api/folders/[folderId]/users/route.ts (1)

79-79: Extract repeated plan lists to maintain DRY.

Adding "business legacy" here is correct, but the same array of plans is duplicated across many routes. Consider extracting these into a shared constant (e.g. ALLOWED_FOLDER_PLANS) to avoid drift when plan tiers change.

apps/web/app/api/folders/route.ts (2)

41-41: Extract shared requiredPlan array for consistency.

The insertion of "business legacy" looks good. To reduce duplication and ensure uniform updates, factor these plan arrays into a single exported constant used by both GET and POST handlers.


143-143: Extract shared requiredPlan array for consistency.

Similarly here, the "business legacy" addition is valid. Pull the repeated plan list into a shared constant to streamline future modifications.

apps/web/app/api/folders/access-requests/route.ts (1)

25-25: Extract repeated plan lists to maintain DRY.

Including "business legacy" is correct for access requests. As the same plan sequence recurs across many endpoints, factor this into a shared REQUIRED_PLANS constant to reduce duplication.

apps/web/lib/auth/workspace.ts (1)

43-53: Add legacy plan to global workspace auth defaults
Including "business legacy" in the default requiredPlan ensures any route that doesn’t override plan checks will honor the legacy tier.

Nitpick: Consider a consistent ordering of business tiers (e.g., legacy → plus → extra → max) across all configurations for readability.

apps/web/app/(ee)/api/events/route.ts (1)

88-96: Centralize plan-gating arrays to avoid future drift

Nearly every route now repeats the same long requiredPlan literal. Consider importing a shared constant (e.g. BUSINESS_PLANS or PAID_PLANS) or a helper such as getBusinessPlans() so that adding/removing a tier only touches one file.

-import { withWorkspace } from "@/lib/auth";
+import { withWorkspace } from "@/lib/auth";
+import { BUSINESS_PLANS } from "@/lib/plans"; // ← single source-of-truth
...
-    requiredPlan: [
-      "business",
-      "business legacy",
-      "business plus",
-      "business extra",
-      "business max",
-      "advanced",
-      "enterprise",
-    ],
+    requiredPlan: BUSINESS_PLANS,
apps/web/app/(ee)/api/partners/route.ts (1)

32-39: Nit: keep plan arrays consistently ordered

Re-ordering "business plus" is harmless but makes diff-noise across routes. Adopting alphabetical or tier-ascending order (or, better, a shared constant) keeps future PRs tidy.

apps/web/lib/plan-capabilities.ts (1)

12-13: Centralise plan-exclusion lists to avoid future drift

["free", "pro", "business legacy"] is now the third hard-coded list in this file alone (see lines 8-11).
When a new tier is introduced the risk of missing one of these literals is high.

-  !!plan && !["free", "pro", "business legacy"].includes(plan),
+  !!plan && !EXCLUDED_FROM_PROGRAM.includes(plan),

…and export EXCLUDED_FROM_PROGRAM (or a more general PLAN_EXCLUSIONS) from a single source of truth under @/lib/plans.

apps/web/app/(ee)/api/stripe/integration/route.ts (1)

96-105: Duplicate requiredPlan arrays: extract a reusable constant

The same eight-item array appears in many routes. Consider:

import { BUSINESS_WRITE_PLANS } from "@/lib/plans";

// …

requiredPlan: BUSINESS_WRITE_PLANS,

A shared constant improves readability and prevents inconsistencies when plans change.

apps/web/app/(ee)/api/shopify/integration/callback/route.ts (1)

88-97: Keep plan lists consistent via a shared enum/constant

Same comment as for the Stripe route: hard-coding plan strings in every handler is brittle.

apps/web/app/(ee)/api/customers/[id]/route.ts (1)

42-50: Consolidate plan gating logic

Three identical requiredPlan blocks in one file (GET/PATCH/DELETE). Refactor to:

const CUSTOMER_PLANS = BUSINESS_WRITE_PLANS; // from shared constant

// …
requiredPlan: CUSTOMER_PLANS,

This reduces noise and keeps authorisation rules aligned across methods.

Also applies to: 143-151, 180-188

apps/web/app/api/webhooks/[webhookId]/route.ts (1)

41-49: Authorisation lists are drifting – move to config

Webhooks now have three separate copies of the plan array. A central definition (e.g., ALLOWED_WEBHOOK_PLANS) will make future tier additions a one-line change.

Also applies to: 250-259, 320-329

apps/web/app/api/webhooks/route.ts (1)

49-58: Extract plan list to a shared constant to avoid copy-paste drift

The same requiredPlan array (now with “business legacy”) appears verbatim across many endpoints. Keeping these ad-hoc lists in every route is brittle—next time a plan tier is renamed/added you must hunt through multiple files.

Consider:

-  requiredPlan: [
-    "business",
-    "business legacy",
-    "business plus",
-    "business extra",
-    "business max",
-    "advanced",
-    "enterprise",
-  ],
+  requiredPlan: ALL_BUSINESS_PLANS, // import from a single source of truth

Centralising the tiers (e.g. @/lib/plan/constants.ts) eliminates duplication and guarantees consistency.

Also applies to: 192-201

apps/web/app/(ee)/api/customers/route.ts (1)

136-144: Same plan list duplication issue as above

This route repeats the tier list twice. Please reuse the shared constant once it’s introduced to keep customer APIs in sync with other endpoints.

Also applies to: 209-217

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 71d6f50 and 9c712ea.

📒 Files selected for processing (24)
  • apps/web/app/(ee)/api/customers/[id]/route.ts (3 hunks)
  • apps/web/app/(ee)/api/customers/route.ts (2 hunks)
  • apps/web/app/(ee)/api/events/export/route.ts (1 hunks)
  • apps/web/app/(ee)/api/events/route.ts (1 hunks)
  • apps/web/app/(ee)/api/partners/count/route.ts (1 hunks)
  • apps/web/app/(ee)/api/partners/export/route.ts (1 hunks)
  • apps/web/app/(ee)/api/partners/route.ts (1 hunks)
  • apps/web/app/(ee)/api/partners/sales/route.ts (0 hunks)
  • apps/web/app/(ee)/api/shopify/integration/callback/route.ts (1 hunks)
  • apps/web/app/(ee)/api/stripe/integration/route.ts (1 hunks)
  • apps/web/app/(ee)/api/track/lead/route.ts (1 hunks)
  • apps/web/app/(ee)/api/track/sale/route.ts (1 hunks)
  • apps/web/app/api/folders/[folderId]/route.ts (3 hunks)
  • apps/web/app/api/folders/[folderId]/users/route.ts (1 hunks)
  • apps/web/app/api/folders/access-requests/route.ts (1 hunks)
  • apps/web/app/api/folders/permissions/route.ts (1 hunks)
  • apps/web/app/api/folders/route.ts (2 hunks)
  • apps/web/app/api/webhooks/[webhookId]/events/route.ts (1 hunks)
  • apps/web/app/api/webhooks/[webhookId]/route.ts (3 hunks)
  • apps/web/app/api/webhooks/route.ts (2 hunks)
  • apps/web/lib/auth/workspace.ts (1 hunks)
  • apps/web/lib/plan-capabilities.ts (1 hunks)
  • apps/web/lib/types.ts (1 hunks)
  • apps/web/scripts/framer/export-links.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/app/(ee)/api/partners/sales/route.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (9)
apps/web/app/(ee)/api/partners/count/route.ts (1)

165-165: Align plan ordering in access control.

The repositioning of "business plus" immediately after "business" matches the ordering in related partner endpoints. No functional impact detected.

apps/web/app/(ee)/api/partners/export/route.ts (1)

81-81: Align plan ordering in access control.

Moving "business plus" to follow "business" brings this export endpoint into line with the other partner routes. No issues found.

apps/web/app/api/folders/permissions/route.ts (1)

51-59:

✅ Verification successful

Add legacy business plan to folder permissions access
Including "business legacy" alongside existing business tiers correctly grants legacy customers access to folder permissions. Ensure the PlanProps union in apps/web/lib/types.ts is updated to include this new plan name.


🏁 Script executed:

#!/bin/bash
# Verify "business legacy" is present in the PlanProps type
rg -n "\"business legacy\"" apps/web/lib/types.ts

Length of output: 74


All set: “business legacy” is included
Verified that "business legacy" exists in the PlanProps union (apps/web/lib/types.ts:264). No further changes needed.

apps/web/app/(ee)/api/events/export/route.ts (1)

118-126: Include "business legacy" for event export
Adding "business legacy" here aligns this endpoint’s plan requirements with the rest of the suite.

apps/web/app/(ee)/api/track/sale/route.ts (1)

277-285: Authorize legacy business plan for sale tracking
The "business legacy" plan is now included in the POST /api/track/sale access control list, matching other endpoints.

apps/web/app/api/webhooks/[webhookId]/events/route.ts (1)

30-39: Authorize legacy business plan for webhook events
Adding "business legacy" here extends webhook event log access to legacy business customers, consistent with other API routes.

apps/web/app/api/folders/[folderId]/route.ts (1)

29-37:

✅ Verification successful

Double-check capability matrix for “business legacy”

accessLevel validation relies on getPlanCapabilities(workspace.plan).
Please verify that plan-capabilities.ts treats "business legacy" the same as current Business tiers for folder-permission management; otherwise users on this legacy tier will hit the “Upgrade to Business” error path.


🏁 Script executed:

#!/usr/bin/env bash
# Does canManageFolderPermissions include "business legacy"?
rg -A3 -n 'canManageFolderPermissions' apps/web/lib/plan-capabilities.ts

Length of output: 348


Business legacy is covered by canManageFolderPermissions
The capability is defined as:

canManageFolderPermissions: !!plan && !["free", "pro"].includes(plan)

Since "business legacy" isn’t in ["free", "pro"], it’s granted the same permissions as other business tiers. No changes required.

< 8000 summary>apps/web/lib/types.ts (1)

260-270:

❓ Verification inconclusive

plans enum extended – compile-time fallout looks good, but scan for exhaustive checks

The new literal is correctly inserted. Make sure any switch(plan) / if (…) logic that enumerates all plans now handles "business legacy" explicitly to avoid falling into default branches.


🏁 Script executed:

#!/usr/bin/env bash
# Find potentially exhaustive switches.
rg -n 'switch *\(.*plan' --glob '*.ts'

Length of output: 40


Let’s extend our search to include .tsx files and also look for any if (plan === “…”) comparisons:


🏁 Script executed:

#!/usr/bin/env bash
# Search for switch statements on `plan` in both .ts and .tsx
rg -n 'switch\s*\(\s*plan' --glob '*.{ts,tsx}'

# Search for explicit if-checks comparing `plan` to string literals
rg -n -E 'if\s*\(\s*plan\s*===\s*"' --glob '*.{ts,tsx}'

Length of output: 503


Let’s correct the quoting and include .tsx files. Also scan for any direct plan === checks:

#!/usr/bin/env bash
# Search for `switch (plan)` in .ts and .tsx
rg -n 'switch\s*\(\s*plan' --glob '*.{ts,tsx}'

# Search for explicit `if (plan === "...")` checks
rg -n 'if\s*\(\s*plan\s*===\s*"' --glob '*.{ts,tsx}'

# Catch any other direct comparisons `plan === "…"`
rg -n 'plan\s*===\s*"' --glob '*.{ts,tsx}'

Confirm exhaustive plan-based logic

I didn’t find any switch(plan) or if (plan === “…”) checks in your .ts/.tsx files—please manually verify that any places enumerating plans (e.g. via switch or if/else if) have been updated to handle the new "business legacy" value and won’t fall through to a default case.

To assist your verification, you can run:

# Look for switch statements on `plan`
rg -n 'switch\s*\(\s*plan' --glob '*.{ts,tsx}'

# Look for direct plan comparisons
rg -n 'if\s*\(\s*plan\s*===\s*' --glob '*.{ts,tsx}'
apps/web/lib/plan-capabilities.ts (1)

8-13: Confirm “business legacy” is only blocked for canManageProgram

Every other capability still grants access to the legacy tier.
Please double-check that this asymmetry is intentional; otherwise the legacy tier could unexpectedly edit folders, customers, etc.

Comment on lines +25 to +28
links.map((link) => ({
via: link.key,
parnter_id: link.partnerId,
})),
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

Typo in CSV header will break downstream consumers

parnter_id is misspelled.

-        parnter_id: link.partnerId,
+        partner_id: link.partnerId,

Fix before the CSV is consumed by external tooling.

📝 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
links.map((link) => ({
via: link.key,
parnter_id: link.partnerId,
})),
links.map((link) => ({
via: link.key,
partner_id: link.partnerId,
})),
🤖 Prompt for AI Agents
In apps/web/scripts/framer/export-links.ts around lines 25 to 28, the CSV header
key 'parnter_id' is misspelled. Correct the typo by changing 'parnter_id' to
'partner_id' to ensure downstream consumers and external tooling can correctly
process the CSV data.

Copy link
bug0-qa-agent bot commented Jun 12, 2025

🤖 Bug0 QA Agent

Here are the results of the automated tests for PR #2521:

To re-run the tests, please comment /bug0 run or push a new commit to this PR.

Copy link
bug0-qa-agent bot commented Jun 13, 2025

🤖 Bug0 QA Agent

Here are the results of the automated tests for PR #2521:

To re-run the tests, please comment /bug0 run or push a new commit to this PR.

Copy link
bug0-qa-agent bot commented Jun 15, 2025

🤖 Bug0 QA Agent

Here are the results of the automated tests for PR #2521:

To re-run the tests, please comment /bug0 run or push a new commit to this PR.

Copy link
bug0-qa-agent bot commented Jun 15, 2025

🤖 Bug0 QA Agent

Here are the results of the automated tests for PR #2521:

To re-run the tests, please comment /bug0 run or push a new commit to this PR.

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.

1 participant
0