Skip to content

Conversation

@AshishViradiya153
Copy link
Contributor

@AshishViradiya153 AshishViradiya153 commented May 8, 2025

Summary by CodeRabbit

  • New Features

    • Introduced an "Excel Advanced Mode" setting for teams, allowing enhanced processing of Excel documents.
    • Added the ability for team admins to enable or disable Excel Advanced Mode from the general settings page.
    • Included a plan-based restriction: enabling Excel Advanced Mode requires a Business plan, with an upgrade prompt for lower plans.
    • Updated forms and UI to support toggling this feature and display plan badges.
  • Bug Fixes

    • Corrected HTTP method annotations and allowed headers in team settings API endpoints.
  • Chores

    • Added database support for storing the Excel Advanced Mode setting at the team level.

@AshishViradiya153 AshishViradiya153 requested a review from mfts as a code owner May 8, 2025 21:06
@vercel
Copy link

vercel bot commented May 8, 2025

@AshishViradiya153 is attempting to deploy a commit to the mftsio Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 16, 2025

Walkthrough

The changes introduce an "Excel Advanced Mode" feature, enabling teams to toggle advanced Excel processing for sheet-type documents. This includes new API endpoints for updating the mode, schema and type updates to persist the setting, UI enhancements for toggling the feature with plan-based gating, and backend logic to handle document processing based on the mode.

Changes

File(s) / Path(s) Change Summary
prisma/schema/schema.prisma, prisma/migrations/.../migration.sql Added enableExcelAdvancedMode boolean field (default: false) to the Team model and table.
lib/types.ts Extended Team interface with optional enableExcelAdvancedMode property.
lib/documents/create-document.ts Added optional enableExcelAdvancedMode property to DocumentData type.
lib/api/documents/process-document.ts Updated processDocument to accept and process enableExcelAdvancedMode flag for sheet documents, including copying files and revalidating documents when advanced mode is enabled.
app/api/links/[id]/upload/route.ts, pages/api/teams/[teamId]/documents/index.ts Integrated team's enableExcelAdvancedMode flag into document processing when uploading/creating sheet documents.
pages/api/teams/index.ts Included enableExcelAdvancedMode in team data returned by GET endpoint and during default team creation.
pages/api/teams/[teamId]/enable-advanced-mode.ts, pages/api/teams/[teamId]/update-advanced-mode.ts Added new PATCH API routes to enable/disable or update the team's advanced Excel mode, including authorization, plan checks, document updates, and cache revalidation.
pages/api/teams/[teamId]/update-name.ts Fixed HTTP method annotation and allowed method header from POST to PATCH for accuracy.
context/team-context.tsx Added currentTeamId to context type, initial state, and provider value for easier access to the current team identifier.
components/ui/form.tsx Enhanced Form component to support checkbox (switch) input, added optional plan prop, and updated save button logic for checkboxes.
components/documents/document-header.tsx Refactored enableAdvancedExcel to use toast.promise for centralized loading, success, and error handling, removing manual try-catch and toast calls.
pages/settings/general.tsx Added UI and logic for toggling Excel Advanced Mode, including plan restriction gating, analytics, error handling, and upgrade modal integration. Refactored team name update logic into a handler function.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SettingsPage
    participant API
    participant DB

    User->>SettingsPage: Toggle "Excel Advanced Mode"
    SettingsPage->>API: PATCH /api/teams/[teamId]/update-advanced-mode
    API->>DB: Update Team.enableExcelAdvancedMode
    DB-->>API: Success/Failure
    API-->>SettingsPage: Response
    SettingsPage-->>User: Show toast / modal (if upgrade needed)
Loading
sequenceDiagram
    participant User
    participant UploadPage
    participant API
    participant DB
    participant Storage

    User->>UploadPage: Upload sheet document
    UploadPage->>API: POST /api/teams/[teamId]/documents
    API->>DB: Check Team.enableExcelAdvancedMode
    alt Advanced Mode Enabled
        API->>Storage: Copy file to bucket server
        API->>DB: Update document advanced flags and version
        API->>API: Trigger revalidation
    else
        API->>DB: Standard processing
    end
    API-->>UploadPage: Response
Loading

Poem

🐇
A toggle appears, a mode so new,
For Excel sheets, advanced things to do!
With switches and forms, and a modal or two,
Teams can now choose what magic ensues.
From backend to front, the changes are grand—
Rabbits rejoice, with spreadsheets in hand!

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

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm warn config production Use --omit=dev instead.
npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-05-16T17_10_34_305Z-debug-0.log

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.


Note

⚡️ Faster reviews with caching

CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

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

@mfts mfts left a comment

Choose a reason for hiding this comment

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

Good work on this!

@vercel
Copy link

vercel bot commented May 16, 2025

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

Name Status Preview Comments Updated (UTC)
papermark ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 16, 2025 5:17pm

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

🔭 Outside diff range comments (1)
lib/documents/create-document.ts (1)

3-48: 💡 Verification agent

🧩 Analysis chain

Consider adding the new flag to the request body.

The enableExcelAdvancedMode property has been added to the DocumentData type, but it's not included in the request body when creating a document. Consider whether this property should be passed to the API endpoint.


🏁 Script executed:

#!/bin/bash
# Search for API endpoint implementations to see if they expect this property
rg -A 10 "api/teams/\[teamId\]/documents" --type ts

Length of output: 1104


Include enableExcelAdvancedMode in the create‐document flow

We added enableExcelAdvancedMode to the DocumentData type but never send it in the POST or persist it server-side. To fully support this flag:

  • In lib/documents/create-document.ts, extend the JSON body:

       body: JSON.stringify({
         name: documentData.name,
         url: documentData.key,
         storageType: documentData.storageType,
         numPages: numPages,
         folderPathName: folderPathName,
         type: documentData.supportedFileType,
         contentType: documentData.contentType,
         createLink: createLink,
         fileSize: documentData.fileSize,
    +    enableExcelAdvancedMode: documentData.enableExcelAdvancedMode,
       }),
  • In your API handler (e.g. pages/api/teams/[teamId]/documents/index.ts or equivalent), update the POST branch to:

    1. Destructure enableExcelAdvancedMode from req.body.
    2. Persist it on the new document record.

This ensures the client sends the flag and the backend stores it.

🧹 Nitpick comments (1)
pages/api/teams/[teamId]/enable-advanced-mode.ts (1)

40-43: Input payload is not validated

enableExcelAdvancedMode is assumed to be a boolean. A typo ("tru", 1, etc.) will silently flip all sheet documents to the opposite state.
Add a runtime guard and early 400 response:

if (typeof enableExcelAdvancedMode !== "boolean") {
  return res.status(400).json({ error: "`enableExcelAdvancedMode` must be a boolean" });
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between fa0f127 and 344e7e6.

📒 Files selected for processing (15)
  • app/api/links/[id]/upload/route.ts (2 hunks)
  • components/documents/document-header.tsx (1 hunks)
  • components/ui/form.tsx (6 hunks)
  • context/team-context.tsx (2 hunks)
  • lib/api/documents/process-document.ts (4 hunks)
  • lib/documents/create-document.ts (1 hunks)
  • lib/types.ts (1 hunks)
  • pages/api/teams/[teamId]/documents/index.ts (1 hunks)
  • pages/api/teams/[teamId]/enable-advanced-mode.ts (1 hunks)
  • pages/api/teams/[teamId]/update-advanced-mode.ts (1 hunks)
  • pages/api/teams/[teamId]/update-name.ts (2 hunks)
  • pages/api/teams/index.ts (2 hunks)
  • pages/settings/general.tsx (2 hunks)
  • prisma/migrations/20250516000000_add_advanced_mode_to_team/migration.sql (1 hunks)
  • prisma/schema/schema.prisma (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
app/api/links/[id]/upload/route.ts (1)
lib/api/documents/process-document.ts (1)
  • processDocument (26-246)
context/team-context.tsx (1)
lib/types.ts (1)
  • Team (296-303)
pages/api/teams/[teamId]/update-advanced-mode.ts (4)
pages/api/teams/[teamId]/enable-advanced-mode.ts (1)
  • handle (21-135)
pages/api/teams/[teamId]/update-name.ts (1)
  • handle (10-68)
pages/api/auth/[...nextauth].ts (1)
  • authOptions (25-189)
lib/types.ts (1)
  • CustomUser (18-18)
🔇 Additional comments (28)
lib/types.ts (1)

302-302: LGTM: New team property added correctly.

Adding an optional boolean property to support Excel Advanced Mode at the team level makes sense. This property aligns with the database schema changes in the migration file.

lib/documents/create-document.ts (1)

11-11: LGTM: New document property added correctly.

The optional enableExcelAdvancedMode property has been added to support advanced Excel features for sheet-type documents. This aligns with the team-level setting and enables proper document processing based on this mode.

prisma/migrations/20250516000000_add_advanced_mode_to_team/migration.sql (1)

1-3: LGTM: Database migration is correctly implemented.

The migration adds a non-nullable boolean column with a default value of false, which ensures backward compatibility for existing teams. This aligns with the type changes in the codebase.

pages/api/teams/[teamId]/update-name.ts (2)

15-15: Corrected API method comment.

Fixed comment to accurately reflect that this is a PATCH endpoint rather than POST.


64-66: Fixed allowed methods header.

Corrected the Allow header to properly indicate PATCH is the only allowed method, which is consistent with the implementation.

prisma/schema/schema.prisma (1)

103-104: LGTM! Team setting for Excel advanced mode added correctly.

The new boolean field enableExcelAdvancedMode is properly added to the Team model with an appropriate default value of false. The comment clearly explains the purpose of this setting.

pages/api/teams/[teamId]/documents/index.ts (1)

281-283: LGTM! Excel advanced mode correctly conditionally enabled.

The implementation properly passes the team's Excel advanced mode setting to the document processing function, but only when the document is actually a sheet-type document. This conditional check ensures the setting is only applied to relevant documents.

app/api/links/[id]/upload/route.ts (3)

54-54: LGTM! Team setting selection added.

Correctly fetches the enableExcelAdvancedMode flag from the team record when querying the link.


91-95: LGTM! Excel advanced mode correctly propagated to document data.

The implementation creates a new object with all existing document data and adds the enableExcelAdvancedMode property from the team settings. The fallback to false is appropriate when the team setting isn't available.


99-100: LGTM! Updated document data passed to process function.

The updated document data with the Excel advanced mode flag is correctly passed to the processDocument function.

pages/api/teams/index.ts (2)

37-37: LGTM! Team setting included in user teams query.

The enableExcelAdvancedMode field is correctly included in the team data selection when fetching a user's teams.


70-70: LGTM! Team setting included in default team creation.

The enableExcelAdvancedMode field is correctly included in the selection when creating and returning a default team for users with no teams.

context/team-context.tsx (2)

19-19: LGTM: Adding currentTeamId to TeamContextType

This properly extends the context type to include the current team ID as a direct property.


27-27: LGTM: Setting appropriate initial state

The initial state correctly sets currentTeamId to null, matching the type definition.

components/documents/document-header.tsx (1)

289-312: Improved error handling with toast.promise

The refactoring to use toast.promise creates more consistent error handling and reduces code duplication. This is a good improvement that aligns with how other API calls are handled in this file.

components/ui/form.tsx (7)

14-15: LGTM: Importing PlanBadge for plan-based feature gating

This import supports showing plan badges in the form for plan-restricted features.


25-26: LGTM: Adding Label and Switch imports

These imports are needed for the new checkbox input type implementation.


38-39: LGTM: Adding plan prop to Form component

This properly extends the Form component to support displaying plan badges with form fields.

Also applies to: 49-50


58-66: LGTM: Updated saveDisabled logic for checkbox inputs

The saveDisabled logic now correctly handles checkbox input types by comparing boolean values.


68-109: LGTM: Added renderInput function

The new renderInput function elegantly handles conditional rendering of different input types.


129-131: LGTM: Updated CardTitle to show plan badge

The CardTitle now conditionally displays a PlanBadge when the plan prop is provided.


136-137: LGTM: Using renderInput

Replaced inline JSX with the new renderInput function call for better code organization.

lib/api/documents/process-document.ts (3)

4-4: LGTM: Importing copyFileToBucketServer

This import is necessary for the new advanced Excel mode functionality.


43-44: LGTM: Extracting enableExcelAdvancedMode from documentData

Properly destructuring the new flag from the DocumentData parameter.


90-91: LGTM: Setting advancedExcelEnabled in document creation

The document creation properly persists the Excel advanced mode setting.

pages/api/teams/[teamId]/enable-advanced-mode.ts (1)

80-88: Primary version existence is not guaranteed

const primaryVersion = doc.versions[0]; can be undefined (e.g., a sheet without a primary version).
When that happens, the document is skipped entirely, leaving its advancedExcelEnabled flag inconsistent with the team setting.

At minimum log / surface this case or filter the initial query to ensure versions is non-empty:

where: {
  teamId: teamId as string,
  type: "sheet",
  advancedExcelEnabled: !enableExcelAdvancedMode,
+ versions: { some: { isPrimary: true, type: "sheet" } },  // guarantees at least one
},
pages/settings/general.tsx (2)

45-60: Error-handling assumes { error: { message } } – breaks on string responses

/api/teams/[teamId]/update-advanced-mode currently returns a string on success and possibly on failure.
await res.json() will parse correctly, but destructuring { error } and then reading error.message throws when error is a plain string.

Defensive fix:

- const { error } = await res.json();
- throw new Error(error.message);
+ const payload = await res.json();
+ if (typeof payload === "string") {
+   throw new Error(payload);
+ }
+ throw new Error(payload?.error ?? "Unknown server error");

32-38: Double gating: move “free-plan” check to UI layer only

You already disable the toggle visually via the plan prop and show the upgrade modal.
Keeping this early-return here is fine, but remember that the backend still must enforce plan limits; otherwise a crafted request enables the feature. Verify the server route mirrors this logic (see previous comment).

currentTeam:
(teams || []).find((team) => team.id === currentTeamId) ||
(teams || [])[0],
currentTeamId,
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add currentTeamId to useMemo dependencies

The context value now includes currentTeamId, but this value is not included in the dependency array on line 58.

  const value = useMemo(
    () => ({
      teams: teams || [],
      currentTeam:
        (teams || []).find((team) => team.id === currentTeamId) ||
        (teams || [])[0],
      currentTeamId,
      isLoading: loading,
      setCurrentTeam,
    }),
-    [teams, currentTeam, loading],
+    [teams, currentTeam, loading, currentTeamId, setCurrentTeam],
  );
📝 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
currentTeamId,
const value = useMemo(
() => ({
teams: teams || [],
currentTeam:
(teams || []).find((team) => team.id === currentTeamId) ||
(teams || [])[0],
currentTeamId,
isLoading: loading,
setCurrentTeam,
}),
[teams, currentTeam, loading, currentTeamId, setCurrentTeam],
);
🤖 Prompt for AI Agents
In context/team-context.tsx at line 54, the currentTeamId is included in the
context value but is missing from the useMemo dependency array around line 58.
Add currentTeamId to the dependency array of the useMemo hook to ensure the
memoized value updates correctly when currentTeamId changes.

Comment on lines +205 to +224
if (type === "sheet" && enableExcelAdvancedMode) {
await copyFileToBucketServer({
filePath: document.versions[0].file,
storageType: document.versions[0].storageType,
});

await prisma.documentVersion.update({
where: { id: document.versions[0].id },
data: { numPages: 1 },
});

try {
await fetch(
`${process.env.NEXTAUTH_URL}/api/revalidate?secret=${process.env.REVALIDATE_TOKEN}&documentId=${document.id}`,
);
} catch (error) {
console.error("Failed to revalidate document:", error);
// The document is still updated, so we can continue without throwing
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add environment variable validation for revalidation URL

The implementation for the Excel advanced mode looks good overall, but there's a potential issue with the revalidation URL. The code uses process.env.NEXTAUTH_URL without checking if it's defined.

if (type === "sheet" && enableExcelAdvancedMode) {
  await copyFileToBucketServer({
    filePath: document.versions[0].file,
    storageType: document.versions[0].storageType,
  });

  await prisma.documentVersion.update({
    where: { id: document.versions[0].id },
    data: { numPages: 1 },
  });

  try {
+   const revalidateUrl = process.env.NEXTAUTH_URL;
+   if (!revalidateUrl) {
+     console.error("NEXTAUTH_URL is not defined, skipping revalidation");
+     return document;
+   }
    await fetch(
-     `${process.env.NEXTAUTH_URL}/api/revalidate?secret=${process.env.REVALIDATE_TOKEN}&documentId=${document.id}`,
+     `${revalidateUrl}/api/revalidate?secret=${process.env.REVALIDATE_TOKEN}&documentId=${document.id}`,
    );
  } catch (error) {
    console.error("Failed to revalidate document:", error);
    // The document is still updated, so we can continue without throwing
  }
}
📝 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
if (type === "sheet" && enableExcelAdvancedMode) {
await copyFileToBucketServer({
filePath: document.versions[0].file,
storageType: document.versions[0].storageType,
});
await prisma.documentVersion.update({
where: { id: document.versions[0].id },
data: { numPages: 1 },
});
try {
await fetch(
`${process.env.NEXTAUTH_URL}/api/revalidate?secret=${process.env.REVALIDATE_TOKEN}&documentId=${document.id}`,
);
} catch (error) {
console.error("Failed to revalidate document:", error);
// The document is still updated, so we can continue without throwing
}
}
if (type === "sheet" && enableExcelAdvancedMode) {
await copyFileToBucketServer({
filePath: document.versions[0].file,
storageType: document.versions[0].storageType,
});
await prisma.documentVersion.update({
where: { id: document.versions[0].id },
data: { numPages: 1 },
});
try {
const revalidateUrl = process.env.NEXTAUTH_URL;
if (!revalidateUrl) {
console.error("NEXTAUTH_URL is not defined, skipping revalidation");
return document;
}
await fetch(
`${revalidateUrl}/api/revalidate?secret=${process.env.REVALIDATE_TOKEN}&documentId=${document.id}`,
);
} catch (error) {
console.error("Failed to revalidate document:", error);
// The document is still updated, so we can continue without throwing
}
}
🤖 Prompt for AI Agents
In lib/api/documents/process-document.ts around lines 205 to 224, the code uses
process.env.NEXTAUTH_URL directly in the revalidation URL without verifying if
it is defined, which can cause runtime errors. Add a check to ensure
process.env.NEXTAUTH_URL is defined before using it in the fetch call. If it is
undefined, handle the case gracefully by either skipping the fetch or logging a
warning, to prevent potential failures.

Comment on lines +60 to +115
const result = await prisma.$transaction(async (tx) => {
// Get all Excel documents in the team that need to be updated
const documents = await tx.document.findMany({
where: {
teamId: teamId as string,
type: "sheet",
advancedExcelEnabled: !enableExcelAdvancedMode,
},
include: {
versions: {
where: {
isPrimary: true,
type: "sheet",
},
},
},
});

// Update all documents and their versions
const updatePromises = documents.map(async (doc) => {
const primaryVersion = doc.versions[0];
if (!primaryVersion) return;

if (enableExcelAdvancedMode) {
// Copy file to bucket if enabling advanced mode
await copyFileToBucketServer({
filePath: primaryVersion.file,
storageType: primaryVersion.storageType,
});

// Update document and version when enabling
await Promise.all([
tx.document.update({
where: { id: doc.id },
data: { advancedExcelEnabled: true },
}),
tx.documentVersion.update({
where: { id: primaryVersion.id },
data: { numPages: 1 },
}),
]);
} else {
await tx.document.update({
where: { id: doc.id },
data: { advancedExcelEnabled: false },
});
}

// Revalidate the document
await fetch(
`${process.env.NEXTAUTH_URL}/api/revalidate?secret=${process.env.REVALIDATE_TOKEN}&documentId=${doc.id}`,
);
});

await Promise.all(updatePromises);
const updatedTeam = await tx.team.update({
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid non-DB side-effects inside a Prisma transaction

copyFileToBucketServer (network / storage I/O) and the fetch(.../revalidate) call are executed inside the $transaction closure.
Because they are not part of the database, two issues arise:

  1. If one of those side-effects succeeds but a later DB query fails, the SQL transaction will roll back while the external side-effects remain → inconsistent state (orphaned files, premature cache re-validation).
  2. The long-running I/O keeps the DB transaction open, increasing lock-time and contention risk.

Consider this safer flow:

// 1.  Gather ids / versions that need work  ➜  tx only
- const result = await prisma.$transaction(async (tx) => {
+ const {team, affectedDocs} = await prisma.$transaction(async (tx) => {
     ...
-     // do NOT call copyFileToBucketServer or fetch here
      return { team: updatedTeam, affectedDocs: documents.map(d => ({ id: d.id, file: d.versions[0]?.file, storageType: d.versions[0]?.storageType })) }
});

+// 2.  Perform external work after commit
+await Promise.all(
+  affectedDocs.map(async (d) => {
+     if (enableExcelAdvancedMode && d.file) {
+        await copyFileToBucketServer({ filePath: d.file, storageType: d.storageType });
+     }
+     await fetch(`${process.env.NEXTAUTH_URL}/api/revalidate?secret=${process.env.REVALIDATE_TOKEN}&documentId=${d.id}`);
+  })
+);

This guarantees DB integrity and keeps the SQL lock window minimal.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In pages/api/teams/[teamId]/enable-advanced-mode.ts between lines 60 and 115,
the calls to copyFileToBucketServer and fetch for revalidation are inside the
Prisma $transaction, causing side-effects during the DB transaction. To fix
this, move all non-database side-effect operations like file copying and HTTP
fetch calls outside and after the $transaction block. First, perform all
database updates within the transaction, then sequentially execute the external
side-effects to avoid inconsistent states and reduce DB lock duration.

Comment on lines +45 to +47
if (!team || team.plan.includes("free")) {
return res.status(401).json({ error: "Unauthorized" });
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Plan check may throw when plan is null and is case-sensitive

team.plan.includes("free"):

  1. Throws if plan is null.
  2. Fails silently if plans are stored as "Free" / enum values.

Prefer a strict comparison against your existing PlanEnum:

-import { PlanEnum } from "@/ee/stripe/constants";
 ...
-if (!team || team.plan.includes("free")) {
+if (!team || team.plan === PlanEnum.Free) {
   return res.status(401).json({ error: "Unauthorized" });
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In pages/api/teams/[teamId]/update-advanced-mode.ts around lines 45 to 47, the
current check team.plan.includes("free") can throw an error if plan is null and
is case-sensitive, which may cause incorrect authorization logic. To fix this,
first ensure plan is not null before checking its value, and replace the
includes check with a strict comparison against the PlanEnum values, handling
case sensitivity properly. This will prevent runtime errors and ensure accurate
plan validation.

Comment on lines +35 to +44
const team = await prisma.team.findUnique({
where: {
id: teamId,
users: {
some: {
userId: (session.user as CustomUser).id,
},
},
},
});
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

findUnique with relation filters is invalid – compilation will fail

findUnique only supports unique scalar fields. Passing users: { some: ... } will raise a Prisma type error.

- const team = await prisma.team.findUnique({
+ const team = await prisma.team.findFirst({
   where: {
     id: teamId,
     users: {
       some: {
         userId: (session.user as CustomUser).id,
       },
     },
   },
 });
📝 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
const team = await prisma.team.findUnique({
where: {
id: teamId,
users: {
some: {
userId: (session.user as CustomUser).id,
},
},
},
});
const team = await prisma.team.findFirst({
where: {
id: teamId,
users: {
some: {
userId: (session.user as CustomUser).id,
},
},
},
});
🤖 Prompt for AI Agents
In pages/api/teams/[teamId]/update-advanced-mode.ts around lines 35 to 44, the
use of findUnique with a relation filter on users is invalid and causes a
compilation error. Replace findUnique with findFirst to allow filtering by
related users. Adjust the query to use findFirst with the same where clause
including the users.some condition to correctly filter teams by teamId and user
membership.

@mfts mfts merged commit 0ed0472 into mfts:main May 16, 2025
4 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators May 16, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants