Skip to content

Comments

Brief my meeting onboarding#1138

Merged
elie222 merged 14 commits intomainfrom
feat/brief-my-meeting-onboarding
Dec 30, 2025
Merged

Brief my meeting onboarding#1138
elie222 merged 14 commits intomainfrom
feat/brief-my-meeting-onboarding

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Dec 29, 2025

User description

Note

Introduces a dedicated, 3-step Meeting Briefs onboarding.

  • New onboarding-brief flow: StepConnectCalendar, StepSendTestBrief (pick upcoming event, trigger sendBriefAction), and StepReady (pricing summary, Gmail link); rendered via MeetingBriefsOnboardingContent and page files for app/landing
  • Onboarding changes: when utm_source=briefmymeeting (unless force), redirect to /[emailAccountId]/onboarding-brief
  • UTM tracking: new registerUtmTracking helper wraps after() and returns parsed UTM values; adopted in onboarding pages
  • Pricing refactor: extracted PricingFrequencyToggle and DiscountBadge, added frequency query param handling, and typed Frequency; updated Pricing/PriceTier to use them
  • Billing config: added legacy Stripe price IDs for "brief my meeting" to map subscriptions correctly
  • Navigation/layout: removed beta badge from Meeting Briefs item; SideNavWithTopNav hides sidebars on onboarding-brief routes

Written by Cursor Bugbot for commit ae28f6d. Configure here.


Generated description

Below is a concise technical summary of the changes proposed in this PR:

graph LR
handleCheckout_("handleCheckout"):::added
generateCheckoutSession_("generateCheckoutSession"):::modified
stripe_("stripe"):::modified
SafeError_("SafeError"):::modified
trackStripeCustomerCreated_("trackStripeCustomerCreated"):::modified
trackStripeCheckoutCreated_("trackStripeCheckoutCreated"):::modified
StepReady_("StepReady"):::added
PricingFrequencyToggle_("PricingFrequencyToggle"):::added
MeetingBriefsOnboardingContent_("MeetingBriefsOnboardingContent"):::added
StepConnectCalendar_("StepConnectCalendar"):::added
StepSendTestBrief_("StepSendTestBrief"):::added
handleCheckout_ -- "Adds priceId param to generateCheckoutSession call." --> generateCheckoutSession_
generateCheckoutSession_ -- "Creates Stripe customers and sessions with tracking." --> stripe_
generateCheckoutSession_ -- "Throws controlled errors for invalid tier or user." --> SafeError_
generateCheckoutSession_ -- "Logs analytics after creating Stripe customer." --> trackStripeCustomerCreated_
generateCheckoutSession_ -- "Logs analytics after creating Stripe checkout session." --> trackStripeCheckoutCreated_
StepReady_ -- "Adds billing frequency toggle for subscription pricing." --> PricingFrequencyToggle_
MeetingBriefsOnboardingContent_ -- "Calls calendar connection step in onboarding." --> StepConnectCalendar_
MeetingBriefsOnboardingContent_ -- "Calls test brief sending step in onboarding." --> StepSendTestBrief_
classDef added stroke:#15AA7A
classDef removed stroke:#CD5270
classDef modified stroke:#EDAC4C
linkStyle default stroke:#CBD5E1,font-size:13px
Loading

Introduce a dedicated three-step onboarding flow for 'Meeting Briefs', guiding users through calendar connection, sending a test brief, and reviewing subscription options. Integrate this new flow by conditionally redirecting users based on UTM parameters, refactor pricing components for reusability, and update billing configurations to support the new offering.

TopicDetails
Meeting Briefs Onboarding Implement a new, dedicated 3-step onboarding experience for 'Meeting Briefs'. This flow includes StepConnectCalendar for calendar integration, StepSendTestBrief to allow users to send a sample brief, and StepReady which presents pricing information and a call to action. The system now redirects users to this specific onboarding path when the utm_source is briefmymeeting, and the navigation layout is adjusted to accommodate these new onboarding routes.
Modified files (12)
  • apps/web/utils/calendar/constants.ts
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/components/SideNav.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
Latest Contributors(2)
UserCommitDate
elie222remove-description-fro...November 28, 2025
eduardoleliss@gmail.comPR-feedbackOctober 10, 2025
Premium & Tracking Updates Enhance the premium subscription and tracking infrastructure by refactoring pricing components into reusable PricingFrequencyToggle and DiscountBadge components. Update the Pricing page to utilize these new components and add specific Stripe price IDs for the 'Brief My Meeting' offering. Modify the generateCheckoutSessionAction to support an optional priceId for more flexible checkout flows. Additionally, introduce a centralized registerUtmTracking helper to streamline UTM value extraction and storage across onboarding pages.
Modified files (5)
  • apps/web/utils/actions/premium.ts
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
Latest Contributors(1)
UserCommitDate
elie222Onboarding-flow-for-se...December 01, 2025
UI/UX Refinements Refine the user interface by updating icon sizing from h-4 w-4 to size-4 for consistency and changing the text 'Transfer rules to...' to 'Copy rules to...' in the account options dropdown.
Modified files (1)
  • apps/web/app/(app)/accounts/page.tsx
Latest Contributors(1)
UserCommitDate
elie222Fix-account-clickDecember 19, 2025
This pull request is reviewed by Baz. Review like a pro on (Baz).

@vercel
Copy link

vercel bot commented Dec 29, 2025

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

Project Deployment Review Updated (UTC)
inbox-zero Ready Ready Preview Dec 30, 2025 0:19am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 29, 2025

Warning

Rate limit exceeded

@elie222 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 19 minutes and 59 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between bc0e756 and 4e8527f.

📒 Files selected for processing (1)
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Adds a three-step Meeting Briefs onboarding flow (calendar connect, send test brief, readiness/checkout), pages/routes, pricing toggle and discount badge, UTM tracking consolidation via registerUtmTracking, optional priceId support in checkout action, Stripe price IDs for “Brief My Meeting”, and small navigation metadata updates.

Changes

Cohort / File(s) Summary
Onboarding flow components
apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx, apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx, apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx, apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
New client components implementing a 3-step onboarding: orchestrator clamps step and navigates; StepConnectCalendar checks calendars and advances or shows ConnectCalendar; StepSendTestBrief lists upcoming events, sends a test brief and advances; StepReady shows pricing, frequency toggle, and checkout flow.
Onboarding pages / routing
apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx, apps/web/app/(landing)/onboarding-brief/page.tsx
Adds server page that parses step, registers UTMs, and renders onboarding content inside Suspense; landing route redirects to per-account onboarding path.
UTM tracking refactor
apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx, apps/web/app/(landing)/welcome/utms.tsx
Consolidates UTM handling into registerUtmTracking(authPromise, cookieStore), replaces prior extract/store pattern, and adds early redirect to /[emailAccountId]/onboarding-brief when utm_source=briefmymeeting (unless forced).
Pricing UI & toggle
apps/web/app/(app)/premium/PricingFrequencyToggle.tsx, apps/web/app/(app)/premium/Pricing.tsx
New reusable PricingFrequencyToggle, frequencies, Frequency type and DiscountBadge; Pricing page updated to use shared toggle and badge; PriceTier prop type updated to use Frequency.
Billing action signature
apps/web/utils/actions/premium.ts
generateCheckoutSessionAction input schema extended to accept optional priceId; logic updated to prefer provided priceId over tier-derived price ID, with adjusted Stripe customer creation and profile updates. getBillingPortalUrlAction continues to accept optional tier.
Stripe price config
apps/web/app/(app)/premium/config.ts
Adds BRIEF_MY_MEETING_PRICE_ID_MONTHLY and BRIEF_MY_MEETING_PRICE_ID_ANNUALLY and includes them in STRIPE price id arrays.
Calendar onboarding return
apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx, apps/web/app/(app)/[emailAccountId]/calendars/page.tsx, apps/web/utils/calendar/constants.ts
ConnectCalendar accepts optional onboardingReturnPath and sets a return cookie; calendars page reads and validates that cookie and redirects if valid; new CALENDAR_ONBOARDING_RETURN_COOKIE constant added.
Navigation & small UI tweaks
apps/web/components/SideNav.tsx, apps/web/components/SideNavWithTopNav.tsx, apps/web/app/(app)/accounts/page.tsx
Removed beta flag from Meeting Briefs nav item; SideNavWithTopNav early-return condition extended to include onboarding-brief for two-segment URLs; minor icon size and copy tweaks in accounts page.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ServerPage as Onboarding Page (server)
    participant Browser as Client/Router
    participant Step1 as StepConnectCalendar (client)
    participant Calendars as Calendars Hook/API
    participant Step2 as StepSendTestBrief (client)
    participant Events as Events Hook/API
    participant Step3 as StepReady (client)
    participant CheckoutAction as generateCheckoutSessionAction

    User->>ServerPage: GET /{emailAccountId}/onboarding-brief?step=1
    ServerPage-->>Browser: render MeetingBriefsOnboardingContent (step=1)

    Browser->>Step1: mount -> useCalendars()
    Step1->>Calendars: fetch connections
    alt calendar connected
        Calendars-->>Step1: connected
        Step1->>Browser: router.push(step=2)
    else not connected
        Step1-->>User: show ConnectCalendar
        User->>Step1: connect -> onNext -> Browser navigates step=2
    end

    Browser->>Step2: mount -> useCalendarUpcomingEvents()
    Step2->>Events: fetch events
    Events-->>Step2: events list
    User->>Step2: select event & Send Test Brief
    Step2->>Step2: invoke sendBriefAction -> success
    Step2-->>Browser: after success router.push(step=3)

    Browser->>Step3: mount (pricing)
    User->>Step3: Start Free Trial (choose frequency)
    Step3->>CheckoutAction: request checkout (priceId or tier)
    CheckoutAction-->>Step3: returns checkout URL
    Step3->>Browser: redirect to Stripe checkout
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hop through steps with a tiny chart,
Calendars sync and test briefs start,
Toggle the price, the badge gleams bright,
I press "Start Trial" and bound to checkout flight. ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Brief my meeting onboarding' clearly describes the main change: implementing a new 3-step onboarding flow for the Meeting Briefs feature. It directly aligns with the core objective of the PR.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@macroscopeapp
Copy link
Contributor

macroscopeapp bot commented Dec 29, 2025

Add a 3-step meeting briefs onboarding flow and set a 180s apps/web/utils/calendar/constants.ts::CALENDAR_ONBOARDING_RETURN_COOKIE during calendar connect to return users to onboarding

Introduce /[emailAccountId]/onboarding-brief with step-based components, add cookie-based return handling in calendar connect and redirect on the calendars page when the cookie is present, and route users with utm_source=briefmymeeting to the new onboarding.

📍Where to Start

Start with the onboarding entry in apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx, then review cookie set/read logic in apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx and apps/web/app/(app)/[emailAccountId]/calendars/page.tsx.


Macroscope summarized 4e8527f.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This is the final PR Bugbot will review for you during this billing cycle

Your free Bugbot reviews will reset on January 28

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
apps/web/components/SideNavWithTopNav.tsx (1)

60-64: Logic correctly extends onboarding path handling.

The addition of "onboarding-brief" to the early-return condition is functionally correct and aligns with the new onboarding flow. The logic safely checks for two-segment paths and renders children directly for both onboarding variants.

Optional: Extract onboarding paths to a constant

While you've noted this is temporary code (line 57), consider extracting the path segments to a constant for easier maintenance:

+ const ONBOARDING_PATHS = ["onboarding", "onboarding-brief"];
+
  // Ugly code. May change the onboarding path later so we don't need to do this.
  // Only return children for the main onboarding page: /[emailAccountId]/onboarding
  const segments = pathname.split("/").filter(Boolean);
  if (
    segments.length === 2 &&
-   (segments[1] === "onboarding" || segments[1] === "onboarding-brief")
+   ONBOARDING_PATHS.includes(segments[1])
  )
    return children;

This makes it easier to add or modify onboarding paths in the future.

apps/web/app/(landing)/onboarding-brief/page.tsx (1)

1-5: LGTM! Clean redirect implementation.

The redirect logic is correct and appropriately delegates to the redirectToEmailAccountPath utility. The implementation follows Next.js App Router patterns and maintains good separation of concerns.


Optional enhancement: Consider adding metadata for SEO, though it's not critical for a redirect-only page:

Optional metadata export
 import { redirectToEmailAccountPath } from "@/utils/account";
+import type { Metadata } from "next";
+
+export const metadata: Metadata = {
+  title: "Meeting Briefs Onboarding",
+};

 export default async function OnboardingBriefPage() {
   await redirectToEmailAccountPath("/onboarding-brief");
 }
apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx (1)

26-33: Unnecessary async keyword.

The onNext callback doesn't use await, so the async keyword is redundant and can be removed for clarity.

🔎 Suggested fix
-  const onNext = useCallback(async () => {
+  const onNext = useCallback(() => {
     if (clampedStep < TOTAL_STEPS) {
       const nextStep = clampedStep + 1;
       router.push(
         prefixPath(emailAccountId, `/onboarding-brief?step=${nextStep}`),
       );
     }
   }, [router, emailAccountId, clampedStep]);
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx (1)

69-79: Hardcoded pricing values may become stale.

The prices ($7.50, $9, $90/year) are hardcoded rather than derived from a configuration. If these are intentionally separate from the main pricing tiers, consider extracting them to a config constant for easier maintenance.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 63cdef1 and ae28f6d.

📒 Files selected for processing (13)
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/components/SideNav.tsx
  • apps/web/components/SideNavWithTopNav.tsx
💤 Files with no reviewable changes (1)
  • apps/web/components/SideNav.tsx
🧰 Additional context used
📓 Path-based instructions (19)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)

**/*.{ts,tsx}: For API GET requests to server, use the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

**/*.{ts,tsx}: For early access feature flags, create hooks using the naming convention use[FeatureName]Enabled that return a boolean from useFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming convention use[FeatureName]Variant that define variant types, use useFeatureFlagVariantKey() with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g., inbox-cleaner, pricing-options-2)
Always define types for A/B test variant flags (e.g., type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array<T> consistently
Initialize each enum member value explicitly
Use export type for types
Use `impo...

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
apps/web/app/(app)/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)

apps/web/app/(app)/**/*.{ts,tsx}: Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
If we're in a deeply nested component we will use swr to fetch via API
If you need to use onClick in a component, that component is a client component and file must start with use client

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)

Always import Prisma enums from @/generated/prisma/enums instead of @/generated/prisma/client to avoid Next.js bundling errors in client components

Import Prisma using the project's centralized utility: import prisma from '@/utils/prisma'

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Use next/image package for images
For API GET requests to server, use the swr package with hooks like useSWR to fetch data
For text inputs, use the Input component with registerProps for form integration and error handling

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
**/*.{tsx,ts,css}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.tsx: Use the LoadingContent component to handle loading states instead of manual loading state management
For text areas, use the Input component with type='text', autosizeTextarea prop set to true, and registerProps for form integration

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like <marquee> or <blink>
Only use the scope prop on <th> elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include a title element for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a lang attribute on the html element
Always include a title attribute for iframe elements
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
Don't use the return value of React.render
Make sure all dependencies are correctly specified in React hooks
Make sure all React hooks are called from the top level of component functions
Don't forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use both children and dangerouslySetInnerHTML props on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use <>...</> instead of <Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't use target="_blank" without rel="noopener"
Don't use <img> elements in Next.js projects
Don't use <head> elements in Next.js projects

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
!(pages/_document).{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

Don't use the next/head module in pages/_document.js on Next.js projects

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx,js,jsx}: Use @/ path aliases for imports from project root
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
apps/web/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
apps/web/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{tsx,jsx}: Follow tailwindcss patterns with prettier-plugin-tailwindcss for class sorting
Prefer functional components with hooks in React
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach in components
Follow consistent naming conventions using PascalCase for components
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Use result?.serverError with toastError and toastSuccess for error handling in forms

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Format code with Prettier

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/premium/PricingFrequencyToggle.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
apps/web/components/**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)

Use LoadingContent component to consistently handle loading and error states, passing loading, error, and children props

Use PascalCase for component file names (e.g., components/Button.tsx)

Files:

  • apps/web/components/SideNavWithTopNav.tsx
**/{pages,routes,components}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/gmail-api.mdc)

Never call Gmail API directly from routes or components - always use wrapper functions from the utils folder

Files:

  • apps/web/components/SideNavWithTopNav.tsx
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/security.mdc)

**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma's select option. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. All findUnique/findFirst calls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
All findMany queries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g., emailAccount: { id: emailAccountId }) to validate ownership

Files:

  • apps/web/app/(app)/premium/config.ts
apps/web/**/*.{example,ts,json}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Add environment variables to .env.example, env.ts, and turbo.json

Files:

  • apps/web/app/(app)/premium/config.ts
🧠 Learnings (38)
📚 Learning: 2025-07-08T13:14:07.449Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 537
File: apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx:30-34
Timestamp: 2025-07-08T13:14:07.449Z
Learning: The clean onboarding page in apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx is intentionally Gmail-specific and should show an error for non-Google email accounts rather than attempting to support multiple providers.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Components with `onClick` handlers must be client components marked with the `use client` directive

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure all anchors are valid and navigable

Applied to files:

  • apps/web/components/SideNavWithTopNav.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Don't use unnecessary fragments

Applied to files:

  • apps/web/components/SideNavWithTopNav.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/**/*.{ts,tsx} : Components for the page are either put in `page.tsx`, or in the `apps/web/app/(app)/PAGE_NAME` folder

Applied to files:

  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/components/ui/**/*.tsx : Shadcn UI components are located in `components/ui` directory

Applied to files:

  • apps/web/components/SideNavWithTopNav.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/app/**/*.{ts,tsx} : Follow NextJS app router structure with (app) directory

Applied to files:

  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/app/**/[!.]*/route.{ts,tsx} : Use kebab-case for route directories in Next.js App Router (e.g., `api/hello-world/route`)

Applied to files:

  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*.tsx : Use `LoadingContent` component to consistently handle loading and error states, passing `loading`, `error`, and `children` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use LoadingContent component for async data with loading and error states

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Use the `LoadingContent` component to handle loading states

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `withAuth` middleware for user-level operations (user settings, API keys, referrals) - provides only `userId` in `request.auth`

Applied to files:

  • apps/web/app/(landing)/welcome/utms.tsx
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/{app,pages}/**/{route,+page}.{ts,tsx} : Use middleware wrappers (withError, withAuth, withEmailAccount, withEmailProvider) that automatically create loggers with request context in API routes

Applied to files:

  • apps/web/app/(landing)/welcome/utms.tsx
📚 Learning: 2025-11-25T14:42:16.602Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-25T14:42:16.602Z
Learning: The `utils` folder contains core app logic such as Next.js Server Actions and Gmail API requests

Applied to files:

  • apps/web/app/(landing)/welcome/utms.tsx
📚 Learning: 2025-11-25T14:42:11.919Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-25T14:42:11.919Z
Learning: Applies to utils/**/*.{js,ts,jsx,tsx} : The `utils` folder contains core app logic such as Next.js Server Actions and Gmail API requests

Applied to files:

  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/app/api/**/*.ts : Use `withAuth` middleware for user-level operations such as user settings, API keys, and referrals that use only `userId`

Applied to files:

  • apps/web/app/(landing)/welcome/utms.tsx
📚 Learning: 2025-11-25T14:37:11.434Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/get-api-route.mdc:0-0
Timestamp: 2025-11-25T14:37:11.434Z
Learning: Applies to **/app/**/route.ts : Always wrap GET API route handlers with `withAuth` or `withEmailAccount` middleware for consistent error handling and authentication in Next.js App Router

Applied to files:

  • apps/web/app/(landing)/welcome/utms.tsx
  • apps/web/app/(landing)/onboarding-brief/page.tsx
📚 Learning: 2025-06-05T09:49:12.168Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 485
File: apps/web/app/(landing)/login/page.tsx:41-43
Timestamp: 2025-06-05T09:49:12.168Z
Learning: In Next.js App Router, components that use the `useSearchParams` hook require a Suspense boundary to handle the asynchronous nature of search parameter access. The Suspense wrapper is necessary and should not be removed when a component uses useSearchParams.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-08-10T22:03:30.507Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 667
File: apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx:18-25
Timestamp: 2025-08-10T22:03:30.507Z
Learning: In Next.js 15, both `params` and `searchParams` passed to page components in the App Router are Promises that need to be awaited. They should be typed as `Promise<{...}>` and accessed using `await` in server components or React's `use()` hook in client components. This is different from Next.js 14 where they were plain objects.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For API get requests to server, use the `swr` package with `useSWR` hook

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
  • apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*{.action,.server}.{ts,tsx} : For mutating data, use Next.js server actions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.{tsx,ts} : For API GET requests to server, use the `swr` package with hooks like `useSWR` to fetch data

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
📚 Learning: 2025-11-25T14:36:36.276Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:36.276Z
Learning: For mutating data, use Next.js server actions instead of SWR

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to !(pages/_document).{jsx,tsx} : Don't use the next/head module in pages/_document.js on Next.js projects

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/*/page.tsx : Create new pages at `apps/web/app/(app)/PAGE_NAME/page.tsx`

Applied to files:

  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/page.tsx : Create new pages at `apps/web/app/(app)/PAGE_NAME/page.tsx`

Applied to files:

  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/app/(app)/*/page.tsx : Create new pages at `apps/web/app/(app)/PAGE_NAME/page.tsx` with components either colocated in the same folder or in `page.tsx`

Applied to files:

  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : Components for pages are either put in `page.tsx`, or in the `apps/web/app/(app)/PAGE_NAME` folder

Applied to files:

  • apps/web/app/(landing)/onboarding-brief/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/*/page.tsx : Pages are Server components so you can load data into them directly

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/app/*/page.tsx : Pages must be Server components that load data directly

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:32.328Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-11-25T14:38:32.328Z
Learning: Applies to **/*.{ts,tsx} : Always define types for A/B test variant flags (e.g., `type PricingVariant = "control" | "variant-a" | "variant-b"`) and provide type safety through type casting

Applied to files:

  • apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : If you need to use `onClick` in a component, that component must be a client component and file must start with `use client` directive

Applied to files:

  • apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Prefer functional components with hooks in React

Applied to files:

  • apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/**/*.{ts,tsx} : If you need to use `onClick` in a component, that component is a client component and file must start with `use client`

Applied to files:

  • apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2024-08-23T11:37:26.779Z
Learnt from: aryanprince
Repo: elie222/inbox-zero PR: 210
File: apps/web/app/(app)/stats/NewsletterModal.tsx:2-4
Timestamp: 2024-08-23T11:37:26.779Z
Learning: `MoreDropdown` is a React component and `useUnsubscribeButton` is a custom React hook, and they should not be imported using `import type`.

Applied to files:

  • apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/hooks/use*.ts : Use SWR hooks for client-side data fetching, with hooks stored in `apps/web/hooks/use*.ts` that return typed responses from GET API routes

Applied to files:

  • apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use React Hook Form with Zod validation for form handling

Applied to files:

  • apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/hooks/**/*.{ts,tsx} : Use SWR for client-side data fetching with type-safe response types from GET API routes

Applied to files:

  • apps/web/app/(app)/premium/Pricing.tsx
🧬 Code graph analysis (8)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx (2)
apps/web/hooks/useCalendars.ts (1)
  • useCalendars (4-6)
apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx (1)
  • ConnectCalendar (12-111)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx (5)
apps/web/providers/EmailAccountProvider.tsx (1)
  • useAccount (79-89)
apps/web/app/(app)/[emailAccountId]/onboarding/OnboardingWrapper.tsx (1)
  • OnboardingWrapper (3-22)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx (1)
  • StepConnectCalendar (11-61)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx (1)
  • StepSendTestBrief (18-187)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx (1)
  • StepReady (31-124)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx (6)
apps/web/providers/EmailAccountProvider.tsx (1)
  • useAccount (79-89)
apps/web/hooks/useCalendarUpcomingEvents.tsx (1)
  • useCalendarUpcomingEvents (4-8)
apps/web/utils/actions/meeting-briefs.ts (1)
  • sendBriefAction (40-94)
apps/web/components/Typography.tsx (1)
  • TypographyP (129-129)
apps/web/components/LoadingContent.tsx (1)
  • LoadingContent (13-31)
apps/web/utils/email.ts (1)
  • extractDomainFromEmail (73-91)
apps/web/app/(landing)/welcome/utms.tsx (1)
apps/web/utils/auth.ts (1)
  • auth (516-517)
apps/web/app/(app)/premium/PricingFrequencyToggle.tsx (1)
apps/web/components/Input.tsx (1)
  • Label (116-132)
apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx (2)
apps/web/app/(landing)/welcome/utms.tsx (1)
  • registerUtmTracking (18-34)
apps/web/utils/auth.ts (1)
  • auth (516-517)
apps/web/app/(landing)/onboarding-brief/page.tsx (1)
apps/web/utils/account.ts (1)
  • redirectToEmailAccountPath (136-160)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx (4)
apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx (1)
  • metadata (11-15)
apps/web/app/(landing)/welcome/utms.tsx (1)
  • registerUtmTracking (18-34)
apps/web/utils/auth.ts (1)
  • auth (516-517)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx (1)
  • MeetingBriefsOnboardingContent (18-42)
⏰ 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). (5)
  • GitHub Check: Baz Reviewer
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Cursor Bugbot
  • GitHub Check: Macroscope - Correctness Check
  • GitHub Check: test
🔇 Additional comments (22)
apps/web/app/(landing)/welcome/utms.tsx (3)

1-16: LGTM: Clean imports and type definitions.

The imports are properly organized, using type-only imports where appropriate. The scoped logger at the file level correctly avoids using .with(), and the UtmValues type definition is clear and appropriate.


18-34: LGTM: Well-designed UTM tracking orchestration.

The registerUtmTracking function correctly separates synchronous cookie extraction from deferred persistence using after(). The pattern of passing authPromise and resolving it inside the after() callback is safe because auth() invokes headers() immediately when called (before the promise is returned), ensuring request APIs are accessed before the response is sent.


40-92: LGTM: Robust helper functions with proper error handling.

The helper functions are well-structured:

  • extractUtmValues safely reads cookies with optional chaining
  • fetchUserAndStoreUtms includes proper error handling and guards against duplicate storage
  • storeUtms is appropriately scoped as internal with comprehensive logging
apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx (3)

1-15: LGTM: Correct imports and metadata.

The import changes correctly reflect the refactoring, replacing inline UTM logic with the centralized registerUtmTracking utility. The metadata export is properly structured with title, description, and canonical URL.


21-32: LGTM: Efficient async handling and correct UTM tracking integration.

The Promise.all pattern efficiently resolves multiple async operations concurrently, correctly treating params and searchParams as Promises per Next.js 15 requirements. The registerUtmTracking call properly passes the auth promise and awaited cookie store, aligning with the function's design to defer UTM persistence while returning values immediately.


34-36: LGTM: Clean conditional routing logic.

The conditional redirect correctly routes "briefmymeeting" UTM sources to the specialized onboarding flow while providing a force parameter escape hatch. The redirect uses next/navigation's redirect() function appropriately for the App Router, and the deferred UTM persistence in registerUtmTracking will complete even after the redirect occurs (per Next.js after() behavior).

apps/web/app/(app)/premium/config.ts (1)

66-68: LGTM!

The new price IDs for the "brief my meeting" feature are correctly added to the oldPriceIds arrays, following the existing pattern. This ensures proper handling of subscriptions created with these price IDs.

Also applies to: 77-79

apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx (2)

18-26: LGTM!

The auto-advancement logic is well-implemented with proper cleanup. The hasAdvanced flag correctly prevents duplicate navigation, and the timer is properly cleared on unmount. The parent component memoizes onNext with useCallback, ensuring stable reference.


44-58: Clean conditional rendering with good UX feedback.

The connected state provides clear visual feedback with the checkmark and animation. The "Continue" button allows manual progression if the user doesn't want to wait for auto-advancement.

apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx (2)

15-23: Well-structured server component following Next.js 15 patterns.

The async params and searchParams are correctly typed as Promises. Note that params is defined but not awaited or used in this component - the emailAccountId is accessed by child components via the useAccount hook instead. This is fine but could be simplified by removing the unused params type if truly not needed.


25-28: LGTM!

UTM tracking is correctly registered. The registerUtmTracking function uses Next.js after() internally to defer the tracking work, so it won't block rendering.

apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx (1)

35-41: LGTM!

The step-based rendering is clean and follows a forward-only flow pattern. The OnboardingWrapper provides consistent styling across all steps.

apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx (3)

24-39: Good error handling following project conventions.

The useAction hook is properly configured with toastSuccess and toastError handlers. The error handling correctly accesses err.serverError with a fallback message, as per coding guidelines.


100-157: Well-implemented selectable event list with good defensive coding.

The event list handles edge cases properly - extractDomainFromEmail safely handles empty attendees arrays via the || "" fallback. The button elements correctly specify type="button" as required by coding guidelines.


162-184: LGTM!

The send button has comprehensive state management - disabled when no event is selected, during execution, or after successful send. The visual feedback (loading spinner, green variant on success) provides clear UX.

apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx (1)

105-120: LGTM!

The Gmail-specific link is correctly guarded by isGoogleProvider check and includes proper target="_blank" with rel="noopener noreferrer" for security.

apps/web/app/(app)/premium/PricingFrequencyToggle.tsx (3)

6-19: Well-designed type-safe frequency configuration.

The as const assertions enable proper type inference, and the Frequency type is correctly derived from the array. This pattern provides type safety while keeping the data as the single source of truth.


34-54: LGTM!

The RadioGroup implementation provides good accessibility with the sr-only label for screen readers. The Headless UI components handle keyboard navigation automatically.


60-65: Clean reusable badge component.

DiscountBadge is appropriately extracted as a simple, reusable styled wrapper.

apps/web/app/(app)/premium/Pricing.tsx (3)

127-134: Clean integration of the reusable frequency toggle.

The PricingFrequencyToggle is well-integrated using the children slot pattern for the discount badge, maintaining the existing layout.


203-203: Good DRY improvement.

Using DiscountBadge consistently for both "Popular" and "SAVE X%" badges eliminates duplicate styling code.

Also applies to: 225-229


41-56: No action needed. The Pricing component is already properly wrapped in a Suspense boundary through AppPricingLazy.tsx, which uses dynamic() from next/dynamic and a Suspense wrapper with a Loading fallback. The useSearchParams hook has the required Suspense boundary and will not cause hydration issues.

Likely an incorrect or invalid review comment.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 13 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="apps/web/components/SideNavWithTopNav.tsx">

<violation number="1" location="apps/web/components/SideNavWithTopNav.tsx:62">
P3: The comment above this condition is now outdated. It states the code only handles `/[emailAccountId]/onboarding` but it now also handles `onboarding-brief`. Consider updating the comment to reflect both paths.</violation>
</file>

<file name="apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx">

<violation number="1" location="apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx:24">
P2: When an invalid step parameter is provided (e.g., `?step=abc`), `Number.parseInt` returns `NaN`, and `Math.max(NaN, 1)` also returns `NaN`. Since `NaN` doesn&#39;t match any step comparison, no component renders, leaving users with a blank page. Add a fallback to default to step 1 when the value is NaN.</violation>
</file>

<file name="apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx">

<violation number="1" location="apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx:100">
P1: The `onNext` prop is received but never used. The &quot;Start Free Trial&quot; button has no `onClick` handler, which will leave users stuck on this screen with no way to proceed through the onboarding flow. Based on other Step components (e.g., `StepDigest.tsx`), the button should call `onNext` when clicked.</violation>
</file>

<file name="apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx">

<violation number="1" location="apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx:23">
P2: `Number.parseInt` with an invalid string returns `NaN`, which won&#39;t fall back to `1`. This could cause no step content to render. Consider using `|| 1` to handle `NaN` cases.</violation>
</file>

Reply to cubic to teach it or ask questions. Tag @cubic-dev-ai to re-run a review.

Comment on lines +35 to +44
value={frequency}
onChange={setFrequency}
className="grid grid-cols-2 gap-x-1 rounded-full p-1 text-center text-xs font-semibold leading-5 ring-1 ring-inset ring-gray-200"
>
<Label className="sr-only">Payment frequency</Label>
{frequencies.map((option) => (
<Radio
key={option.value}
value={option}
className={({ checked }) =>
Copy link
Contributor

Choose a reason for hiding this comment

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

RadioGroup compares by reference, so using the full object for value prevents the checked state when a different instance is passed. Consider using the primitive option.value and frequency.value, mapping onChange back to a Frequency.

Suggested change
value={frequency}
onChange={setFrequency}
className="grid grid-cols-2 gap-x-1 rounded-full p-1 text-center text-xs font-semibold leading-5 ring-1 ring-inset ring-gray-200"
>
<Label className="sr-only">Payment frequency</Label>
{frequencies.map((option) => (
<Radio
key={option.value}
value={option}
className={({ checked }) =>
value={frequency.value}
onChange={(v) => setFrequency(frequencies.find((f) => f.value === v)!)}
className="grid grid-cols-2 gap-x-1 rounded-full p-1 text-center text-xs font-semibold leading-5 ring-1 ring-inset ring-gray-200"
>
<Label className="sr-only">Payment frequency</Label>
{frequencies.map((option) => (
<Radio
key={option.value}
value={option.value}
className={({ checked }) =>

🚀 Want me to fix this? Reply ex: "fix it for me".

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

♻️ Duplicate comments (1)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx (1)

134-142: LGTM! Checkout flow properly implemented.

The "Start Free Trial" button correctly handles the checkout flow with onClick={handleCheckout} and manages loading state. This resolves the issues flagged in previous reviews about the missing click handler.

🧹 Nitpick comments (3)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx (3)

39-39: Consider using a named default instead of array index.

Using frequencies[1] is fragile—if the frequencies array order changes, the default will shift unexpectedly. Consider using a named constant or finding by value (e.g., frequencies.find(f => f.value === "annually")) for clarity and robustness.

🔎 Suggested refactor
-  const [frequency, setFrequency] = useState(frequencies[1]);
+  const [frequency, setFrequency] = useState(
+    frequencies.find(f => f.value === "annually") ?? frequencies[0]
+  );

62-63: Log the caught error for debugging.

The catch block shows a generic error message but doesn't log or pass the actual error. This makes debugging checkout failures difficult in production.

🔎 Suggested fix
-    } catch {
+    } catch (error) {
+      console.error("Checkout error:", error);
       toastError({ description: "Error creating checkout session" });
     } finally {

104-112: Consider extracting hardcoded prices to constants.

The monthly ($9) and annual ($7.50/$90) prices are hardcoded strings. If these prices need to change, you'll have to update multiple locations. Consider extracting them to named constants at the top of the file.

🔎 Example refactor
+const MEETING_BRIEFS_PRICING = {
+  monthly: { amount: 9, display: "$9" },
+  annually: { amount: 7.5, display: "$7.50", yearly: "$90" }
+} as const;
+
 export function StepReady() {
   // ...
               <p className="text-3xl font-bold text-foreground mt-1">
-                ${frequency.value === "annually" ? "7.50" : "9"}
+                {frequency.value === "annually" 
+                  ? MEETING_BRIEFS_PRICING.annually.display 
+                  : MEETING_BRIEFS_PRICING.monthly.display}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae28f6d and 1399fe5.

📒 Files selected for processing (4)
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/actions/premium.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
🧰 Additional context used
📓 Path-based instructions (21)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)

**/*.{ts,tsx}: For API GET requests to server, use the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

**/*.{ts,tsx}: For early access feature flags, create hooks using the naming convention use[FeatureName]Enabled that return a boolean from useFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming convention use[FeatureName]Variant that define variant types, use useFeatureFlagVariantKey() with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g., inbox-cleaner, pricing-options-2)
Always define types for A/B test variant flags (e.g., type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array<T> consistently
Initialize each enum member value explicitly
Use export type for types
Use `impo...

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/actions/premium.ts
apps/web/app/(app)/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)

apps/web/app/(app)/**/*.{ts,tsx}: Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
If we're in a deeply nested component we will use swr to fetch via API
If you need to use onClick in a component, that component is a client component and file must start with use client

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/premium/config.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)

Always import Prisma enums from @/generated/prisma/enums instead of @/generated/prisma/client to avoid Next.js bundling errors in client components

Import Prisma using the project's centralized utility: import prisma from '@/utils/prisma'

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/actions/premium.ts
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/actions/premium.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Use next/image package for images
For API GET requests to server, use the swr package with hooks like useSWR to fetch data
For text inputs, use the Input component with registerProps for form integration and error handling

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/actions/premium.ts
**/*.{tsx,ts,css}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/actions/premium.ts
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.tsx: Use the LoadingContent component to handle loading states instead of manual loading state management
For text areas, use the Input component with type='text', autosizeTextarea prop set to true, and registerProps for form integration

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like <marquee> or <blink>
Only use the scope prop on <th> elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include a title element for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a lang attribute on the html element
Always include a title attribute for iframe elements
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/actions/premium.ts
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
Don't use the return value of React.render
Make sure all dependencies are correctly specified in React hooks
Make sure all React hooks are called from the top level of component functions
Don't forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use both children and dangerouslySetInnerHTML props on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use <>...</> instead of <Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't use target="_blank" without rel="noopener"
Don't use <img> elements in Next.js projects
Don't use <head> elements in Next.js projects

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
!(pages/_document).{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

Don't use the next/head module in pages/_document.js on Next.js projects

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/actions/premium.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/actions/premium.ts
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx,js,jsx}: Use @/ path aliases for imports from project root
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/actions/premium.ts
apps/web/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/premium/config.ts
apps/web/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{tsx,jsx}: Follow tailwindcss patterns with prettier-plugin-tailwindcss for class sorting
Prefer functional components with hooks in React
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach in components
Follow consistent naming conventions using PascalCase for components
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Use result?.serverError with toastError and toastSuccess for error handling in forms

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Format code with Prettier

Files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/actions/premium.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/security.mdc)

**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma's select option. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. All findUnique/findFirst calls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
All findMany queries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g., emailAccount: { id: emailAccountId }) to validate ownership

Files:

  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/actions/premium.ts
apps/web/**/*.{example,ts,json}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Add environment variables to .env.example, env.ts, and turbo.json

Files:

  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/actions/premium.ts
apps/web/utils/actions/*.ts

📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)

apps/web/utils/actions/*.ts: Use next-safe-action with Zod schemas for all server actions (create/update/delete mutations), storing validation schemas in apps/web/utils/actions/*.validation.ts
Server actions should use 'use server' directive and automatically receive authentication context (emailAccountId) from the actionClient

apps/web/utils/actions/*.ts: Create corresponding server action implementation files using the naming convention apps/web/utils/actions/NAME.ts with 'use server' directive
Use 'use server' directive at the top of server action implementation files
Implement all server actions using the next-safe-action library with actionClient, actionClientUser, or adminActionClient for type safety and validation
Use actionClientUser when only authenticated user context (userId) is needed
Use actionClient when both authenticated user context and a specific emailAccountId are needed, with emailAccountId bound when calling from the client
Use adminActionClient for actions restricted to admin users
Add metadata with a meaningful action name using .metadata({ name: "actionName" }) for Sentry instrumentation and monitoring
Use .schema() method with Zod validation schemas from corresponding .validation.ts files in next-safe-action configuration
Access context (userId, emailAccountId, etc.) via the ctx object parameter in the .action() handler
Use revalidatePath or revalidateTag from 'next/cache' within server action handlers when mutations modify data displayed elsewhere

Files:

  • apps/web/utils/actions/premium.ts
apps/web/utils/actions/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

apps/web/utils/actions/**/*.ts: Server actions must be located in apps/web/utils/actions folder
Server action files must start with use server directive

apps/web/utils/actions/**/*.ts: Use proper error handling with try/catch blocks
Use next-safe-action with Zod schemas for server actions to handle mutations
Use revalidatePath in server actions for cache invalidation after mutations

Files:

  • apps/web/utils/actions/premium.ts
**/{utils,helpers,lib}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)

Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Files:

  • apps/web/utils/actions/premium.ts
apps/web/utils/actions/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Infer types from Zod schemas using z.infer<typeof schema> instead of duplicating as separate interfaces

Files:

  • apps/web/utils/actions/premium.ts
🧠 Learnings (5)
📚 Learning: 2025-07-08T13:14:07.449Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 537
File: apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx:30-34
Timestamp: 2025-07-08T13:14:07.449Z
Learning: The clean onboarding page in apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx is intentionally Gmail-specific and should show an error for non-Google email accounts rather than attempting to support multiple providers.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Accompany `onClick` with at least one of: `onKeyUp`, `onKeyDown`, or `onKeyPress`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : If you need to use `onClick` in a component, that component must be a client component and file must start with `use client` directive

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Components with `onClick` handlers must be client components marked with the `use client` directive

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `next-safe-action` with Zod schemas for all server actions (create/update/delete mutations), storing validation schemas in `apps/web/utils/actions/*.validation.ts`

Applied to files:

  • apps/web/utils/actions/premium.ts
🧬 Code graph analysis (1)
apps/web/utils/actions/premium.ts (5)
apps/web/app/(app)/premium/config.ts (1)
  • getStripePriceId (119-125)
apps/web/utils/error.ts (1)
  • SafeError (87-97)
apps/web/ee/billing/stripe/index.ts (1)
  • getStripe (7-20)
apps/web/utils/posthog.ts (2)
  • trackStripeCustomerCreated (137-149)
  • trackStripeCheckoutCreated (151-153)
apps/web/env.ts (1)
  • env (17-258)
⏰ 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). (5)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Baz Reviewer
  • GitHub Check: test
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Macroscope - Correctness Check
🔇 Additional comments (3)
apps/web/app/(app)/premium/config.ts (1)

42-45: Verify these Stripe price IDs exist in your Stripe account.

The constants BRIEF_MY_MEETING_PRICE_ID_MONTHLY and BRIEF_MY_MEETING_PRICE_ID_ANNUALLY are used as legacy/old price IDs in the BUSINESS_MONTHLY and BUSINESS_ANNUALLY tier configurations and in the checkout flow. Confirm these IDs are active in Stripe and correctly handle existing subscriptions migrating from the "Brief My Meeting" product.

apps/web/utils/actions/premium.ts (2)

502-525: LGTM! Good use of idempotency key for Stripe customer creation.

The idempotency key pattern on Line 510 correctly prevents race conditions when creating Stripe customers. The flow properly handles both existing and new premium records.


527-548: LGTM! Checkout session creation follows standard patterns.

The quantity calculation on Line 528 correctly handles edge cases with proper fallback to 1. The checkout session configuration is standard and includes appropriate metadata for tracking.

Minor note: The 7-day trial period (Line 536) is hardcoded. Consider extracting to a config constant if this may vary by tier or campaign in the future.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="apps/web/app/(app)/[emailAccountId]/calendars/page.tsx">

<violation number="1" location="apps/web/app/(app)/[emailAccountId]/calendars/page.tsx:18">
P2: Potential open redirect vulnerability. The `returnPath` from the cookie is used directly in `redirect()` without validating it&#39;s an internal path. Consider validating that the path starts with `/` and doesn&#39;t start with `//` to prevent redirects to external sites.</violation>
</file>

Reply to cubic to teach it or ask questions. Tag @cubic-dev-ai to re-run a review.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="apps/web/app/(app)/[emailAccountId]/calendars/page.tsx">

<violation number="1" location="apps/web/app/(app)/[emailAccountId]/calendars/page.tsx:19">
P1: The cookie deletion was removed, which can cause redirect loops for valid paths and leaves stale/malicious cookies for invalid paths. The cookie should be deleted regardless of whether the path is internal or not.</violation>
</file>

Reply to cubic to teach it or ask questions. Tag @cubic-dev-ai to re-run a review.

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

♻️ Duplicate comments (2)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx (1)

28-31: Use optional chaining to safely access result.

The onSuccess callback reads result.message without verifying result exists, which could cause a runtime error if the action response is undefined.

🔎 Proposed fix
-        description: result.message || "Test brief sent! Check your inbox.",
+        description: result?.message ?? "Test brief sent! Check your inbox.",
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx (1)

12-56: Wrap async data in LoadingContent component.

The component uses useCalendars (SWR) but doesn't handle loading or error states. This causes the "Connect Calendar" UI to flash even when a calendar is already connected, and silently ignores fetch errors.

As per coding guidelines and the past review comment, wrap the content in LoadingContent to properly handle these states.

Based on coding guidelines: "Use LoadingContent component for async data with loading and error states"

🔎 Proposed fix
 export function StepConnectCalendar({ onNext }: { onNext: () => void }) {
   const { emailAccountId } = useAccount();
-  const { data: calendarsData } = useCalendars();
+  const { data: calendarsData, isLoading, error } = useCalendars();
 
   const hasCalendarConnected =
     calendarsData?.connections && calendarsData.connections.length > 0;
 
   return (
-    <>
+    <LoadingContent loading={isLoading} error={error}>
       <div className="flex justify-center">
         <IconCircle size="lg">
           <Calendar className="size-6" />
         </IconCircle>
       </div>
 
       <div className="text-center">
         <PageHeading className="mt-4">Connect Your Calendar</PageHeading>
         <TypographyP className="mt-2 max-w-lg mx-auto">
           We'll automatically detect your upcoming meetings with external guests
           and prepare personalized briefings.
         </TypographyP>
       </div>
 
       <div className="flex flex-col items-center justify-center mt-8 gap-4">
         {hasCalendarConnected ? (
           <>
             <div className="flex items-center gap-2 text-green-600 font-medium animate-in fade-in zoom-in duration-300">
               <CheckIcon className="h-5 w-5" />
               Calendar Connected!
             </div>
             <Button onClick={onNext} className="mt-2">
               Continue
             </Button>
           </>
         ) : (
           <ConnectCalendar
             onboardingReturnPath={prefixPath(
               emailAccountId,
               "/onboarding-brief?step=2",
             )}
           />
         )}
       </div>
-    </>
+    </LoadingContent>
   );
 }

Don't forget to add the import:

+"use client";
+
+import { Calendar, CheckIcon } from "lucide-react";
+import { PageHeading, TypographyP } from "@/components/Typography";
+import { useCalendars } from "@/hooks/useCalendars";
+import { IconCircle } from "@/app/(app)/[emailAccountId]/onboarding/IconCircle";
+import { ConnectCalendar } from "@/app/(app)/[emailAccountId]/calendars/ConnectCalendar";
+import { Button } from "@/components/ui/button";
+import { useAccount } from "@/providers/EmailAccountProvider";
+import { prefixPath } from "@/utils/path";
++import { LoadingContent } from "@/components/LoadingContent";
🧹 Nitpick comments (1)
apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx (1)

23-27: Consider adding SameSite attribute to the cookie.

The cookie implementation is functional and secure. For additional CSRF protection, consider adding SameSite=Lax to the cookie attributes.

🔎 Proposed enhancement
   const setOnboardingReturnCookie = () => {
     if (onboardingReturnPath) {
-      document.cookie = `${CALENDAR_ONBOARDING_RETURN_COOKIE}=${encodeURIComponent(onboardingReturnPath)}; path=/; max-age=180`;
+      document.cookie = `${CALENDAR_ONBOARDING_RETURN_COOKIE}=${encodeURIComponent(onboardingReturnPath)}; path=/; max-age=180; SameSite=Lax`;
     }
   };
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e1c788d and bc0e756.

📒 Files selected for processing (6)
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/utils/calendar/constants.ts
🧰 Additional context used
📓 Path-based instructions (19)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)

**/*.{ts,tsx}: For API GET requests to server, use the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

**/*.{ts,tsx}: For early access feature flags, create hooks using the naming convention use[FeatureName]Enabled that return a boolean from useFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming convention use[FeatureName]Variant that define variant types, use useFeatureFlagVariantKey() with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g., inbox-cleaner, pricing-options-2)
Always define types for A/B test variant flags (e.g., type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array<T> consistently
Initialize each enum member value explicitly
Use export type for types
Use `impo...

Files:

  • apps/web/utils/calendar/constants.ts
  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)

Always import Prisma enums from @/generated/prisma/enums instead of @/generated/prisma/client to avoid Next.js bundling errors in client components

Import Prisma using the project's centralized utility: import prisma from '@/utils/prisma'

Files:

  • apps/web/utils/calendar/constants.ts
  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed

Files:

  • apps/web/utils/calendar/constants.ts
  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/security.mdc)

**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma's select option. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. All findUnique/findFirst calls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
All findMany queries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g., emailAccount: { id: emailAccountId }) to validate ownership

Files:

  • apps/web/utils/calendar/constants.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Use next/image package for images
For API GET requests to server, use the swr package with hooks like useSWR to fetch data
For text inputs, use the Input component with registerProps for form integration and error handling

Files:

  • apps/web/utils/calendar/constants.ts
  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.{tsx,ts,css}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • apps/web/utils/calendar/constants.ts
  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like <marquee> or <blink>
Only use the scope prop on <th> elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include a title element for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a lang attribute on the html element
Always include a title attribute for iframe elements
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...

Files:

  • apps/web/utils/calendar/constants.ts
  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
!(pages/_document).{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

Don't use the next/head module in pages/_document.js on Next.js projects

Files:

  • apps/web/utils/calendar/constants.ts
  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

Files:

  • apps/web/utils/calendar/constants.ts
  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/{utils,helpers,lib}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)

Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Files:

  • apps/web/utils/calendar/constants.ts
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx,js,jsx}: Use @/ path aliases for imports from project root
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports

Files:

  • apps/web/utils/calendar/constants.ts
  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Format code with Prettier

Files:

  • apps/web/utils/calendar/constants.ts
  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
apps/web/**/*.{example,ts,json}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Add environment variables to .env.example, env.ts, and turbo.json

Files:

  • apps/web/utils/calendar/constants.ts
apps/web/app/(app)/*/page.tsx

📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)

apps/web/app/(app)/*/page.tsx: Create new pages at apps/web/app/(app)/PAGE_NAME/page.tsx
Pages are Server components so you can load data into them directly

Create new pages at apps/web/app/(app)/PAGE_NAME/page.tsx with components either colocated in the same folder or in page.tsx

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/app/(app)/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)

apps/web/app/(app)/**/*.{ts,tsx}: Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
If we're in a deeply nested component we will use swr to fetch via API
If you need to use onClick in a component, that component is a client component and file must start with use client

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.tsx: Use the LoadingContent component to handle loading states instead of manual loading state management
For text areas, use the Input component with type='text', autosizeTextarea prop set to true, and registerProps for form integration

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
Don't use the return value of React.render
Make sure all dependencies are correctly specified in React hooks
Make sure all React hooks are called from the top level of component functions
Don't forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use both children and dangerouslySetInnerHTML props on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use <>...</> instead of <Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't use target="_blank" without rel="noopener"
Don't use <img> elements in Next.js projects
Don't use <head> elements in Next.js projects

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
apps/web/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
apps/web/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{tsx,jsx}: Follow tailwindcss patterns with prettier-plugin-tailwindcss for class sorting
Prefer functional components with hooks in React
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach in components
Follow consistent naming conventions using PascalCase for components
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Use result?.serverError with toastError and toastSuccess for error handling in forms

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
🧠 Learnings (13)
📚 Learning: 2025-07-08T13:14:07.449Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 537
File: apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx:30-34
Timestamp: 2025-07-08T13:14:07.449Z
Learning: The clean onboarding page in apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx is intentionally Gmail-specific and should show an error for non-Google email accounts rather than attempting to support multiple providers.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/*/page.tsx : Create new pages at `apps/web/app/(app)/PAGE_NAME/page.tsx`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/app/(app)/*/page.tsx : Create new pages at `apps/web/app/(app)/PAGE_NAME/page.tsx` with components either colocated in the same folder or in `page.tsx`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/page.tsx : Create new pages at `apps/web/app/(app)/PAGE_NAME/page.tsx`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/**/*.{ts,tsx} : Components for the page are either put in `page.tsx`, or in the `apps/web/app/(app)/PAGE_NAME` folder

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : Components for pages are either put in `page.tsx`, or in the `apps/web/app/(app)/PAGE_NAME` folder

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use LoadingContent component for async data with loading and error states

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*.tsx : Use `LoadingContent` component to consistently handle loading and error states, passing `loading`, `error`, and `children` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Use the `LoadingContent` component to handle loading states

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.tsx : Use the `LoadingContent` component to handle loading states instead of manual loading state management

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : If nested deeply in components, use `swr` to fetch via API instead of loading data directly

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-11-25T14:37:30.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:30.660Z
Learning: Applies to apps/web/hooks/use*.ts : For data fetching, prefer using `useSWR` and follow the data-fetching guidelines

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use shadcn/ui components when available

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
🧬 Code graph analysis (2)
apps/web/app/(app)/[emailAccountId]/calendars/page.tsx (1)
apps/web/utils/calendar/constants.ts (1)
  • CALENDAR_ONBOARDING_RETURN_COOKIE (2-2)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx (5)
apps/web/providers/EmailAccountProvider.tsx (1)
  • useAccount (79-89)
apps/web/hooks/useCalendarUpcomingEvents.tsx (1)
  • useCalendarUpcomingEvents (4-8)
apps/web/utils/actions/meeting-briefs.ts (1)
  • sendBriefAction (40-94)
apps/web/components/LoadingContent.tsx (1)
  • LoadingContent (13-31)
apps/web/utils/email.ts (1)
  • extractDomainFromEmail (73-91)
⏰ 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). (3)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: test
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (5)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx (1)

19-180: LGTM! Well-structured onboarding component.

The implementation follows best practices:

  • Uses LoadingContent for async state handling
  • Proper error handling with toast notifications
  • Semantic HTML with accessible button elements
  • Clear visual feedback for loading, selection, and success states
  • Good empty state handling with skip option
apps/web/utils/calendar/constants.ts (1)

2-2: LGTM!

The constant addition is well-named and follows the existing pattern in the file.

apps/web/app/(app)/accounts/page.tsx (2)

206-219: LGTM!

The icon size utility update from h-4 w-4 to size-4 is a cleaner Tailwind convention, and the text change from "Transfer" to "Copy" more accurately describes the functionality.


233-233: LGTM!

Consistent icon sizing update.

apps/web/app/(app)/[emailAccountId]/calendars/page.tsx (1)

11-22: LGTM! Path validation properly prevents open redirect.

The cookie-based return path logic is well-implemented with proper validation. The code correctly checks that the path is internal (starts with "/" but not "//"), addressing the open redirect concern from previous reviews. The cookie is only read (not deleted) in this server component, which is the appropriate approach.

@elie222 elie222 merged commit 225bb2c into main Dec 30, 2025
9 of 11 checks passed
@elie222 elie222 deleted the feat/brief-my-meeting-onboarding branch December 30, 2025 00:16
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