-
Notifications
You must be signed in to change notification settings - Fork 5
feat: message users when no match #757
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
📝 WalkthroughWalkthroughThe changes add a no-match notification system that identifies users with active non-private wishlists who didn't receive matches during a matching run and sends them system messages encouraging wishlist expansion. Changes
Sequence DiagramsequenceDiagram
participant AIMatch as AIMatchingService
participant DB as Database
participant NotifSvc as MatchNotificationService
participant Chat as Chat System
participant Message as Message Store
AIMatch->>AIMatch: processUnmessagedMatches()
AIMatch->>DB: getAllWishlistUserIdsForNoMatch()
DB-->>AIMatch: [wishlistUserIds]
AIMatch->>DB: Query matched users
DB-->>AIMatch: [matchedUserIds]
AIMatch->>AIMatch: Compute no-match candidates
loop For each no-match user
AIMatch->>NotifSvc: sendNoMatchNotification(userId)
NotifSvc->>DB: Resolve user details
DB-->>NotifSvc: User info
NotifSvc->>Chat: Find/create mutual chat
Chat-->>NotifSvc: Chat (possibly new)
alt New chat created
NotifSvc->>NotifSvc: Wait 15 seconds
end
NotifSvc->>Message: Create system message
Message-->>NotifSvc: Saved
NotifSvc-->>AIMatch: Notification sent
end
AIMatch->>AIMatch: Log totals
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@platforms/dreamsync-api/src/services/AIMatchingService.ts`:
- Around line 141-156: The current getAllWishlistUserIdsForNoMatch collects all
active wishlist owners (including empty wishlists) and ignores the run's
200‑wishlist processing cap; change the query in getAllWishlistUserIdsForNoMatch
(using wishlistRepository.createQueryBuilder("wishlist")) to only include
wishlists that were actually analyzed: add a predicate to exclude empty
wishlists (e.g., where wishlist.items IS NOT NULL or wishlist.itemCount > 0 or
the appropriate non-empty column for your schema) and apply the same
limit/offset or 200‑item cap used elsewhere in this run so the returned userIds
exactly match the processed, non‑empty wishlists. Ensure the distinct userId
select remains and keep the processLogger/console message updated if desired.
In `@platforms/dreamsync-api/src/services/MatchNotificationService.ts`:
- Around line 722-732: In MatchNotificationService update the no-match message
string assigned to messageContent (using displayName) to a clearer,
grammatically correct user-facing copy: replace the current body with a concise
message such as "Dear {displayName},\n\nWe couldn’t find any conclusive matches
for your wishlist this time. Try adding more details or topics to increase your
chances of finding a match.\n\nBest wishes,\nDreamSync" (preserve the
$$system-message$$ wrapper if required), ensuring proper capitalization and
removing repeated phrasing.
🧹 Nitpick comments (1)
platforms/dreamsync-api/src/services/AIMatchingService.ts (1)
161-188: Consider batching no‑match sends to avoid very long runs.
The loop is fully sequential; with the 15‑second delay insendNoMatchNotification, large batches can make a run take hours. A small concurrency cap keeps throughput reasonable. Please confirm the cap is compatible with any messaging/DB rate limits.♻️ Example batching with a small concurrency cap
- for (let i = 0; i < noMatchUserIds.length; i++) { - const userId = noMatchUserIds[i]; - try { - console.log(`📨 [no-match] (${i + 1}/${noMatchUserIds.length}) Sending no-match notification to user: ${userId}`); - await this.notificationService.sendNoMatchNotification(userId); - sentCount++; - console.log(`✅ [no-match] Sent to user ${userId} (${sentCount}/${noMatchUserIds.length})`); - } catch (error) { - errorCount++; - console.error(`❌ [no-match] Error sending no-match notification to user ${userId}:`, error); - } - } + const batchSize = 10; + for (let i = 0; i < noMatchUserIds.length; i += batchSize) { + const batch = noMatchUserIds.slice(i, i + batchSize); + await Promise.all(batch.map(async (userId, idx) => { + const ordinal = i + idx + 1; + try { + console.log(`📨 [no-match] (${ordinal}/${noMatchUserIds.length}) Sending no-match notification to user: ${userId}`); + await this.notificationService.sendNoMatchNotification(userId); + sentCount++; + console.log(`✅ [no-match] Sent to user ${userId} (${sentCount}/${noMatchUserIds.length})`); + } catch (error) { + errorCount++; + console.error(`❌ [no-match] Error sending no-match notification to user ${userId}:`, error); + } + })); + }
| /** | ||
| * Get all user IDs that have at least one active wishlist (non-null record), regardless of content/empty. | ||
| * Used for no-match notifications so we include users whose wishlists may be considered "empty". | ||
| */ | ||
| private async getAllWishlistUserIdsForNoMatch(): Promise<string[]> { | ||
| const rows = await this.wishlistRepository | ||
| .createQueryBuilder("wishlist") | ||
| .select("DISTINCT wishlist.userId") | ||
| .leftJoin("wishlist.user", "user") | ||
| .where("wishlist.isActive = :isActive", { isActive: true }) | ||
| .andWhere("user.isPrivate = :isPrivate", { isPrivate: false }) | ||
| .getRawMany<Record<string, string>>(); | ||
| const userIds = rows.map(r => Object.values(r)[0]).filter(Boolean) as string[]; | ||
| console.log(`📋 [no-match] Found ${userIds.length} distinct users with at least one active wishlist (including empty wishlists)`); | ||
| return userIds; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Limit no‑match candidates to wishlists actually analyzed (and non‑empty).
The current query scans all active wishlists (including empty) and ignores the 200‑wishlist cap used in this run, so users not processed could receive a false “no match” message. This also conflicts with the “non‑empty wishlist” requirement.
✅ Suggested fix to align eligibility with the processed, non‑empty wishlists
- const allWishlistUserIds = await this.getAllWishlistUserIdsForNoMatch();
- await this.sendNoMatchNotifications(allWishlistUserIds, matchResults);
+ const allWishlistUserIds = this.getAllWishlistUserIdsForNoMatch(wishlistData);
+ await this.sendNoMatchNotifications(allWishlistUserIds, matchResults);- /**
- * Get all user IDs that have at least one active wishlist (non-null record), regardless of content/empty.
- * Used for no-match notifications so we include users whose wishlists may be considered "empty".
- */
- private async getAllWishlistUserIdsForNoMatch(): Promise<string[]> {
- const rows = await this.wishlistRepository
- .createQueryBuilder("wishlist")
- .select("DISTINCT wishlist.userId")
- .leftJoin("wishlist.user", "user")
- .where("wishlist.isActive = :isActive", { isActive: true })
- .andWhere("user.isPrivate = :isPrivate", { isPrivate: false })
- .getRawMany<Record<string, string>>();
- const userIds = rows.map(r => Object.values(r)[0]).filter(Boolean) as string[];
- console.log(`📋 [no-match] Found ${userIds.length} distinct users with at least one active wishlist (including empty wishlists)`);
- return userIds;
- }
+ /**
+ * Get user IDs from the wishlists processed in this run (non-empty).
+ * Keeps no-match notifications aligned with the actual matching scope.
+ */
+ private getAllWishlistUserIdsForNoMatch(wishlistData: WishlistData[]): string[] {
+ const userIds = [...new Set(wishlistData.map(w => w.userId))];
+ console.log(`📋 [no-match] Found ${userIds.length} users with non-empty wishlists processed in this run`);
+ return userIds;
+ }🤖 Prompt for AI Agents
In `@platforms/dreamsync-api/src/services/AIMatchingService.ts` around lines 141 -
156, The current getAllWishlistUserIdsForNoMatch collects all active wishlist
owners (including empty wishlists) and ignores the run's 200‑wishlist processing
cap; change the query in getAllWishlistUserIdsForNoMatch (using
wishlistRepository.createQueryBuilder("wishlist")) to only include wishlists
that were actually analyzed: add a predicate to exclude empty wishlists (e.g.,
where wishlist.items IS NOT NULL or wishlist.itemCount > 0 or the appropriate
non-empty column for your schema) and apply the same limit/offset or 200‑item
cap used elsewhere in this run so the returned userIds exactly match the
processed, non‑empty wishlists. Ensure the distinct userId select remains and
keep the processLogger/console message updated if desired.
| const displayName = user.name || user.ename || "User"; | ||
| const messageContent = `$$system-message$$ | ||
|
|
||
| Dear ${displayName}, | ||
|
|
||
| DreamSync tried to find matches with other users using your wishlist but no conclusive matches were found. | ||
|
|
||
| we would encourage you to add more details to your wishlist and add more topics you are interested in. | ||
|
|
||
| Best Wishes, | ||
| DreamSync`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Polish the no‑match message copy.
Minor grammar/capitalization and repeated phrasing in a user‑facing message.
✍️ Suggested copy edit
- const messageContent = `$$system-message$$
-
-Dear ${displayName},
-
-DreamSync tried to find matches with other users using your wishlist but no conclusive matches were found.
-
-we would encourage you to add more details to your wishlist and add more topics you are interested in.
-
-Best Wishes,
-DreamSync`;
+ const messageContent = `$$system-message$$
+
+Dear ${displayName},
+
+DreamSync tried to find matches with other users using your wishlist, but no conclusive matches were found.
+
+We encourage you to add more details to your wishlist and include more topics you're interested in.
+
+Best wishes,
+DreamSync`;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const displayName = user.name || user.ename || "User"; | |
| const messageContent = `$$system-message$$ | |
| Dear ${displayName}, | |
| DreamSync tried to find matches with other users using your wishlist but no conclusive matches were found. | |
| we would encourage you to add more details to your wishlist and add more topics you are interested in. | |
| Best Wishes, | |
| DreamSync`; | |
| const displayName = user.name || user.ename || "User"; | |
| const messageContent = `$$system-message$$ | |
| Dear ${displayName}, | |
| DreamSync tried to find matches with other users using your wishlist, but no conclusive matches were found. | |
| We encourage you to add more details to your wishlist and include more topics you're interested in. | |
| Best wishes, | |
| DreamSync`; |
🤖 Prompt for AI Agents
In `@platforms/dreamsync-api/src/services/MatchNotificationService.ts` around
lines 722 - 732, In MatchNotificationService update the no-match message string
assigned to messageContent (using displayName) to a clearer, grammatically
correct user-facing copy: replace the current body with a concise message such
as "Dear {displayName},\n\nWe couldn’t find any conclusive matches for your
wishlist this time. Try adding more details or topics to increase your chances
of finding a match.\n\nBest wishes,\nDreamSync" (preserve the $$system-message$$
wrapper if required), ensuring proper capitalization and removing repeated
phrasing.
Description of change
User's get notification if wishlist match is not found at dreamsync
Issue Number
closes #752
Type of change
Change checklist
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.