Skip to content

feat: Add Brief My Meeting feature page#1197

Merged
elie222 merged 2 commits intomainfrom
feat/brief-my-meeting-feature-page
Jan 5, 2026
Merged

feat: Add Brief My Meeting feature page#1197
elie222 merged 2 commits intomainfrom
feat/brief-my-meeting-feature-page

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Jan 4, 2026

User description

Add dedicated feature page for Brief My Meeting within Inbox Zero.

TLDR: Creates a feature page at /brief-my-meeting with custom hero, adds footer link, and includes pre-meeting briefings in pricing features.

  • Add /brief-my-meeting feature page with custom two-column hero section featuring email briefing mockup
  • Add Brief My Meeting link to footer Product section
  • Add "Pre-meeting briefings" to starter tier pricing features with tooltip
  • Uses Inbox Zero's existing styling (blue color scheme, existing typography components)
  • Includes BrandScroller, Banner, Testimonials, Pricing, and FinalCTA sections

Generated description

Below is a concise technical summary of the changes proposed in this PR:
Introduces a new feature page for 'Brief My Meeting' at /brief-my-meeting, integrating it into the application's navigation and pricing structure. Updates the Footer.tsx component to include a link to the new page and modifies config.ts to list 'Pre-meeting briefings' as a feature in the premium tier.

Latest Contributors(2)
UserCommitDate
elie222stripe-for-bmmDecember 29, 2025
joshwerner001@gmail.comFix-mobile-version-of-...November 30, 2025
This pull request is reviewed by Baz. Review like a pro on (Baz).

@vercel
Copy link

vercel bot commented Jan 4, 2026

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

Project Deployment Review Updated (UTC)
inbox-zero Ready Ready Preview Jan 4, 2026 10:51pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 4, 2026

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

This PR adds the "Brief My Meeting" premium feature by updating configuration and UI, while enhancing email similarity calculation to properly handle HTML content from Outlook through ParsedMessage object support and content normalization utilities.

Changes

Cohort / File(s) Summary
Premium feature & footer navigation
apps/web/app/(app)/premium/config.ts, apps/web/app/(landing)/home/Footer.tsx
Added "Pre-meeting briefings" feature to business tier; added "Brief My Meeting" footer navigation link.
Email similarity & draft tracking
apps/web/utils/similarity-score.ts, apps/web/utils/reply-tracker/draft-tracking.ts
Refactored similarity calculation to accept ParsedMessage objects and full message content; added HTML-to-text normalization and quoted content stripping to handle Outlook HTML responses; updated draft tracking to pass full message objects instead of textPlain.
Similarity scoring test expansion
apps/web/utils/similarity-score.test.ts
Restructured from mock-heavy unit tests to mixed unit and integration tests; added comprehensive coverage for identity, normalization, HTML/plaintext handling, and realistic ParsedMessage scenarios.
Marketing submodule
apps/web/app/(marketing)
Subproject commit updated.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • baz-reviewer
  • johnlowe399-blip

Poem

🐰 Hop along, dear messages true,
HTML textures now parse just right, it's true!
Brief thy meetings with AI's grace,
Outlook drafts find their resting place.
Tests abound like clover so green—
The finest reply tracker we've seen!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: Add Brief My Meeting feature page' clearly and specifically describes the main change—adding a new feature page. It directly relates to the primary objective of the PR, which is to introduce the /brief-my-meeting feature page.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings

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

❤️ Share

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

@macroscopeapp
Copy link
Contributor

macroscopeapp bot commented Jan 4, 2026

Add 'Brief My Meeting' feature link in footer and include 'Pre-meeting briefings' in Business tier features in Footer.tsx and config.ts to introduce the Brief My Meeting feature page

Add a footer navigation item linking to /brief-my-meeting and update Business tier features with Pre-meeting briefings, plus bump the (marketing) submodule commit.

📍Where to Start

Start with the footerNavigation.main update in Footer.tsx, then review businessTier.features in config.ts.


Macroscope summarized 1545b1c.

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.

No issues found across 6 files

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 (2)
apps/web/utils/similarity-score.test.ts (2)

107-113: Remove unnecessary module reset and unmock.

The vi.doUnmock("@/utils/mail") is unmocking a module that was never mocked in the first place. The only mock in this file is for "server-only". This entire beforeAll block appears unnecessary since calculateSimilarity is already imported at line 2.

🔎 Proposed simplification
 describe("calculateSimilarity - integration tests with ParsedMessage", () => {
-  // Import real implementation without mocks
-  let realCalculateSimilarity: typeof calculateSimilarity;
-
-  beforeAll(async () => {
-    // Clear the module cache and re-import without mocks
-    vi.resetModules();
-    vi.doUnmock("@/utils/mail");
-    const module = await import("./similarity-score");
-    realCalculateSimilarity = module.calculateSimilarity;
-  });
+  // Use the already-imported calculateSimilarity directly
+  const realCalculateSimilarity = calculateSimilarity;

Then update all usages of realCalculateSimilarity in the integration tests, or simply use calculateSimilarity directly throughout.


115-137: Consider using test helpers from @/__tests__/helpers.

Per coding guidelines, prefer using existing helpers like getMockMessage from @/__tests__/helpers.ts for creating mock data instead of custom test data helpers. However, since this helper creates a specific structure needed for these tests with controlled bodyContentType, this approach is acceptable if the existing helpers don't support this use case.

📜 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 a96ef31 and c136316.

📒 Files selected for processing (6)
  • apps/web/app/(app)/premium/config.ts
  • apps/web/app/(landing)/home/Footer.tsx
  • apps/web/app/(marketing)
  • apps/web/utils/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.ts
🧰 Additional context used
📓 Path-based instructions (22)
**/*.{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/(landing)/home/Footer.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.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/(landing)/home/Footer.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.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/(landing)/home/Footer.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.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/(landing)/home/Footer.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.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/(landing)/home/Footer.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.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/(landing)/home/Footer.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/(landing)/home/Footer.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.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/(landing)/home/Footer.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/(landing)/home/Footer.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.ts
  • apps/web/app/(marketing)
**/*.{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/(landing)/home/Footer.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.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/(landing)/home/Footer.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.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/(landing)/home/Footer.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/(landing)/home/Footer.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css}

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

Format code with Prettier

Files:

  • apps/web/app/(landing)/home/Footer.tsx
  • apps/web/app/(app)/premium/config.ts
  • apps/web/utils/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.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)/premium/config.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/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.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/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.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/reply-tracker/draft-tracking.ts
  • apps/web/utils/similarity-score.test.ts
  • apps/web/utils/similarity-score.ts
**/*.{test,spec}.{js,jsx,ts,tsx}

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

**/*.{test,spec}.{js,jsx,ts,tsx}: Don't nest describe() blocks too deeply in test files
Don't use callbacks in asynchronous tests and hooks
Don't have duplicate hooks in describe blocks
Don't use export or module.exports in test files
Don't use focused tests
Make sure the assertion function, like expect, is placed inside an it() function call
Don't use disabled tests

Files:

  • apps/web/utils/similarity-score.test.ts
apps/web/**/*.test.{ts,tsx}

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

Co-locate test files next to source files (e.g., utils/example.test.ts). Only E2E and AI tests go in __tests__/

Files:

  • apps/web/utils/similarity-score.test.ts
**/*.test.{ts,tsx}

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

**/*.test.{ts,tsx}: Use vitest as the testing framework
Colocate test files next to the tested file with .test.ts or .test.tsx naming convention (e.g., dir/format.ts and dir/format.test.ts)
Mock server-only using vi.mock("server-only", () => ({}))
Mock Prisma using vi.mock("@/utils/prisma") and the provided mock from @/utils/__mocks__/prisma
Use test helper functions getEmail, getEmailAccount, and getRule from @/__tests__/helpers for creating mock data
Clear all mocks between tests using beforeEach(() => { vi.clearAllMocks(); })
Use descriptive test names that clearly indicate what is being tested
Do not mock the Logger in tests

Files:

  • apps/web/utils/similarity-score.test.ts
**/*.test.{js,jsx,ts,tsx}

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

Co-locate test files next to source files (e.g., utils/example.test.ts). Only E2E and AI tests go in __tests__/

Files:

  • apps/web/utils/similarity-score.test.ts
🧠 Learnings (8)
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls

Applied to files:

  • apps/web/utils/reply-tracker/draft-tracking.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls

Applied to files:

  • apps/web/utils/reply-tracker/draft-tracking.ts
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Prefer using existing helpers from `@/__tests__/helpers.ts` (`getEmailAccount`, `getEmail`, `getRule`, `getMockMessage`, `getMockExecutedRule`) instead of creating custom test data helpers

Applied to files:

  • apps/web/utils/similarity-score.test.ts
📚 Learning: 2026-01-01T10:42:29.775Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.775Z
Learning: Applies to **/*.test.{ts,tsx} : Use descriptive test names that clearly indicate what is being tested

Applied to files:

  • apps/web/utils/similarity-score.test.ts
📚 Learning: 2026-01-01T10:42:29.775Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.775Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helper functions `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for creating mock data

Applied to files:

  • apps/web/utils/similarity-score.test.ts
📚 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 **/*.test.ts : Include security tests in test suites to verify: authentication is required, IDOR protection works (other users cannot access resources), parameter validation rejects invalid inputs, and error messages don't leak information

Applied to files:

  • apps/web/utils/similarity-score.test.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Keep related AI functions in the same file or directory, extract common patterns into utility functions, and document complex AI logic with clear comments

Applied to files:

  • apps/web/utils/similarity-score.test.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions

Applied to files:

  • apps/web/utils/similarity-score.ts
🧬 Code graph analysis (2)
apps/web/utils/reply-tracker/draft-tracking.ts (1)
apps/web/utils/similarity-score.ts (1)
  • calculateSimilarity (44-76)
apps/web/utils/similarity-score.test.ts (1)
apps/web/utils/similarity-score.ts (1)
  • calculateSimilarity (44-76)
⏰ 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: Baz Reviewer
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: test
🔇 Additional comments (11)
apps/web/app/(marketing) (1)

1-1: Verify the private marketing submodule commit contains all expected changes.

This is a submodule commit update to the private marketing repository. The commit 9ca3dc0d4f8a8cf8b2e3565e7acc2db6d1affd10 includes a Brief My Meeting feature page. However, since the marketing repository is private and not accessible in this environment, verify that the commit contains all expected changes described in the PR objectives:

  • New /brief-my-meeting feature page with custom two-column hero section
  • Email briefing mockup component integration
  • "Brief My Meeting" footer link added to Product section
  • "Pre-meeting briefings" added to Starter tier pricing features with tooltip
  • Proper reuse of Inbox Zero's blue color scheme and typography components
  • Composition of BrandScroller, Banner, Testimonials, Pricing, and FinalCTA sections

You can verify this in the private marketing repository or during CI/build verification.

apps/web/app/(landing)/home/Footer.tsx (1)

12-12: LGTM!

The new footer navigation item follows the existing pattern and is correctly placed in the Product section without target="_blank" since it's an internal page.

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

165-169: LGTM!

The new feature entry follows the established pattern for features with tooltips, and the tooltip text clearly describes the pre-meeting briefing functionality.

apps/web/utils/reply-tracker/draft-tracking.ts (3)

22-29: LGTM!

Good defensive addition to guard against missing sentMessageId with a warning log before early return. This prevents potential issues downstream when creating the draftSendLog record.


82-83: LGTM!

Passing the full message object enables proper handling of Outlook HTML content through the updated calculateSimilarity function, which now supports ParsedMessage and applies appropriate normalization based on bodyContentType.


167-172: LGTM!

The updated condition correctly handles emails that only have HTML content (common with Outlook), and passing the full draftDetails object allows calculateSimilarity to properly normalize based on the content type.

apps/web/utils/similarity-score.test.ts (2)

6-96: Good test coverage for basic similarity calculations.

The tests comprehensively cover edge cases including null/undefined handling, case-insensitivity, whitespace normalization, partial similarity, special characters, and realistic email scenarios.


139-242: Good integration test coverage for Outlook and Gmail content handling.

The integration tests effectively validate the key scenarios: Outlook HTML content with various structures (div wrappers, signatures, quoted content), Gmail quote stripping, newline normalization, and backward compatibility with plain strings.

apps/web/utils/similarity-score.ts (3)

10-17: LGTM!

The normalization approach correctly handles the stored draft content by converting newlines to <br> tags before HTML-to-text conversion, preserving line break semantics. The subsequent quote stripping and case normalization ensure consistent comparison.


23-34: LGTM!

Clean implementation that properly handles the Outlook HTML case by converting to plain text when bodyContentType === "html", then applying consistent normalization.


64-68: Good fallback logic for HTML-only emails.

The fallback from textPlain to textHtml with forced "html" content type correctly handles emails that only contain HTML content (common with Outlook). This ensures proper conversion to plain text before comparison.

Comment on lines 57 to 69
if (typeof providerMessage === "string") {
// Legacy: plain string - use parseReply for backwards compatibility with Gmail
const reply = parseReply(providerMessage);
normalized2 = reply.toLowerCase().trim();
} else {
// ParsedMessage - use proper normalization with bodyContentType
// Fall back to textHtml if textPlain is empty (some emails only have HTML)
const text = providerMessage.textPlain || providerMessage.textHtml || "";
const contentType = providerMessage.textPlain
? providerMessage.bodyContentType
: "html";
normalized2 = normalizeProviderContent(text, contentType);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for parseReply and stripQuotedContent implementations

echo "=== Locating parseReply ==="
rg -n -B 2 -A 20 'export.*parseReply|function parseReply' --type ts

echo ""
echo "=== Locating stripQuotedContent ==="
rg -n -B 2 -A 20 'export.*stripQuotedContent|function stripQuotedContent' --type ts

echo ""
echo "=== Locating normalizeProviderContent ==="
rg -n -B 2 -A 15 'export.*normalizeProviderContent|function normalizeProviderContent' --type ts

Repository: elie222/inbox-zero

Length of output: 4569


Normalization inconsistency confirmed: legacy and ParsedMessage paths use fundamentally different quote-stripping mechanisms.

The legacy string path uses parseReply which leverages the EmailReplyParser library's getVisibleText() method, while the ParsedMessage path uses stripQuotedContent which applies manual regex patterns (On .* wrote:, ----Original Message----, >+ On, From:). These implementations could identify and strip quoted content differently, causing inconsistent similarity scores for identical emails. Consider consolidating both paths to use the same quote-stripping mechanism.

🤖 Prompt for AI Agents
apps/web/utils/similarity-score.ts lines 57-69: the legacy string branch uses
parseReply (EmailReplyParser.getVisibleText semantics) while the ParsedMessage
branch uses stripQuotedContent with different regexes, causing inconsistent
quote-stripping and similarity scores; unify both paths to use the same
quote-stripping/normalization function: extract visible text using a single
helper (either standardize on EmailReplyParser.getVisibleText or standardize on
stripQuotedContent), ensure it accepts bodyContentType (plain vs html) and falls
back from textPlain to textHtml, then apply lowercase/trim normalization to the
helper result for both branches; update calls so the string path runs through
this helper instead of raw parseReply, and add/adjust tests to cover both input
shapes.

Comment on lines 115 to 119
const createParsedMessage = (
textPlain: string,
bodyContentType?: "html" | "text",
) => ({
id: "msg-123",
Copy link
Contributor

Choose a reason for hiding this comment

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

The new integration suite introduces an ad-hoc createParsedMessage factory (lines 115‑137) instead of consuming the shared email mocks from @/__tests__/helpers (e.g., getMockMessage), which breaches the .cursor/rules/testing.mdc rule that all email/account mock data must come from that central helper.

Prompt for AI Agents:

In apps/web/utils/similarity-score.test.ts around lines 115-119, the local
createParsedMessage factory duplicates email mock data and violates the testing rule
that all email/account mocks must come from @/__tests__/helpers. Replace the local
factory by importing the shared helper (e.g., getMockMessage or getParsedMessage) from
@/__tests__/helpers at the top of the file, remove lines 115-137 (the
createParsedMessage function), and update every test that called createParsedMessage to
instead call the shared helper while passing the same textPlain/textHtml and
bodyContentType values. Ensure the helper calls set id/threadId/subject/headers as
needed so existing assertions and behavior remain unchanged.

Fix in Cursor


Finding type: AI Coding Guidelines

@elie222 elie222 merged commit c8adcf8 into main Jan 5, 2026
13 checks passed
@elie222 elie222 deleted the feat/brief-my-meeting-feature-page branch January 5, 2026 10:08
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

Comments