Skip to content

Conversation

@2witstudios
Copy link
Owner

@2witstudios 2witstudios commented Jan 15, 2026

…ents

This adds a notification system for user mentions and task assignments:

  • Add MENTION and TASK_ASSIGNED notification types to schema
  • Create user_mentions table to track when users are @mentioned in pages
  • Add createMentionNotification and createTaskAssignedNotification helpers
  • Update page-mention-service to parse user mentions and create notifications
  • Add notification creation when tasks are assigned to users
  • Update NotificationDropdown with icons and navigation for new types
  • Include database migration for schema changes

Users will now receive notifications in the notification bell when:

  • They are @mentioned in a page (using @Name format)
  • A task is assigned to them in a task list

Summary by CodeRabbit

  • New Features
    • Receive notifications when mentioned in a page.
    • Receive notifications when assigned to a task.
    • New icons for mention and task-assignment notifications in the UI.
    • Tap notification to navigate directly to the related page or task list.
    • Mention-driven notifications are now delivered (including email pathways) when new mentions occur.

✏️ Tip: You can customize this high-level summary in your review settings.

…ents

This adds a notification system for user mentions and task assignments:

- Add MENTION and TASK_ASSIGNED notification types to schema
- Create user_mentions table to track when users are @mentioned in pages
- Add createMentionNotification and createTaskAssignedNotification helpers
- Update page-mention-service to parse user mentions and create notifications
- Add notification creation when tasks are assigned to users
- Update NotificationDropdown with icons and navigation for new types
- Include database migration for schema changes

Users will now receive notifications in the notification bell when:
- They are @mentioned in a page (using @[Name](userId:user) format)
- A task is assigned to them in a task list
@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

Adds mention and task-assigned notifications: DB migration and schema for user mentions; mention extraction/sync returns structured user/page IDs; notification creators for MENTION and TASK_ASSIGNED; code paths fire-and-forget notifications on new mentions and task assignee changes; UI shows icons and navigation for these notifications.

Changes

Cohort / File(s) Summary
Database Schema & Migrations
packages/db/drizzle/0038_salty_phalanx.sql, packages/db/drizzle/meta/_journal.json, packages/db/src/schema/core.ts, packages/db/src/schema/notifications.ts
Adds user_mentions table with FK constraints and indexes; appends MENTION and TASK_ASSIGNED to NotificationType enum; journal entry for migration.
Notification Types & Creators
packages/lib/src/notifications/types.ts, packages/lib/src/notifications/notifications.ts, packages/lib/src/services/notification-email-service.ts, packages/lib/package.json
New notification types (MentionNotification, TaskAssignedNotification) and exported creators createMentionNotification and createTaskAssignedNotification; package exports/types updated; email service type union extended.
Mention Sync & Mutation Flow
apps/web/src/services/api/page-mention-service.ts, apps/web/src/services/api/page-mutation-service.ts, apps/web/src/services/api/rollback-service.ts
findMentionNodes refactored to return { pageIds, userIds }; syncMentions signature and result updated (SyncMentionsResult); added syncPageMentions and syncUserMentions; callers (mutation and rollback) pass mentionedByUserId and propagate/record mentionsResult; post-commit/rollback fire-and-forget mention notifications for newly mentioned users.
Task Route
apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts
PATCH handler now triggers a non-blocking createTaskAssignedNotification when assigneeId changes to a different non-null user (after update, before broadcast).
UI Notifications
apps/web/src/components/notifications/NotificationDropdown.tsx
Adds icon mappings for MENTION and TASK_ASSIGNED and navigation handling to /dashboard/{driveId}/{pageId} when notification includes pageId and driveId.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant API as Page Mutation API
    participant MentionSvc as Mention Service
    participant DB as Database
    participant NotifSvc as Notification Service
    participant Email as Email System

    User->>API: PATCH page content (with mentions)
    API->>MentionSvc: syncMentions(sourcePageId, content, tx, {mentionedByUserId})
    MentionSvc->>MentionSvc: Extract pageIds & userIds (HTML/Markdown)
    MentionSvc->>DB: Update page_mentions & user_mentions within tx
    DB-->>MentionSvc: tx commit
    MentionSvc->>NotifSvc: createMentionNotification for newlyMentionedUserIds (fire-and-forget)
    NotifSvc->>DB: Insert MENTION notification
    NotifSvc->>Email: Trigger email send (async)
    API-->>User: HTTP response (no wait for notifications)
Loading
sequenceDiagram
    actor User
    participant API as Task PATCH Endpoint
    participant DB as Database
    participant NotifSvc as Notification Service
    participant Email as Email System

    User->>API: PATCH task (change assignee)
    API->>DB: Update task record
    DB-->>API: Task updated
    API->>API: Detect assignee change (new non-null assignee)
    API->>NotifSvc: createTaskAssignedNotification(targetUserId, taskId, ...) (fire-and-forget)
    NotifSvc->>DB: Insert TASK_ASSIGNED notification
    NotifSvc->>Email: Trigger email send (async)
    API-->>User: HTTP response (no wait for notification)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I nibble at code and hop with delight,
Mentions and tasks now sparkle in sight,
Tables and types, notifications take flight,
Fire-and-forget whispers through day and night,
Hop on — collaboration's feeling just right! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and concisely describes the main feature being added: notifications for @mentions and task assignments, which is the primary focus of this comprehensive changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
apps/web/src/services/api/page-mutation-service.ts (1)

276-287: Remove redundant type assertion.

Line 278 casts mentionsResult as SyncMentionsResult, but the variable is already typed as SyncMentionsResult | null and the if (mentionsResult) check on line 277 narrows it to SyncMentionsResult. The cast is unnecessary.

♻️ Suggested fix
   // Send notifications for newly mentioned users after transaction commits (fire-and-forget)
   if (mentionsResult) {
-    const result = mentionsResult as SyncMentionsResult;
-    if (result.mentionedByUserId && result.newlyMentionedUserIds.length > 0) {
-      for (const targetUserId of result.newlyMentionedUserIds) {
-        createMentionNotification(targetUserId, result.sourcePageId, result.mentionedByUserId)
+    if (mentionsResult.mentionedByUserId && mentionsResult.newlyMentionedUserIds.length > 0) {
+      for (const targetUserId of mentionsResult.newlyMentionedUserIds) {
+        createMentionNotification(targetUserId, mentionsResult.sourcePageId, mentionsResult.mentionedByUserId)
           .catch((error: unknown) => {
             loggers.api.error('Failed to send mention notification:', error as Error);
           });
       }
     }
   }

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e3cc8d8 and 765ef09.

📒 Files selected for processing (3)
  • apps/web/src/services/api/page-mention-service.ts
  • apps/web/src/services/api/page-mutation-service.ts
  • apps/web/src/services/api/rollback-service.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Never use any types - always use proper TypeScript types
Use camelCase for variable and function names
Use UPPER_SNAKE_CASE for constants
Use PascalCase for type and enum names
Use kebab-case for filenames, except React hooks (camelCase with use prefix), Zustand stores (camelCase with use prefix), and React components (PascalCase)
Lint with Next/ESLint as configured in apps/web/eslint.config.mjs
Message content should always use the message parts structure with { parts: [{ type: 'text', text: '...' }] }
Use centralized permission functions from @pagespace/lib/permissions (e.g., getUserAccessLevel, canUserEditPage) instead of implementing permission logic locally
Always use Drizzle client from @pagespace/db package for database access
Use ESM modules throughout the codebase

**/*.{ts,tsx}: Never use any types - always use proper TypeScript types
Write code that is explicit over implicit and self-documenting

Files:

  • apps/web/src/services/api/page-mutation-service.ts
  • apps/web/src/services/api/rollback-service.ts
  • apps/web/src/services/api/page-mention-service.ts
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.ts: React hook files should use camelCase matching the exported hook name (e.g., useAuth.ts)
Zustand store files should use camelCase with use prefix (e.g., useAuthStore.ts)

Files:

  • apps/web/src/services/api/page-mutation-service.ts
  • apps/web/src/services/api/rollback-service.ts
  • apps/web/src/services/api/page-mention-service.ts
**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Format code with Prettier

Files:

  • apps/web/src/services/api/page-mutation-service.ts
  • apps/web/src/services/api/rollback-service.ts
  • apps/web/src/services/api/page-mention-service.ts
apps/web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/src/**/*.{ts,tsx}: Use message parts structure for message content: { parts: [{ type: 'text', text: '...' }] }
For database access, always use Drizzle client from @pagespace/db: import { db, pages } from '@pagespace/db';
Use centralized Drizzle ORM with PostgreSQL for all database operations - no direct SQL or other ORMs
Use Socket.IO for real-time collaboration features - imported from the realtime service at port 3001
Use Vercel AI SDK with async/await for all AI operations and streaming
Use Next.js 15 App Router and TypeScript for all routes and components

Files:

  • apps/web/src/services/api/page-mutation-service.ts
  • apps/web/src/services/api/rollback-service.ts
  • apps/web/src/services/api/page-mention-service.ts
🧬 Code graph analysis (3)
apps/web/src/services/api/page-mutation-service.ts (3)
apps/web/src/services/api/page-mention-service.ts (2)
  • SyncMentionsResult (69-73)
  • syncMentions (75-94)
packages/lib/src/notifications/notifications.ts (1)
  • createMentionNotification (353-392)
packages/lib/src/logging/logger-config.ts (1)
  • loggers (8-18)
apps/web/src/services/api/rollback-service.ts (2)
apps/web/src/services/api/page-mention-service.ts (2)
  • SyncMentionsResult (69-73)
  • syncMentions (75-94)
packages/lib/src/notifications/notifications.ts (1)
  • createMentionNotification (353-392)
apps/web/src/services/api/page-mention-service.ts (1)
packages/db/src/schema/core.ts (1)
  • userMentions (149-161)
🔇 Additional comments (9)
apps/web/src/services/api/page-mention-service.ts (3)

8-63: LGTM! Mention parsing correctly extracts both page and user mentions.

The findMentionNodes function properly handles:

  • HTML parsing with data-page-id and data-user-id attributes
  • Markdown-style @[Label](id:type) format with default type fallback
  • Deduplication via Set

The error handling for HTML parsing gracefully falls back to regex parsing.


65-94: Good fix for the race condition.

The refactoring correctly addresses the previous race condition concern by:

  1. Returning newlyMentionedUserIds instead of dispatching notifications internally
  2. Providing sourcePageId and mentionedByUserId in the result for callers to use
  3. Removing the setTimeout hack

Callers can now send notifications after their transactions commit.


127-161: LGTM! Clean implementation following the established pattern.

The syncUserMentions function correctly:

  • Computes the diff between current and desired mentions
  • Inserts new mentions with proper fields matching the schema
  • Deletes stale mentions
  • Returns only newly created user IDs for notification dispatch
apps/web/src/services/api/page-mutation-service.ts (2)

192-221: LGTM! Correct integration of mention syncing with user context.

The changes properly:

  • Track mentionsResult to capture newly mentioned users
  • Pass mentionedByUserId: context.userId to associate mentions with the actor
  • Store the result for post-commit notification dispatch

268-287: Verify: Notifications may still fire before external transaction commits.

When tx is provided by the caller (line 268), the notification dispatch at lines 276-287 runs after applyMutationInTx completes but before the external transaction commits. If the caller's transaction rolls back after applyPageMutation returns, notifications will have been sent for mentions that weren't persisted.

This edge case might be acceptable given:

  • External transaction rollbacks are rare
  • Spurious notifications have low user impact

If strict consistency is required, consider returning mentionsResult in ApplyPageMutationResult so callers with external transactions can dispatch notifications after their commit.

apps/web/src/services/api/rollback-service.ts (4)

36-37: LGTM! Imports correctly added.


279-288: LGTM! Interface correctly extended to propagate mention results.

Adding mentionsResult to PageMutationMeta enables the rollback flow to track newly mentioned users and dispatch notifications after operations complete.


395-427: LGTM! Mention syncing correctly integrated into rollback's page update flow.

The changes properly:

  • Capture mentionsResult when content is updated during rollback
  • Pass mentionedByUserId from options to track the actor
  • Return the result in PageMutationMeta for post-operation notification dispatch

1804-1814: LGTM! Notification dispatch follows the established pattern.

The implementation correctly:

  • Checks for both mentionedByUserId and non-empty newlyMentionedUserIds
  • Uses fire-and-forget with error logging
  • Fires notifications after the rollback operations complete

The same edge case noted for page-mutation-service.ts applies here when tx is provided externally, but this is consistent with the established pattern.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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.

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

🤖 Fix all issues with AI agents
In `@apps/web/src/services/api/page-mention-service.ts`:
- Around line 140-152: The setTimeout-based dispatch in syncUserMentions can
send notifications before the DB transaction commits; remove the setTimeout
block and instead return the toCreate array (and sourcePageId/mentionedByUserId
context as needed) from syncUserMentions so the caller can iterate over
newlyMentioned user IDs and call createMentionNotification for each only after
the transaction successfully commits; update callers to perform the notification
loop and error-logging (loggers.api.error) after commit to avoid race/rollback
issues.
🧹 Nitpick comments (1)
packages/db/src/schema/core.ts (1)

148-161: Consider using a unique constraint instead of a regular index for sourceUserKey.

The sourceUserKey index on (sourcePageId, targetUserId) appears to enforce uniqueness semantically (one mention record per user per page). If duplicate mentions for the same user on the same page should be prevented at the database level, consider using uniqueIndex instead of index.

♻️ Optional: Use uniqueIndex for deduplication at DB level
 }, (table) => {
     return {
-        sourceUserKey: index('user_mentions_source_page_id_target_user_id_key').on(table.sourcePageId, table.targetUserId),
+        sourceUserKey: uniqueIndex('user_mentions_source_page_id_target_user_id_key').on(table.sourcePageId, table.targetUserId),
         sourcePageIdx: index('user_mentions_source_page_id_idx').on(table.sourcePageId),
         targetUserIdx: index('user_mentions_target_user_id_idx').on(table.targetUserId),
     }
 });

Note: This would require importing uniqueIndex from drizzle-orm/pg-core and regenerating the migration.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b5dd39 and e3cc8d8.

📒 Files selected for processing (14)
  • apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts
  • apps/web/src/components/notifications/NotificationDropdown.tsx
  • apps/web/src/services/api/page-mention-service.ts
  • apps/web/src/services/api/page-mutation-service.ts
  • apps/web/src/services/api/rollback-service.ts
  • packages/db/drizzle/0038_salty_phalanx.sql
  • packages/db/drizzle/meta/0038_snapshot.json
  • packages/db/drizzle/meta/_journal.json
  • packages/db/src/schema/core.ts
  • packages/db/src/schema/notifications.ts
  • packages/lib/package.json
  • packages/lib/src/notifications/notifications.ts
  • packages/lib/src/notifications/types.ts
  • packages/lib/src/services/notification-email-service.ts
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Format code with Prettier

Files:

  • packages/db/drizzle/meta/_journal.json
  • apps/web/src/services/api/rollback-service.ts
  • apps/web/src/services/api/page-mutation-service.ts
  • packages/lib/package.json
  • packages/db/src/schema/notifications.ts
  • apps/web/src/components/notifications/NotificationDropdown.tsx
  • apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts
  • packages/lib/src/notifications/types.ts
  • packages/lib/src/services/notification-email-service.ts
  • packages/db/src/schema/core.ts
  • packages/lib/src/notifications/notifications.ts
  • apps/web/src/services/api/page-mention-service.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Never use any types - always use proper TypeScript types
Use camelCase for variable and function names
Use UPPER_SNAKE_CASE for constants
Use PascalCase for type and enum names
Use kebab-case for filenames, except React hooks (camelCase with use prefix), Zustand stores (camelCase with use prefix), and React components (PascalCase)
Lint with Next/ESLint as configured in apps/web/eslint.config.mjs
Message content should always use the message parts structure with { parts: [{ type: 'text', text: '...' }] }
Use centralized permission functions from @pagespace/lib/permissions (e.g., getUserAccessLevel, canUserEditPage) instead of implementing permission logic locally
Always use Drizzle client from @pagespace/db package for database access
Use ESM modules throughout the codebase

**/*.{ts,tsx}: Never use any types - always use proper TypeScript types
Write code that is explicit over implicit and self-documenting

Files:

  • apps/web/src/services/api/rollback-service.ts
  • apps/web/src/services/api/page-mutation-service.ts
  • packages/db/src/schema/notifications.ts
  • apps/web/src/components/notifications/NotificationDropdown.tsx
  • apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts
  • packages/lib/src/notifications/types.ts
  • packages/lib/src/services/notification-email-service.ts
  • packages/db/src/schema/core.ts
  • packages/lib/src/notifications/notifications.ts
  • apps/web/src/services/api/page-mention-service.ts
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.ts: React hook files should use camelCase matching the exported hook name (e.g., useAuth.ts)
Zustand store files should use camelCase with use prefix (e.g., useAuthStore.ts)

Files:

  • apps/web/src/services/api/rollback-service.ts
  • apps/web/src/services/api/page-mutation-service.ts
  • packages/db/src/schema/notifications.ts
  • apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts
  • packages/lib/src/notifications/types.ts
  • packages/lib/src/services/notification-email-service.ts
  • packages/db/src/schema/core.ts
  • packages/lib/src/notifications/notifications.ts
  • apps/web/src/services/api/page-mention-service.ts
apps/web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/src/**/*.{ts,tsx}: Use message parts structure for message content: { parts: [{ type: 'text', text: '...' }] }
For database access, always use Drizzle client from @pagespace/db: import { db, pages } from '@pagespace/db';
Use centralized Drizzle ORM with PostgreSQL for all database operations - no direct SQL or other ORMs
Use Socket.IO for real-time collaboration features - imported from the realtime service at port 3001
Use Vercel AI SDK with async/await for all AI operations and streaming
Use Next.js 15 App Router and TypeScript for all routes and components

Files:

  • apps/web/src/services/api/rollback-service.ts
  • apps/web/src/services/api/page-mutation-service.ts
  • apps/web/src/components/notifications/NotificationDropdown.tsx
  • apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts
  • apps/web/src/services/api/page-mention-service.ts
packages/db/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Drizzle ORM for database queries with PostgreSQL

Files:

  • packages/db/src/schema/notifications.ts
  • packages/db/src/schema/core.ts
packages/db/src/schema/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Database schema changes must be made in packages/db/src/schema/ and then pnpm db:generate must be run to create migrations

Files:

  • packages/db/src/schema/notifications.ts
  • packages/db/src/schema/core.ts
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/*.tsx: React component files should use PascalCase (e.g., UserProfile.tsx)
Use @dnd-kit for drag-and-drop functionality
Use Zustand for client state management
Use SWR for server state management and caching

Files:

  • apps/web/src/components/notifications/NotificationDropdown.tsx
**/*.{tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use Tailwind CSS and shadcn/ui components for styling and UI

Files:

  • apps/web/src/components/notifications/NotificationDropdown.tsx
apps/web/src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/src/components/**/*.{ts,tsx}: When document editing, register editing state with useEditingStore.getState().startEditing() to prevent UI refreshes, and clean up in return statement
When AI is streaming, register streaming state with useEditingStore.getState().startStreaming() to prevent UI refreshes, and clean up in return statement
For SWR data fetching with editing protection, use isPaused: () => hasLoadedRef.current && isEditingActive() to allow initial fetch and only pause after, with revalidateOnFocus: false
Use Zustand for client-side state management as the primary state solution
Use SWR for server state and caching with proper configuration including revalidateOnFocus: false for editing protection
Use TipTap rich text editor with markdown support for document editing
Use Monaco Editor for code editing features
Use @dnd-kit for drag-and-drop functionality instead of other libraries
Use Tailwind CSS with shadcn/ui components for all UI styling and components

Files:

  • apps/web/src/components/notifications/NotificationDropdown.tsx
apps/web/src/app/**/route.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/web/src/app/**/route.{ts,tsx}: In Next.js 15 route handlers, params in dynamic routes are Promise objects and MUST be awaited before destructuring
Use Response.json() or NextResponse.json() for returning JSON from route handlers
Get request body using const body = await request.json();
Get search parameters using const { searchParams } = new URL(request.url);

apps/web/src/app/**/route.{ts,tsx}: In Next.js 15 dynamic routes, params are Promise objects and MUST be awaited before destructuring: const { id } = await context.params;
In Route Handlers, get request body with const body = await request.json();
In Route Handlers, get search parameters with const { searchParams } = new URL(request.url);
In Route Handlers, return JSON using Response.json(data) or NextResponse.json(data)
For permission logic, use centralized functions from @pagespace/lib/permissions: getUserAccessLevel(), canUserEditPage()

Files:

  • apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts
**/*ai*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Vercel AI SDK for AI integrations

Files:

  • packages/lib/src/services/notification-email-service.ts
🧠 Learnings (6)
📚 Learning: 2025-12-22T20:04:40.910Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T20:04:40.910Z
Learning: Applies to **/*.{ts,tsx} : Use ESM modules throughout the codebase

Applied to files:

  • packages/lib/package.json
📚 Learning: 2025-12-14T14:54:45.713Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-14T14:54:45.713Z
Learning: Use TypeScript strict mode and ESM modules throughout the codebase

Applied to files:

  • packages/lib/package.json
📚 Learning: 2025-12-22T20:04:40.910Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T20:04:40.910Z
Learning: Applies to packages/db/src/schema.ts : Update database schema in `packages/db/src/schema.ts` and generate migrations with `pnpm db:generate`

Applied to files:

  • packages/db/src/schema/notifications.ts
  • packages/db/src/schema/core.ts
📚 Learning: 2025-12-14T14:54:45.713Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-14T14:54:45.713Z
Learning: Applies to packages/db/src/schema.ts : Maintain the Drizzle ORM database schema in `packages/db/src/schema.ts` as the single entry point for schema definitions

Applied to files:

  • packages/db/src/schema/core.ts
📚 Learning: 2025-12-22T20:04:40.910Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T20:04:40.910Z
Learning: Applies to packages/db/src/schema.ts : Database schema entry point is at `packages/db/src/schema.ts`; migrations emit to `packages/db/drizzle/`

Applied to files:

  • packages/db/src/schema/core.ts
📚 Learning: 2025-12-23T18:49:41.966Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-23T18:49:41.966Z
Learning: Applies to packages/db/src/schema/**/*.{ts,tsx} : Database schema changes must be made in `packages/db/src/schema/` and then `pnpm db:generate` must be run to create migrations

Applied to files:

  • packages/db/src/schema/core.ts
🧬 Code graph analysis (6)
apps/web/src/services/api/rollback-service.ts (1)
apps/web/src/services/api/page-mention-service.ts (1)
  • syncMentions (70-83)
apps/web/src/services/api/page-mutation-service.ts (1)
apps/web/src/services/api/page-mention-service.ts (1)
  • syncMentions (70-83)
apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts (1)
packages/lib/src/notifications/notifications.ts (1)
  • createTaskAssignedNotification (397-440)
packages/db/src/schema/core.ts (1)
packages/db/src/schema/auth.ts (1)
  • users (10-33)
packages/lib/src/notifications/notifications.ts (2)
packages/db/src/index.ts (1)
  • db (20-20)
packages/db/src/schema/core.ts (1)
  • pages (24-68)
apps/web/src/services/api/page-mention-service.ts (2)
packages/db/src/schema/core.ts (1)
  • userMentions (149-161)
packages/lib/src/notifications/notifications.ts (1)
  • createMentionNotification (353-392)
⏰ 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). (2)
  • GitHub Check: Unit Tests
  • GitHub Check: Lint & TypeScript Check
🔇 Additional comments (23)
packages/db/drizzle/meta/_journal.json (1)

270-277: LGTM!

The new migration journal entry follows the established pattern and is properly formatted.

packages/lib/package.json (2)

210-215: LGTM!

The new ./notifications export follows the established pattern used by other exports like ./auth, with proper ESM/CommonJS support and TypeScript type declarations.


332-335: LGTM!

The typesVersions entry correctly maps to the notifications type declarations, ensuring proper TypeScript resolution.

packages/db/src/schema/core.ts (2)

196-196: LGTM!

The userMentionsFrom relation correctly links pages to their user mentions using the appropriate relation name.


252-269: LGTM!

The userMentionsRelations are correctly defined with appropriate relation names that match the corresponding relations in pagesRelations. The three-way relationship (sourcePage, targetUser, mentionedByUser) is properly modeled.

packages/db/src/schema/notifications.ts (1)

21-23: LGTM!

The new MENTION and TASK_ASSIGNED notification types follow the existing naming convention and align with the PR objectives. The existing notifications table structure (with pageId and triggeredByUserId) supports the metadata needed for these notification types.

packages/db/drizzle/0038_salty_phalanx.sql (2)

1-2: LGTM!

The enum type extension is performed before the table creation, which is the correct order of operations.


3-31: LGTM!

The migration is well-structured with:

  • Proper IF NOT EXISTS for idempotent table creation
  • Foreign key constraints with appropriate ON DELETE behavior (CASCADE for page/target user, SET NULL for mentioner)
  • Exception handling for duplicate constraints ensures rerunnability
  • Indexes aligned with the Drizzle schema definition

As per coding guidelines, database schema changes in packages/db/src/schema/ have been paired with migration generation via pnpm db:generate.

apps/web/src/services/api/rollback-service.ts (1)

393-395: LGTM!

The change correctly passes mentionedByUserId to syncMentions when restoring content during rollback, ensuring mention notifications are properly attributed to the user performing the rollback operation. The nullish coalescing handles the case where options?.userId might be null.

apps/web/src/services/api/page-mutation-service.ts (1)

214-216: LGTM!

The change correctly passes the acting user's ID to syncMentions, enabling proper attribution for mention notifications when page content is updated.

apps/web/src/components/notifications/NotificationDropdown.tsx (3)

20-23: LGTM!

Clean import additions for the new notification icon types.


58-61: LGTM!

Appropriate icon choices: AtSign for mentions and ListTodo for task assignments are intuitive and consistent with the notification semantics.


202-207: LGTM!

The navigation logic correctly handles both new notification types by routing to the relevant page. The check for both pageId and driveId provides graceful fallback to the generic drive navigation (line 208-211) when either is missing.

apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts (2)

8-8: LGTM!

Clean import of the new notification helper from the library package.


224-234: LGTM!

The notification logic is well-implemented:

  • The condition correctly triggers only when assigneeId changes to a non-null value (new assignment, not unassignment)
  • Fire-and-forget with void is appropriate since notification delivery shouldn't block the API response
  • The createTaskAssignedNotification function already handles self-assignment checks internally
packages/lib/src/services/notification-email-service.ts (1)

30-32: Email templates not yet implemented for new notification types.

The MENTION and TASK_ASSIGNED types are correctly added to the union, but there are no corresponding email templates in getEmailTemplate(). Currently, these notification types will silently skip email sending (lines 291-294 handle this gracefully).

If email notifications for mentions and task assignments are desired, templates will need to be added in a follow-up PR.

Is intentionally skipping email notifications for these types the desired behavior, or should email templates be added as part of this PR?

packages/lib/src/notifications/types.ts (2)

197-225: LGTM! Well-structured notification types.

The new MentionNotification and TaskAssignedNotification types follow the established discriminated union pattern consistently. Metadata fields appropriately capture all context needed for notification display and navigation.


241-243: LGTM!

Union type correctly extended with the new notification types.

apps/web/src/services/api/page-mention-service.ts (3)

14-64: LGTM! Well-structured mention parsing.

The findMentionNodes function correctly:

  • Parses both HTML (data-page-id, data-user-id) and markdown-style mentions
  • Falls back to regex parsing if HTML parsing fails
  • Returns deduplicated results using Set
  • Handles the type discriminator (user vs page) appropriately

85-114: LGTM!

The syncPageMentions function correctly implements the diff-based synchronization pattern with proper transaction support.


66-83: LGTM!

Clean orchestration with a well-defined options interface.

packages/lib/src/notifications/notifications.ts (2)

350-392: LGTM! Clean implementation following established patterns.

The createMentionNotification function:

  • Correctly prevents self-mention notifications
  • Properly fetches related entities with null checks
  • Provides appropriate fallback for missing user names
  • Metadata aligns with MentionNotification type definition

394-440: LGTM! Consistent implementation.

The createTaskAssignedNotification function follows the same well-established pattern as other notification creators in this file, with appropriate self-assignment checks and complete metadata population.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Fixes race condition where notifications could be sent before the database
transaction commits. If the transaction rolled back, incorrect notifications
would have already been sent.

Changes:
- Remove setTimeout-based notification dispatch from syncUserMentions
- Return newly mentioned user IDs from syncMentions
- Send notifications in callers after transaction commits
- Update page-mutation-service and rollback-service to handle notifications
  after their respective transaction boundaries
@2witstudios 2witstudios merged commit a588fcf into master Jan 15, 2026
3 checks passed
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