Skip to content

feat: Add automatic webhook setup and Connect Calendar UI for Meeting Scheduler#893

Closed
salja03-t21 wants to merge 32 commits intoelie222:mainfrom
salja03-t21:feature/email-triggered-meeting-scheduler
Closed

feat: Add automatic webhook setup and Connect Calendar UI for Meeting Scheduler#893
salja03-t21 wants to merge 32 commits intoelie222:mainfrom
salja03-t21:feature/email-triggered-meeting-scheduler

Conversation

@salja03-t21
Copy link

@salja03-t21 salja03-t21 commented Nov 2, 2025

Summary

Implements automatic webhook configuration with manual fallback UI to enable real-time email processing for the Meeting Scheduler feature. Premium checks temporarily disabled for testing.

Key Changes

  • Automatic Webhook Setup: Outlook webhooks are now automatically created when users enable Meeting Scheduler in Settings
  • Connect Calendar UI: Added a "Connect Calendar" button with status display showing webhook expiration in Meeting Scheduler Settings (Microsoft accounts only)
  • Premium Bypass: Temporarily disabled premium checks in webhook cron job and Share Premium section for testing
  • Bug Fixes:
    • Fixed HTML validation errors in ProgressPanel component (p>div nesting issue)
    • Fixed form layout issues in Meeting Scheduler settings (column width)
    • Removed invalid showPreview prop from clean onboarding page
  • API Updates: Added watchEmailsExpirationDate and account.provider to Meeting Scheduler settings endpoint

Testing

See MEETING_SCHEDULER_README.md for comprehensive testing guide.

Production Checklist

Before deploying to production:

  • Re-enable premium checks in /api/outlook/watch/all/route.ts
  • Re-enable premium checks in MultiAccountSection.tsx
  • Deploy to stable URL for reliable webhook validation
  • Test end-to-end meeting scheduling flow

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added Microsoft Calendar and Outlook integration for email operations.
    • Introduced Meeting Scheduler with configurable settings (duration, working hours, provider preferences).
    • Added email cleaning preview functionality to test actions before processing full inbox.
    • Extended deep-clean feature to support Outlook accounts.
  • Improvements

    • Enhanced navigation with back-button support across onboarding steps.
    • Improved responsive layouts for settings forms.
  • Documentation

    • Updated README with Microsoft Calendar setup instructions and Discord community link.

edulelis and others added 30 commits October 9, 2025 18:30
…dling

Fix calendar OAuth callbacks to redirect to /{emailAccountId}/calendars
and standardize error handling between Google and Microsoft providers.
Implement complete Outlook integration for the deep-clean feature:

Backend Changes:
- Created /api/clean/outlook/route.ts with Graph API integration
- Implemented archive operation (moves to Archive folder)
- Implemented mark as read operation
- Added provider detection and routing in /api/clean/route.ts
- Provider-agnostic static rules (starred/flagged, sent, etc.)
- QStash integration with signature verification

UI Improvements:
- Removed premium banner from intro step
- Updated 'Starred emails' to 'Starred/Flagged emails'
- Provider-aware confirmation text (Gmail vs Outlook)
- Dynamic messaging for archive and mark-as-read operations

Development Changes:
- Commented out premium checks for testing
- QStash credentials configured
- All required environment variables set

Files Created:
- apps/web/app/api/clean/outlook/route.ts

Files Modified:
- apps/web/app/api/clean/route.ts
- apps/web/app/(app)/[emailAccountId]/clean/IntroStep.tsx
- apps/web/app/(app)/[emailAccountId]/clean/CleanInstructionsStep.tsx
- apps/web/app/(app)/[emailAccountId]/clean/ConfirmationStep.tsx
- apps/web/.env

Note: Premium checks are disabled for development/testing only.
Re-enable before production deployment.
- Added onPrevious() function to useStep hook
- Added Back buttons to all wizard steps:
  * ActionSelectionStep
  * CleanInstructionsStep
  * TimeRangeStep
  * ConfirmationStep
- Users can now navigate back through the wizard steps
- Improves UX by allowing users to correct mistakes without restarting
Temporarily commented out PremiumExpiredCard component in SideNav
to allow testing of Outlook deep-clean feature without premium restrictions.
This should be re-enabled before production deployment.
Temporarily disable premium banner by making PremiumAlertWithData return null.
Original code preserved in comment block for re-enabling before production.
This resolves the persistent premium banner issue in the deep-clean wizard.
Temporarily comment out premium validation (lines 41-43) to allow testing
the deep-clean wizard without premium subscription.
Original code preserved in comments for re-enabling before production.
- Both lines 87 and 153 now correctly access provider from account object
- Pattern matches usage throughout codebase (safe-action.ts, etc)
- Type definition includes provider in account select
- Refactored undoCleanInboxAction and changeKeepToDoneAction to use provider-agnostic EmailProvider pattern instead of Gmail-only functions
- Fixed Undo button to work with both Gmail and Outlook accounts
- Hidden 'Process Only These 50 Emails' button on preview page as requested
- Integrated useEmailStream hook to properly display emails in real-time via SSE
- Fixed React hydration errors in Radix UI components (DropdownMenu, Tooltip) by adding suppressHydrationWarning
- Fixed TypeScript error in LoadingContent by changing error prop from string | null to string | undefined
- Add loading state to ConfirmationStep to prevent duplicate submissions
- Clamp onPrevious in useStep to prevent underflow below step 0
- Extract duplicate payload construction in PreviewStep into buildCleanPayload helper
- Fix LoadingContent error prop type in PreviewStep
- Updated all cursor rules documentation for consistency
- Enhanced Outlook email streaming and preview functionality
- Added clean-preview utility for better code organization
- Improved error handling in Microsoft email utilities
- Refined clean preview batch UI components

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This merge brings in comprehensive Outlook/Microsoft Calendar support:

- OAuth authentication flow for Microsoft Calendar
- Calendar syncing with Microsoft Graph API
- Unified availability checking across Google and Microsoft calendars
- Provider pattern architecture for multi-provider support
- AI integration for meeting time suggestions using Microsoft calendars
- Updated UI with "Add Outlook Calendar" button
- Token refresh handling for Microsoft Calendar
- Documentation updates for setup instructions

Key features:
- Users can connect multiple calendar providers (Google + Microsoft)
- AI drafts check availability across all connected calendars
- Clean architecture with provider abstraction
- Automatic calendar sync after connection

Files added:
- utils/outlook/calendar-client.ts - Microsoft Graph API client
- utils/calendar/providers/microsoft.ts - OAuth provider
- utils/calendar/providers/microsoft-availability.ts - Availability checking
- utils/calendar/unified-availability.ts - Multi-provider aggregation
- app/api/outlook/calendar/* - OAuth endpoints

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Eduardo Lelis <eduardoleliss@gmail.com>
- Add showPreview prop to ConfirmationStep component type
- Update clean-preview.ts to use correct Account token structure
- Fix token access: use account.access_token instead of tokens.access_token
- Convert Date to timestamp (getTime()) for client functions
- Use queryBatchMessages for Gmail to get full message details
- Fix message property access: use message.headers instead of message.parsedMessage.headers
- Remove unsupported 'after' parameter from Outlook getMessages call

All TypeScript errors resolved, build now passes successfully.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Support email triggers: 'Schedule:' in subject or '/schedule meeting' in body
- AI-powered meeting detail extraction
- Calendar availability checking
- Teams/Zoom/Google Meet link generation
- Native calendar event creation (not .ics files)
- Automatic invite sending via Google Calendar/Outlook Calendar APIs
- Comprehensive 6-phase implementation plan
- Created detectMeetingTrigger utility to detect meeting scheduling triggers
- Supports "Schedule:" in subject line (case-insensitive)
- Supports "/schedule meeting" command in email body (case-insensitive)
- Works for both sent emails and emails to yourself
- Integrated detection into webhook processing (Gmail and Outlook)
- Added comprehensive test coverage with 19 passing tests
- Lazy-loads logger to avoid env validation issues in tests

Trigger patterns:
1. Subject: "Schedule:" (e.g., "Schedule: Team meeting next week")
2. Body: "/schedule meeting" (e.g., "Hi team, /schedule meeting to discuss Q4")

Both patterns work for:
- Sent emails (outbound messages)
- Emails to yourself (inbound from your own address)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Phase 2 of meeting scheduler implementation

- Created aiParseMeetingRequest to extract structured meeting data
- Parses attendees from To/CC fields and email body
- Extracts date/time preferences in natural language
- Detects meeting duration (default 60 min)
- Generates professional meeting title from content
- Extracts agenda/purpose from email body
- Detects preferred provider (Teams/Zoom/Google Meet)
- Identifies in-person meeting locations
- Captures special requests and notes
- Detects urgency flags (ASAP, urgent, today)
- Integrated parser into webhook processing
- Added comprehensive test suite (11 test cases)

Features:
- Zod schema validation for structured output
- Uses createGenerateObject for AI integration
- Follows codebase LLM patterns
- Scoped logging for debugging
- Handles self-reminder emails (emails to yourself)

Test coverage:
✓ Simple meeting requests
✓ Teams/Zoom/Google Meet detection
✓ Urgency detection
✓ In-person location extraction
✓ Multiple attendees from CC
✓ Detailed agenda extraction
✓ Requests with no specific times
✓ Special preparation notes
✓ Self-reminder emails

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Phase 3 of meeting scheduler implementation

- Created findMeetingAvailability to find available time slots
- Leverages existing unified calendar integration (Google + Microsoft)
- Parses natural language time preferences (e.g., "next Tuesday at 2pm")
- Checks requested times against busy periods from all calendars
- Suggests alternative times if requested slots are busy
- Integrated into webhook processing pipeline

Features:
- Natural language parsing for common date/time expressions
- Supports: "tomorrow at 2pm", "next Tuesday", "Jan 15 at 10am"
- Day-of-week detection (Monday-Sunday)
- Intelligent time slot conflict detection
- Working hours suggestions (9 AM - 5 PM)
- Timezone-aware date handling using TZDate
- User timezone detection from calendar connections
- Fallback suggestions when no specific times requested

Algorithm:
1. Parse user's timezone from connected calendars
2. Parse natural language date/time preferences
3. Fetch busy periods across all Google + Microsoft calendars
4. Check if requested times are available (no conflicts)
5. If conflicts found, suggest alternative times
6. Return structured availability data with timezone

Time slot conflict detection:
- Checks for overlaps: slot starts before busy ends AND slot ends after busy starts
- Returns only available slots (no conflicts)

Suggestions algorithm:
- Checks next 7 days by default
- Prioritizes times near user's preferred hour
- Working hours: 9 AM - 5 PM
- Returns up to 5 suggestions
- Filters duplicate slots

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add meeting link generators for Microsoft Teams and Google Meet with provider validation.

**New Files:**
- `create-meeting-link.ts`: Main orchestration for creating meeting links with provider validation
- `providers/types.ts`: Provider validation logic ensuring Teams=Microsoft only, Google Meet=Google only
- `providers/teams.ts`: Microsoft Teams meeting creation via Graph API /me/onlineMeetings
- `providers/google-meet.ts`: Google Meet conferenceData generation for calendar events

**Updates:**
- `parse-meeting-request.ts`: Fixed EmailForLLM type usage (removed .headers accessor)
- `process-history-item.ts`: Integrated meeting link creation into webhook flow

**Key Features:**
- Provider compatibility validation (Teams for Microsoft, Google Meet for Google)
- Automatic fallback to native provider when incompatible provider requested
- Zoom support deferred (returns fallback to native provider)
- Teams uses Microsoft Graph API with OAuth refresh
- Google Meet uses conferenceData structure (link auto-created by Google Calendar)

Next: Phase 5 (calendar event creation) and Phase 6 (user settings)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add unified calendar event creation for both Google Calendar and Microsoft Calendar with full meeting link integration.

**New File:**
- `create-calendar-event.ts`: Unified calendar event creation with provider-specific implementations

**Key Features:**
- **Google Calendar**: Uses googleapis calendar_v3 API
  - Creates events with conferenceData for Google Meet
  - Sets sendUpdates='all' to notify attendees
  - Includes description with agenda, notes, and meeting link

- **Microsoft Calendar**: Uses Microsoft Graph API
  - Creates events with Teams meeting integration
  - Sets isOnlineMeeting and onlineMeetingProvider
  - Includes body content with agenda, notes, and meeting link

- **Unified Interface**: Single function handles both providers
  - Automatically detects provider from email account
  - Gets primary/enabled calendar
  - Validates authentication tokens
  - Returns standardized event details (eventId, eventUrl, provider)

- **Full Integration**: Connected to meeting details
  - Adds all attendees from parsed meeting request
  - Sets location if specified
  - Includes agenda and notes in event description
  - Applies correct timezone from availability checker
  - Sends calendar invitations automatically

**Updates:**
- `process-history-item.ts`: Integrated calendar event creation after meeting link generation

**Flow:**
1. Parse meeting request → 2. Find availability → 3. Generate meeting link → 4. **Create calendar event** → 5. Send confirmation email (TODO)

Next: Phase 6 (user settings) and testing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add unit tests for meeting provider validation logic:
- Test getAvailableProviders() for both Google and Microsoft accounts
- Test validateProviderForAccount() for all provider/account combinations
- Verify Teams=Microsoft only, Google Meet=Google only
- Test fallback logic for incompatible providers
- Test 'none' and 'zoom' edge cases

All 11 tests passing ✅

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add user-configurable settings for meeting scheduler:
- meetingSchedulerEnabled: Enable/disable automatic meeting scheduling (default: true)
- meetingSchedulerDefaultDuration: Default meeting duration in minutes (default: 60)
- meetingSchedulerPreferredProvider: Preferred meeting provider (auto/teams/google-meet/zoom/none)
- meetingSchedulerWorkingHoursStart: Working hours start 0-23 (default: 9)
- meetingSchedulerWorkingHoursEnd: Working hours end 0-23 (default: 17)
- meetingSchedulerAutoCreate: Auto-create events or prompt for confirmation (default: true)

Migration applied successfully ✅

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add database schema fields for meeting scheduler configuration:
  - meetingSchedulerEnabled: toggle meeting scheduler on/off
  - meetingSchedulerDefaultDuration: default meeting duration (15-240 minutes)
  - meetingSchedulerPreferredProvider: preferred meeting provider (auto, teams, google-meet, zoom, none)
  - meetingSchedulerWorkingHoursStart/End: working hours for scheduling (0-23)
  - meetingSchedulerAutoCreate: auto-create meetings without confirmation

- Create validation schema with Zod for settings updates
- Implement server action for updating meeting scheduler settings with working hours validation
- Integrate settings check into webhook processing to respect user preferences
- Update webhook type definitions to include meetingSchedulerEnabled
- Add meetingSchedulerEnabled to webhook account selection

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…idation

- Add 24 test cases covering all validation scenarios
- Test valid inputs for all settings fields
- Test boundary conditions (min/max values)
- Test edge cases (0, 23 hours; 15, 240 minutes)
- Test invalid inputs (out of range, wrong types)
- Test optional field handling
- All tests passing (24/24)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
salja03-t21 and others added 2 commits November 2, 2025 21:50
- Create GET API route for fetching meeting scheduler settings
- Build comprehensive settings UI component with:
  - Enable/disable toggle for meeting scheduler
  - Default meeting duration input (15-240 minutes)
  - Preferred meeting provider dropdown (auto, teams, google-meet, zoom, none)
  - Working hours configuration (start/end hours 0-23)
  - Auto-create toggle for automatic meeting creation
- Dynamic provider options based on account type (Google/Microsoft)
- Form validation with React Hook Form and Zod
- Integrated with existing settings page under Email Account tab
- Real-time form state management with SWR data fetching
- Proper error handling with toast notifications

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
… Scheduler

Implements automatic webhook configuration with manual fallback UI to enable real-time email processing for the Meeting Scheduler feature. Premium checks temporarily disabled for testing.

Key changes:
- Auto-setup Outlook webhooks when enabling Meeting Scheduler
- Add "Connect Calendar" button with status display in Settings
- Disable premium checks in webhook cron job for testing
- Fix HTML validation errors in ProgressPanel component
- Fix form layout issues in Meeting Scheduler settings
- Enable Share Premium section for testing
- Update API to return webhook expiration status

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@vercel
Copy link

vercel bot commented Nov 2, 2025

@salja03-t21 is attempting to deploy a commit to the Inbox Zero OSS Program Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 2, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This PR introduces a comprehensive Meeting Scheduler feature triggered by email patterns, implements multi-provider email abstraction to support Outlook alongside Gmail, refactors the Deep Clean flow with preview capabilities and back navigation, extends calendar OAuth integration with Microsoft provider support, and adds temporary testing bypasses for premium features.

Changes

Cohort / File(s) Summary
Cursor Rules Configuration
.cursor/rules/cursor-rules.mdc, .cursor/rules/data-fetching.mdc, .cursor/rules/environment-variables.mdc, .cursor/rules/features/*.mdc, .cursor/rules/form-handling.mdc, .cursor/rules/fullstack-workflow.mdc, .cursor/rules/get-api-route.mdc, .cursor/rules/gmail-api.mdc, .cursor/rules/hooks.mdc, .cursor/rules/installing-packages.mdc, .cursor/rules/llm-test.mdc, .cursor/rules/llm.mdc, .cursor/rules/logging.mdc, .cursor/rules/notes.mdc, .cursor/rules/page-structure.mdc, .cursor/rules/posthog-feature-flags.mdc, .cursor/rules/prisma.mdc, .cursor/rules/project-structure.mdc, .cursor/rules/security.mdc, .cursor/rules/server-actions.mdc, .cursor/rules/task-list.mdc, .cursor/rules/testing.mdc, .cursor/rules/ui-components.mdc, .cursor/rules/ultracite.mdc, .cursor/rules/utilities.mdc
Expanded glob patterns and metadata across 25+ cursor rules files to specify which files each rule applies to; added descriptions, enabled alwaysApply flags, and fixed formatting issues.
IDE Configuration
.idea/.gitignore, .idea/copilot.data.migration.*.xml, .idea/inbox-zero.iml, .idea/inspectionProfiles/Project_Default.xml, .idea/modules.xml, .idea/vcs.xml
Added IntelliJ IDEA project configuration files including module definition, VCS mapping, inspection profiles (ESLint, PyPEP8), and Copilot migration state markers.
Documentation & Planning
MEETING_SCHEDULER_PLAN.md, Cline_Notes/outlook-deep-clean-plan.md, README.md, apps/web/MEETING_SCHEDULER_README.md
Introduced comprehensive implementation plans for Meeting Scheduler and Outlook deep-clean features, updated README with Microsoft Calendar OAuth setup details and Discord invite, added Meeting Scheduler feature documentation.
Calendar OAuth & Provider Implementation
apps/web/app/api/google/calendar/callback/route.ts, apps/web/app/api/outlook/calendar/auth-url/route.ts, apps/web/app/api/outlook/calendar/callback/route.ts, apps/web/utils/calendar/handle-calendar-callback.ts, apps/web/utils/calendar/oauth-callback-helpers.ts, apps/web/utils/calendar/oauth-types.ts, apps/web/utils/calendar/providers/google.ts, apps/web/utils/calendar/providers/microsoft.ts
Refactored Google calendar callback to delegated handler; added Outlook calendar OAuth endpoints, unified callback handler, helper utilities, and provider-specific implementations for token exchange and calendar synchronization.
Calendar Availability & Utilities
apps/web/utils/calendar/availability-types.ts, apps/web/utils/calendar/availability.ts, apps/web/utils/calendar/unified-availability.ts, apps/web/utils/calendar/providers/google-availability.ts, apps/web/utils/calendar/providers/microsoft-availability.ts
Deleted single-provider availability module; introduced provider interface, provider-specific implementations (Google, Microsoft), and unified availability fetcher that aggregates busy periods across all connected calendars.
Calendar Connection UI
apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendarButton.tsx, apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx, apps/web/app/(app)/[emailAccountId]/calendars/CalendarConnectionCard.tsx, apps/web/app/(app)/[emailAccountId]/calendars/CalendarConnections.tsx, apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
Replaced single-provider button with multi-provider component (Google/Outlook); dynamified provider display labels and icons; updated connection UI text to reference both Google and Microsoft calendars.
Meeting Scheduler API & Settings
apps/web/app/api/user/meeting-scheduler-settings/route.ts, apps/web/app/(app)/[emailAccountId]/settings/MeetingSchedulerSection.tsx, apps/web/utils/actions/meeting-scheduler.ts, apps/web/utils/actions/meeting-scheduler.validation.ts
Added Meeting Scheduler settings API endpoint, React settings component with form validation, server actions for settings updates and webhook connection, and Zod validation schema.
Meeting Scheduler Utilities
apps/web/utils/meetings/detect-meeting-trigger.ts, apps/web/utils/meetings/create-meeting-link.ts, apps/web/utils/meetings/create-calendar-event.ts
Introduced meeting trigger detection from email subjects/bodies, meeting link creation across providers, and calendar event creation orchestration with provider-specific builders.
Meeting Scheduler Tests
apps/web/__tests__/ai-parse-meeting-request.test.ts, apps/web/__tests__/detect-meeting-trigger.test.ts, apps/web/__tests__/meeting-provider-validation.test.ts, apps/web/__tests__/meeting-scheduler-settings.test.ts
Added comprehensive test suites for AI meeting request parsing, trigger detection, provider validation, and settings validation.
Deep Clean Preview & Flow Refactor
apps/web/app/(app)/[emailAccountId]/clean/ActionSelectionStep.tsx, apps/web/app/(app)/[emailAccountId]/clean/CleanInstructionsStep.tsx, apps/web/app/(app)/[emailAccountId]/clean/ConfirmationStep.tsx, apps/web/app/(app)/[emailAccountId]/clean/IntroStep.tsx, apps/web/app/(app)/[emailAccountId]/clean/TimeRangeStep.tsx, apps/web/app/(app)/[emailAccountId]/clean/PreviewBatch.tsx, apps/web/app/(app)/[emailAccountId]/clean/PreviewStep.tsx, apps/web/app/(app)/[emailAccountId]/clean/types.ts, apps/web/app/(app)/[emailAccountId]/clean/useStep.tsx, apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx
Added back navigation to all steps, introduced new PreviewStep for sandbox testing, updated flow types to include PREVIEW enum, enhanced useStep with functional updater and onPrevious callback, changed UI text to reflect sample/preview behavior.
Email Stream & Provider Connection
apps/web/app/(app)/[emailAccountId]/clean/useEmailStream.ts, apps/web/app/api/email-stream/route.ts
Enhanced connection resilience with guards against concurrent SSE connections, improved lifecycle/cleanup logic, added unified closeController, and postponed cleanup on unmount to detect hot reloads.
Outlook Clean Integration
apps/web/app/api/clean/outlook/route.ts, apps/web/app/api/clean/route.ts
Added dedicated Outlook clean route handler with conversation/message operations; updated Gmail route with provider-agnostic routing and label/action dispatching for both Gmail and Outlook.
Provider-Agnostic Email Utilities
apps/web/utils/email/constants.ts, apps/web/utils/email/microsoft.ts
Introduced unified EmailState/EmailCategory enums with Gmail/Outlook mappings, Inbox Zero folder constants/helpers, and enhanced Outlook thread fetching with error handling, filtering, and thread normalization.
Multi-Provider Actions
apps/web/utils/actions/clean.ts, apps/web/utils/actions/clean-preview.ts
Refactored clean actions from Gmail-only to provider-agnostic, removing hard-coded Gmail clients; added preview email action supporting both Gmail and Outlook with uniform message shape.
Outlook Webhook Integration
apps/web/app/api/outlook/webhook/process-history-item.ts, apps/web/app/api/outlook/watch/all/route.ts, apps/web/app/api/google/webhook/types.ts
Extended webhook history processing to include meetingSchedulerEnabled field; removed premium access gating from Outlook watch route (testing bypass); updated Google webhook types to include meeting scheduler state.
Database Schema
apps/web/prisma/schema.prisma, apps/web/prisma/migrations/20251102202912_add_meeting_scheduler_settings/migration.sql
Added Meeting Scheduler configuration fields to EmailAccount (enabled, defaultDuration, preferredProvider, workingHours start/end, autoCreate).
Premium & Feature Flags
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx, apps/web/app/(app)/[emailAccountId]/settings/MultiAccountSection.tsx, apps/web/utils/actions/premium.ts, apps/web/hooks/useFeatureFlags.ts
Removed session-based premium gating and always-enabled premium UI (testing); disabled premium credit decrements; hardcoded cleaner feature flag to true; removed unread-only filter from bulk rule processing.
UI Components & Navigation
apps/web/components/Form.tsx, apps/web/components/ProgressPanel.tsx, apps/web/components/SideNav.tsx, apps/web/components/ui/dropdown-menu.tsx, apps/web/components/ui/tooltip.tsx
Updated FormSectionRight responsive grid; refactored ProgressPanel DOM structure; removed premium UI, referral dialog, and PremiumExpiredCard from sidebar (testing); converted DropdownMenuTrigger and TooltipTrigger to forwardRef components.
Settings & App Providers
apps/web/app/(app)/[emailAccountId]/settings/page.tsx, apps/web/providers/AppProviders.tsx
Added MeetingSchedulerSection to settings page; wrapped app providers with NuqsAdapter for URL state management.
Project Configuration
.gitignore
Added memory-bank/ to ignored directories and adjusted coverage entry formatting.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Email as Email Provider
    participant EmailStream as Email Stream
    participant DetectTrigger as Detect Trigger
    participant MeetingService as Meeting Service
    participant Calendar as Calendar Provider

    User->>Email: Receives email with "Schedule: meeting"
    Email->>EmailStream: Streams email to user
    EmailStream->>DetectTrigger: Extract subject/body
    DetectTrigger-->>EmailStream: {isTriggered: true, triggerType: "schedule_subject"}
    EmailStream->>MeetingService: Parse meeting request via AI
    MeetingService-->>MeetingService: Extract attendees, time, provider preference
    MeetingService->>Calendar: Create calendar event
    Calendar-->>MeetingService: {eventId, eventUrl, provider}
    MeetingService->>Email: Optional: Send confirmation/update email
    Email-->>User: Meeting created & calendar updated
Loading
sequenceDiagram
    participant User
    participant UI as Deep Clean UI
    participant Preview as Preview Step
    participant EmailAPI as Email API
    participant Clean as Clean Service

    User->>UI: Start deep clean flow
    UI->>Preview: IntroStep → TimeRangeStep → ... → PreviewStep
    Preview->>EmailAPI: Fetch preview batch (limited count)
    EmailAPI-->>Preview: Sample emails matching criteria
    Preview->>UI: Render sandbox results with "Process Preview" & "Full Inbox" buttons
    User->>UI: Choose "Process Preview Only"
    UI->>Clean: Run cleanup on preview batch
    Clean-->>UI: Success with preview mode enabled
    UI->>UI: Show results, enable "Run on Full Inbox" button
    User->>UI: Click "Run on Full Inbox"
    UI->>Clean: Execute full cleanup
    Clean-->>UI: Completion
Loading
sequenceDiagram
    participant Browser as Browser
    participant AuthURL as Auth URL Endpoint
    participant OAuth as OAuth Provider
    participant Callback as Callback Endpoint
    participant DB as Database
    participant UI as Calendar UI

    Browser->>AuthURL: Request calendar OAuth URL
    AuthURL->>AuthURL: Create state (emailAccountId + nonce)
    AuthURL-->>Browser: Return OAuth URL + set state cookie
    Browser->>OAuth: Redirect to OAuth provider (Google/Microsoft)
    OAuth-->>Browser: Prompt user for consent
    Browser->>Callback: Redirect with authorization code
    Callback->>Callback: Validate state cookie + extract emailAccountId
    Callback->>OAuth: Exchange code for tokens
    OAuth-->>Callback: Return access/refresh tokens
    Callback->>DB: Create calendar connection + sync calendars
    DB-->>Callback: Connection stored
    Callback-->>Browser: Redirect to calendars page with success message
    UI->>UI: Display connected calendar(s)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Areas requiring extra attention:

  • Meeting Scheduler Detection & AI Integration (apps/web/utils/meetings/detect-meeting-trigger.ts, apps/web/__tests__/ai-parse-meeting-request.test.ts): Logic for pattern matching email subjects/bodies and AI-driven meeting request parsing; verify edge cases (case sensitivity, HTML/text extraction, false positives).
  • Calendar OAuth Flow (apps/web/utils/calendar/oauth-callback-helpers.ts, apps/web/utils/calendar/providers/google.ts, apps/web/utils/calendar/providers/microsoft.ts): Token exchange, state validation, calendar synchronization, and error handling across multiple providers; ensure secure state management and token refresh logic.
  • Provider-Agnostic Email Refactor (apps/web/utils/actions/clean.ts, apps/web/utils/email/microsoft.ts): Replacement of Gmail-only logic with provider-based dispatching; verify correct label/folder mappings and action execution for both Gmail and Outlook (archive, mark read, move, label).
  • Preview Flow Integration (apps/web/app/(app)/[emailAccountId]/clean/PreviewStep.tsx, apps/web/app/(app)/[emailAccountId]/clean/PreviewBatch.tsx): New preview step adds complexity to the clean flow; verify state transitions, error handling, and email stream management during preview runs.
  • Testing Bypasses (apps/web/utils/actions/premium.ts, apps/web/app/(app)/[emailAccountId]/settings/MultiAccountSection.tsx, apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx): Temporary disabling of premium checks and premium credit management; ensure these are intended testing-only changes and do not ship to production.
  • Outlook Webhook Route (apps/web/app/api/outlook/watch/all/route.ts): Removed premium gating may expose Outlook syncing to all users; verify intended scope.
  • Database Schema & Migration (apps/web/prisma/schema.prisma, migration): Six new fields on EmailAccount; verify defaults and backward compatibility for existing accounts.

Possibly related PRs

  • Add calendar connections #775: Both implement overlapping calendar integration work (OAuth routes, calendar providers, availability utilities, calendar connection DB models, API routes, and calendar UI components).
  • Using more Outlook Move to folder action #720: Both modify provider-aware email categorization and cleanup flow to support Outlook alongside Gmail, adding folder helpers and provider-based category mappings.
  • Outlook refactor & Delayed Actions fixes #595: Main PR continues Outlook/email-provider refactor work, expanding provider-agnostic APIs and Outlook-specific routes and webhook handling.

Suggested reviewers

  • elie222
  • anakarentorosserrano-star

🐰 Hop along, the scheduler hops too!
From Gmail to Outlook, now both calendars brew,
With meeting links generated and previews in view,
The inbox cleaner bounces—step back, then break through! ✨📅

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent 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 f4908ee and 2abae54.

⛔ Files ignored due to path filters (1)
  • apps/web/public/images/product/outlook-calendar.svg is excluded by !**/*.svg
📒 Files selected for processing (107)
  • .cursor/rules/cursor-rules.mdc (1 hunks)
  • .cursor/rules/data-fetching.mdc (2 hunks)
  • .cursor/rules/environment-variables.mdc (2 hunks)
  • .cursor/rules/features/cleaner.mdc (1 hunks)
  • .cursor/rules/features/delayed-actions.mdc (1 hunks)
  • .cursor/rules/features/digest.mdc (1 hunks)
  • .cursor/rules/features/knowledge.mdc (1 hunks)
  • .cursor/rules/features/schedule.mdc (1 hunks)
  • .cursor/rules/form-handling.mdc (1 hunks)
  • .cursor/rules/fullstack-workflow.mdc (1 hunks)
  • .cursor/rules/get-api-route.mdc (1 hunks)
  • .cursor/rules/gmail-api.mdc (1 hunks)
  • .cursor/rules/hooks.mdc (1 hunks)
  • .cursor/rules/installing-packages.mdc (1 hunks)
  • .cursor/rules/llm-test.mdc (1 hunks)
  • .cursor/rules/llm.mdc (1 hunks)
  • .cursor/rules/logging.mdc (2 hunks)
  • .cursor/rules/notes.mdc (1 hunks)
  • .cursor/rules/page-structure.mdc (2 hunks)
  • .cursor/rules/posthog-feature-flags.mdc (2 hunks)
  • .cursor/rules/prisma.mdc (2 hunks)
  • .cursor/rules/project-structure.mdc (1 hunks)
  • .cursor/rules/security.mdc (1 hunks)
  • .cursor/rules/server-actions.mdc (2 hunks)
  • .cursor/rules/task-list.mdc (2 hunks)
  • .cursor/rules/testing.mdc (2 hunks)
  • .cursor/rules/ui-components.mdc (2 hunks)
  • .cursor/rules/ultracite.mdc (1 hunks)
  • .cursor/rules/utilities.mdc (2 hunks)
  • .gitignore (1 hunks)
  • .idea/.gitignore (1 hunks)
  • .idea/copilot.data.migration.agent.xml (1 hunks)
  • .idea/copilot.data.migration.ask.xml (1 hunks)
  • .idea/copilot.data.migration.ask2agent.xml (1 hunks)
  • .idea/copilot.data.migration.edit.xml (1 hunks)
  • .idea/inbox-zero.iml (1 hunks)
  • .idea/inspectionProfiles/Project_Default.xml (1 hunks)
  • .idea/modules.xml (1 hunks)
  • .idea/vcs.xml (1 hunks)
  • Cline_Notes/outlook-deep-clean-plan.md (1 hunks)
  • MEETING_SCHEDULER_PLAN.md (1 hunks)
  • README.md (1 hunks)
  • apps/web/MEETING_SCHEDULER_README.md (1 hunks)
  • apps/web/__tests__/ai-parse-meeting-request.test.ts (1 hunks)
  • apps/web/__tests__/detect-meeting-trigger.test.ts (1 hunks)
  • apps/web/__tests__/meeting-provider-validation.test.ts (1 hunks)
  • apps/web/__tests__/meeting-scheduler-settings.test.ts (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (2 hunks)
  • apps/web/app/(app)/[emailAccountId]/calendars/CalendarConnectionCard.tsx (3 hunks)
  • apps/web/app/(app)/[emailAccountId]/calendars/CalendarConnections.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendarButton.tsx (0 hunks)
  • apps/web/app/(app)/[emailAccountId]/calendars/page.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/clean/ActionSelectionStep.tsx (2 hunks)
  • apps/web/app/(app)/[emailAccountId]/clean/CleanInstructionsStep.tsx (3 hunks)
  • apps/web/app/(app)/[emailAccountId]/clean/ConfirmationStep.tsx (5 hunks)
  • apps/web/app/(app)/[emailAccountId]/clean/IntroStep.tsx (0 hunks)
  • apps/web/app/(app)/[emailAccountId]/clean/PreviewBatch.tsx (2 hunks)
  • apps/web/app/(app)/[emailAccountId]/clean/PreviewStep.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/clean/TimeRangeStep.tsx (2 hunks)
  • apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx (2 hunks)
  • apps/web/app/(app)/[emailAccountId]/clean/types.ts (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/clean/useEmailStream.ts (4 hunks)
  • apps/web/app/(app)/[emailAccountId]/clean/useStep.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/settings/MeetingSchedulerSection.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/settings/MultiAccountSection.tsx (3 hunks)
  • apps/web/app/(app)/[emailAccountId]/settings/page.tsx (2 hunks)
  • apps/web/app/api/clean/outlook/route.ts (1 hunks)
  • apps/web/app/api/clean/route.ts (8 hunks)
  • apps/web/app/api/email-stream/route.ts (2 hunks)
  • apps/web/app/api/google/calendar/callback/route.ts (1 hunks)
  • apps/web/app/api/google/webhook/types.ts (1 hunks)
  • apps/web/app/api/outlook/calendar/auth-url/route.ts (1 hunks)
  • apps/web/app/api/outlook/calendar/callback/route.ts (1 hunks)
  • apps/web/app/api/outlook/watch/all/route.ts (2 hunks)
  • apps/web/app/api/outlook/webhook/process-history-item.ts (1 hunks)
  • apps/web/app/api/user/meeting-scheduler-settings/route.ts (1 hunks)
  • apps/web/components/Form.tsx (1 hunks)
  • apps/web/components/ProgressPanel.tsx (2 hunks)
  • apps/web/components/SideNav.tsx (3 hunks)
  • apps/web/components/ui/dropdown-menu.tsx (1 hunks)
  • apps/web/components/ui/tooltip.tsx (2 hunks)
  • apps/web/hooks/useFeatureFlags.ts (1 hunks)
  • apps/web/prisma/migrations/20251102202912_add_meeting_scheduler_settings/migration.sql (1 hunks)
  • apps/web/prisma/schema.prisma (1 hunks)
  • apps/web/providers/AppProviders.tsx (2 hunks)
  • apps/web/utils/actions/clean-preview.ts (1 hunks)
  • apps/web/utils/actions/clean.ts (6 hunks)
  • apps/web/utils/actions/meeting-scheduler.ts (1 hunks)
  • apps/web/utils/actions/meeting-scheduler.validation.ts (1 hunks)
  • apps/web/utils/actions/premium.ts (1 hunks)
  • apps/web/utils/ai/calendar/availability.ts (3 hunks)
  • apps/web/utils/calendar/availability-types.ts (1 hunks)
  • apps/web/utils/calendar/availability.ts (0 hunks)
  • apps/web/utils/calendar/handle-calendar-callback.ts (1 hunks)
  • apps/web/utils/calendar/oauth-callback-helpers.ts (1 hunks)
  • apps/web/utils/calendar/oauth-types.ts (1 hunks)
  • apps/web/utils/calendar/providers/google-availability.ts (1 hunks)
  • apps/web/utils/calendar/providers/google.ts (1 hunks)
  • apps/web/utils/calendar/providers/microsoft-availability.ts (1 hunks)
  • apps/web/utils/calendar/providers/microsoft.ts (1 hunks)
  • apps/web/utils/calendar/unified-availability.ts (1 hunks)
  • apps/web/utils/email/constants.ts (1 hunks)
  • apps/web/utils/email/microsoft.ts (1 hunks)
  • apps/web/utils/meetings/create-calendar-event.ts (1 hunks)
  • apps/web/utils/meetings/create-meeting-link.ts (1 hunks)
  • apps/web/utils/meetings/detect-meeting-trigger.ts (1 hunks)
⛔ Files not processed due to max files limit (15)
  • apps/web/utils/meetings/find-availability.ts
  • apps/web/utils/meetings/parse-meeting-request.ts
  • apps/web/utils/meetings/providers/google-meet.ts
  • apps/web/utils/meetings/providers/teams.ts
  • apps/web/utils/meetings/providers/types.ts
  • apps/web/utils/outlook/calendar-client.ts
  • apps/web/utils/outlook/folders.ts
  • apps/web/utils/outlook/scopes.ts
  • apps/web/utils/outlook/thread.ts
  • apps/web/utils/premium/index.ts
  • apps/web/utils/types.ts
  • apps/web/utils/webhook/process-history-item.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • docker-compose.yml
  • version.txt

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.

@elie222 elie222 closed this Nov 2, 2025
Copy link

@jit-ci jit-ci bot left a comment

Choose a reason for hiding this comment

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

❌ Jit has detected 1 important finding in this PR that you should review.
The finding is detailed below as a comment.
It’s highly recommended that you fix this security issue before merge.

const storedState = request.cookies.get(CALENDAR_STATE_COOKIE_NAME)?.value;

const redirectUrl = new URL("/calendars", request.nextUrl.origin);
const response = NextResponse.redirect(redirectUrl);
Copy link

Choose a reason for hiding this comment

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

Security control: Static Code Analysis Js

Open Redirect Vulnerability In Express Redirect() Method

Untrusted user input in redirect() can result in Open Redirect vulnerability.

Severity: HIGH


Jit Bot commands and options (e.g., ignore issue)

You can trigger Jit actions by commenting on this PR review:

  • #jit_ignore_fp Ignore and mark this specific single instance of finding as “False Positive”
  • #jit_ignore_accept Ignore and mark this specific single instance of finding as “Accept Risk”
  • #jit_ignore_type_in_file Ignore any finding of type "Open Redirect Vulnerability in Express redirect() Method" in apps/web/utils/calendar/oauth-callback-helpers.ts; future occurrences will also be ignored.
  • #jit_undo_ignore Undo ignore command

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.

14 issues found across 123 files

Prompt for AI agents (all 14 issues)

Understand the root cause of the following 14 issues and fix them.


<file name="apps/web/app/api/outlook/watch/all/route.ts">

<violation number="1" location="apps/web/app/api/outlook/watch/all/route.ts:20">
By commenting out the premium checks, this cron will now create Outlook watch subscriptions for every Microsoft-connected account, including non-premium users. That revokes the intended paywall, potentially flooding Outlook with subscriptions and incurring unexpected costs/limits. Please keep the premium gating in place or guard the bypass behind a non-production flag.</violation>
</file>

<file name="apps/web/utils/email/microsoft.ts">

<violation number="1" location="apps/web/utils/email/microsoft.ts:1110">
Returning an empty result here masks provider failures, so callers like /api/threads now respond 200 with zero threads instead of surfacing the underlying error. Please propagate the error (e.g., rethrow after logging) so upstream handlers can return the appropriate failure response.</violation>
</file>

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

<violation number="1" location="apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx:39">
Hard-coding `hasAiAccess` to `true` removes the premium gate for bulk AI processing, letting non-premium users run this costly feature. Please restore the `usePremium()` check instead of bypassing it.</violation>
</file>

<file name="apps/web/utils/premium/index.ts">

<violation number="1" location="apps/web/utils/premium/index.ts:19">
Returning true here bypasses the real Stripe/Lemon Squeezy premium checks, so every user is treated as premium and gains paid features without a subscription.</violation>
</file>

<file name="apps/web/utils/actions/clean-preview.ts">

<violation number="1" location="apps/web/utils/actions/clean-preview.ts:84">
The Outlook preview path ignores the `daysOld` filter, so Microsoft users will see messages outside the intended window; the date constraint needs to be applied when fetching Outlook messages.</violation>
</file>

<file name=".cursor/rules/features/digest.mdc">

<violation number="1" location=".cursor/rules/features/digest.mdc:2">
Removing the closing ``` leaves the final TypeScript code block unterminated, which breaks Markdown rendering for the remainder of the document.</violation>
</file>

<file name="apps/web/utils/webhook/process-history-item.ts">

<violation number="1" location="apps/web/utils/webhook/process-history-item.ts:168">
This code calls the AI parser before we verify hasAiAccess. Accounts without AI access (but with meetingSchedulerEnabled) will still invoke aiParseMeetingRequest and fail every time a trigger fires. Please gate the meeting-scheduler flow behind the existing hasAiAccess check.</violation>
</file>

<file name="apps/web/app/api/clean/outlook/route.ts">

<violation number="1" location="apps/web/app/api/clean/outlook/route.ts:77">
This retrieves only the first page of conversation messages from Microsoft Graph, so longer threads keep their later messages untouched. Please loop through @odata.nextLink to process the entire conversation.</violation>
</file>

<file name="apps/web/utils/meetings/find-availability.ts">

<violation number="1" location="apps/web/utils/meetings/find-availability.ts:263">
Past requested times are being returned as available. Please skip any slot whose start is before the current time so we don’t suggest already-expired windows to the user.</violation>
</file>

<file name="apps/web/utils/meetings/detect-meeting-trigger.ts">

<violation number="1" location="apps/web/utils/meetings/detect-meeting-trigger.ts:89">
HTML meeting-trigger detection should normalize the markup before running the regex; otherwise formatted emails like `&lt;p&gt;/schedule &lt;strong&gt;meeting&lt;/strong&gt;&lt;/p&gt;` will never trigger the scheduler.</violation>
</file>

<file name="apps/web/prisma/schema.prisma">

<violation number="1" location="apps/web/prisma/schema.prisma:134">
Defaulting `meetingSchedulerEnabled` to true causes every account to appear enabled and skips the false→true transition that provisions the Outlook webhook, so first-time enabling never auto-configures the webhook. Please default this flag to false.</violation>
</file>

<file name="MEETING_SCHEDULER_PLAN.md">

<violation number="1" location="MEETING_SCHEDULER_PLAN.md:307">
Setting `identity.user.id` to the attendee email will make the Graph /me/onlineMeetings call fail because that field must be the Azure AD object id or use the `upn` property for email addresses.</violation>

<violation number="2" location="MEETING_SCHEDULER_PLAN.md:631">
`sendEmail` is given `emailAccountId`, which is an internal id rather than the organizer&#39;s email address, so the notification will never reach the user.</violation>
</file>

<file name="apps/web/app/(app)/[emailAccountId]/clean/useEmailStream.ts">

<violation number="1" location="apps/web/app/(app)/[emailAccountId]/clean/useEmailStream.ts:141">
The delayed SSE cleanup keeps the previous EventSource alive when the component remounts quickly (e.g., after `emailAccountId` changes), leaving `eventSourceRef.current` populated so the next `connectToSSE()` aborts. This prevents establishing a stream for the new account and leaves the UI stuck on the old data.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

],
},
},
// TEMPORARILY DISABLED FOR TESTING - All Microsoft accounts included
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 3, 2025

Choose a reason for hiding this comment

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

By commenting out the premium checks, this cron will now create Outlook watch subscriptions for every Microsoft-connected account, including non-premium users. That revokes the intended paywall, potentially flooding Outlook with subscriptions and incurring unexpected costs/limits. Please keep the premium gating in place or guard the bypass behind a non-production flag.

Prompt for AI agents
Address the following comment on apps/web/app/api/outlook/watch/all/route.ts at line 20:

<comment>By commenting out the premium checks, this cron will now create Outlook watch subscriptions for every Microsoft-connected account, including non-premium users. That revokes the intended paywall, potentially flooding Outlook with subscriptions and incurring unexpected costs/limits. Please keep the premium gating in place or guard the bypass behind a non-production flag.</comment>

<file context>
@@ -18,14 +17,15 @@ async function watchAllEmails() {
-          ],
-        },
-      },
+      // TEMPORARILY DISABLED FOR TESTING - All Microsoft accounts included
+      // user: {
+      //   premium: {
</file context>
Fix with Cubic

const toAddress =
message.toRecipients?.[0]?.emailAddress?.address || "";

return {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 3, 2025

Choose a reason for hiding this comment

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

Returning an empty result here masks provider failures, so callers like /api/threads now respond 200 with zero threads instead of surfacing the underlying error. Please propagate the error (e.g., rethrow after logging) so upstream handlers can return the appropriate failure response.

Prompt for AI agents
Address the following comment on apps/web/utils/email/microsoft.ts at line 1110:

<comment>Returning an empty result here masks provider failures, so callers like /api/threads now respond 200 with zero threads instead of surfacing the underlying error. Please propagate the error (e.g., rethrow after logging) so upstream handlers can return the appropriate failure response.</comment>

<file context>
@@ -960,188 +960,204 @@ export class OutlookProvider implements EmailProvider {
+            const toAddress =
+              message.toRecipients?.[0]?.emailAddress?.address || &quot;&quot;;
+
+            return {
+              id: message.id || &quot;&quot;,
+              threadId: message.conversationId || &quot;&quot;,
</file context>
Fix with Cubic


const { hasAiAccess, isLoading: isLoadingPremium } = usePremium();
// Temporarily disable premium check for testing
const hasAiAccess = true;
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 3, 2025

Choose a reason for hiding this comment

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

Hard-coding hasAiAccess to true removes the premium gate for bulk AI processing, letting non-premium users run this costly feature. Please restore the usePremium() check instead of bypassing it.

Prompt for AI agents
Address the following comment on apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx at line 39:

<comment>Hard-coding `hasAiAccess` to `true` removes the premium gate for bulk AI processing, letting non-premium users run this costly feature. Please restore the `usePremium()` check instead of bypassing it.</comment>

<file context>
@@ -35,7 +35,10 @@ export function BulkRunRules() {
 
-  const { hasAiAccess, isLoading: isLoadingPremium } = usePremium();
+  // Temporarily disable premium check for testing
+  const hasAiAccess = true;
+  const isLoadingPremium = false;
+  // const { hasAiAccess, isLoading: isLoadingPremium } = usePremium();
</file context>
Fix with Cubic

isPremiumLemonSqueezy(lemonSqueezyRenewsAt)
);
// Premium enabled for all users permanently
return true;
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 3, 2025

Choose a reason for hiding this comment

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

Returning true here bypasses the real Stripe/Lemon Squeezy premium checks, so every user is treated as premium and gains paid features without a subscription.

Prompt for AI agents
Address the following comment on apps/web/utils/premium/index.ts at line 19:

<comment>Returning true here bypasses the real Stripe/Lemon Squeezy premium checks, so every user is treated as premium and gains paid features without a subscription.</comment>

<file context>
@@ -15,10 +15,12 @@ export const isPremium = (
-    isPremiumLemonSqueezy(lemonSqueezyRenewsAt)
-  );
+  // Premium enabled for all users permanently
+  return true;
+  // return (
+  //   isPremiumStripe(stripeSubscriptionStatus) ||
</file context>
Suggested change
return true;
return isPremiumStripe(stripeSubscriptionStatus) || isPremiumLemonSqueezy(lemonSqueezyRenewsAt);
Fix with Cubic

emailAccountId: emailAccount.id,
});

const { messages } = await getOutlookMessages(outlook, {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 3, 2025

Choose a reason for hiding this comment

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

The Outlook preview path ignores the daysOld filter, so Microsoft users will see messages outside the intended window; the date constraint needs to be applied when fetching Outlook messages.

Prompt for AI agents
Address the following comment on apps/web/utils/actions/clean-preview.ts at line 84:

<comment>The Outlook preview path ignores the `daysOld` filter, so Microsoft users will see messages outside the intended window; the date constraint needs to be applied when fetching Outlook messages.</comment>

<file context>
@@ -0,0 +1,105 @@
+          emailAccountId: emailAccount.id,
+        });
+
+        const { messages } = await getOutlookMessages(outlook, {
+          query: &quot;&quot;,
+          maxResults: PREVIEW_RUN_COUNT,
</file context>
Fix with Cubic

: false;

const hasScheduleInHtmlBody = htmlBody
? scheduleCommandPattern.test(htmlBody)
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 3, 2025

Choose a reason for hiding this comment

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

HTML meeting-trigger detection should normalize the markup before running the regex; otherwise formatted emails like <p>/schedule <strong>meeting</strong></p> will never trigger the scheduler.

Prompt for AI agents
Address the following comment on apps/web/utils/meetings/detect-meeting-trigger.ts at line 89:

<comment>HTML meeting-trigger detection should normalize the markup before running the regex; otherwise formatted emails like `&lt;p&gt;/schedule &lt;strong&gt;meeting&lt;/strong&gt;&lt;/p&gt;` will never trigger the scheduler.</comment>

<file context>
@@ -0,0 +1,143 @@
+    : false;
+
+  const hasScheduleInHtmlBody = htmlBody
+    ? scheduleCommandPattern.test(htmlBody)
+    : false;
+
</file context>
Fix with Cubic

multiRuleSelectionEnabled Boolean @default(false)

// Meeting Scheduler settings
meetingSchedulerEnabled Boolean @default(true) // Enable/disable automatic meeting scheduling
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 3, 2025

Choose a reason for hiding this comment

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

Defaulting meetingSchedulerEnabled to true causes every account to appear enabled and skips the false→true transition that provisions the Outlook webhook, so first-time enabling never auto-configures the webhook. Please default this flag to false.

Prompt for AI agents
Address the following comment on apps/web/prisma/schema.prisma at line 134:

<comment>Defaulting `meetingSchedulerEnabled` to true causes every account to appear enabled and skips the false→true transition that provisions the Outlook webhook, so first-time enabling never auto-configures the webhook. Please default this flag to false.</comment>

<file context>
@@ -130,6 +130,14 @@ model EmailAccount {
   multiRuleSelectionEnabled Boolean           @default(false)
 
+  // Meeting Scheduler settings
+  meetingSchedulerEnabled            Boolean @default(true) // Enable/disable automatic meeting scheduling
+  meetingSchedulerDefaultDuration    Int     @default(60) // Default meeting duration in minutes (30, 60, 90)
+  meetingSchedulerPreferredProvider  String? // Preferred meeting provider: &#39;auto&#39;, &#39;teams&#39;, &#39;google-meet&#39;, &#39;zoom&#39;, &#39;none&#39;
</file context>
Suggested change
meetingSchedulerEnabled Boolean @default(true) // Enable/disable automatic meeting scheduling
meetingSchedulerEnabled Boolean @default(false) // Enable/disable automatic meeting scheduling
Fix with Cubic


// Send notification email to organizer
await sendEmail({
to: [emailAccountId], // Send to self
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 3, 2025

Choose a reason for hiding this comment

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

sendEmail is given emailAccountId, which is an internal id rather than the organizer's email address, so the notification will never reach the user.

Prompt for AI agents
Address the following comment on MEETING_SCHEDULER_PLAN.md at line 631:

<comment>`sendEmail` is given `emailAccountId`, which is an internal id rather than the organizer&#39;s email address, so the notification will never reach the user.</comment>

<file context>
@@ -0,0 +1,1020 @@
+
+  // Send notification email to organizer
+  await sendEmail({
+    to: [emailAccountId], // Send to self
+    subject: `Meeting Scheduled: ${eventDetails.title}`,
+    body: emailBody,
</file context>
Fix with Cubic

attendees: participants.map(email => ({
identity: {
user: {
id: email
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 3, 2025

Choose a reason for hiding this comment

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

Setting identity.user.id to the attendee email will make the Graph /me/onlineMeetings call fail because that field must be the Azure AD object id or use the upn property for email addresses.

Prompt for AI agents
Address the following comment on MEETING_SCHEDULER_PLAN.md at line 307:

<comment>Setting `identity.user.id` to the attendee email will make the Graph /me/onlineMeetings call fail because that field must be the Azure AD object id or use the `upn` property for email addresses.</comment>

<file context>
@@ -0,0 +1,1020 @@
+        attendees: participants.map(email =&gt; ({
+          identity: {
+            user: {
+              id: email
+            }
+          }
</file context>
Fix with Cubic

}
isMountedRef.current = false;
// Don't close connection immediately - wait to see if component remounts
setTimeout(() => {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 3, 2025

Choose a reason for hiding this comment

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

The delayed SSE cleanup keeps the previous EventSource alive when the component remounts quickly (e.g., after emailAccountId changes), leaving eventSourceRef.current populated so the next connectToSSE() aborts. This prevents establishing a stream for the new account and leaves the UI stuck on the old data.

Prompt for AI agents
Address the following comment on apps/web/app/(app)/[emailAccountId]/clean/useEmailStream.ts at line 141:

<comment>The delayed SSE cleanup keeps the previous EventSource alive when the component remounts quickly (e.g., after `emailAccountId` changes), leaving `eventSourceRef.current` populated so the next `connectToSSE()` aborts. This prevents establishing a stream for the new account and leaves the UI stuck on the old data.</comment>

<file context>
@@ -89,38 +100,58 @@ export function useEmailStream(
-      }
+      isMountedRef.current = false;
+      // Don&#39;t close connection immediately - wait to see if component remounts
+      setTimeout(() =&gt; {
+        if (!isMountedRef.current) {
+          console.log(&quot;Cleaning up SSE connection (component unmounted)&quot;);
</file context>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments