Skip to content

fix(achievements): correct batch notification date filter and bound processing - #1410

Merged
RUKAYAT-CODER merged 1 commit into
rinafcode:mainfrom
ZuLu0890:fix/1391-batch-achievement-notifications
Aug 31, 2026
Merged

fix(achievements): correct batch notification date filter and bound processing#1410
RUKAYAT-CODER merged 1 commit into
rinafcode:mainfrom
ZuLu0890:fix/1391-batch-achievement-notifications

Conversation

@ZuLu0890

Copy link
Copy Markdown
Contributor

Summary

Closes #1391

AchievementsNotificationsService.sendBatchNotifications() was silently never sending scheduled batch notifications for achievements unlocked today. The query filtered on unlockedAt: new Date(), which compares against the exact current instant with millisecond precision and essentially never matches any stored row — the computed midnight boundary (today.setHours(0, 0, 0, 0)) was calculated but never used. The query was also unbounded: unlike resendFailedNotifications(), it had no take limit, so a fixed query would load an unbounded number of rows and send them all in a single tight loop.

Changes

src/achievements/achievements-notifications.service.ts

  • Fixed the date filter: replaced unlockedAt: new Date() with unlockedAt: MoreThanOrEqual(today), selecting achievements unlocked since midnight today that have not yet been notified (notificationSent: false). The intended "unlocked today" window is now actually applied.
  • Bounded the batch: added BATCH_SIZE = 100 and process the backlog in bounded chunks using take/skip pagination, so large backlogs are handled chunk-by-chunk instead of in one unbounded query — consistent with the existing resendFailedNotifications() behavior.
  • Loop hygiene: the pagination loop terminates when a chunk comes back empty or smaller than the batch size, and is lint-compliant (while (keepProcessing) rather than a literal constant condition).

src/achievements/achievements-notifications.service.spec.ts

  • Regression test for the corrected date filter: asserts the query is issued with unlockedAt: MoreThanOrEqual(today) and notificationSent: false, and that an achievement unlocked earlier today is selected and notified.
  • Bounded batching test: verifies a 103-record backlog is processed in chunks (100 + 3) and that all 103 records are marked as sent.

Verification

All relevant checks run locally:

Check Result
pnpm lint:ci ✅ 0 errors (only pre-existing warnings in unrelated files)
pnpm format:check ✅ pass
pnpm typecheck ✅ pass
pnpm test src/achievements/achievements-notifications.service.spec.ts ✅ 10/10 pass

Note: src/achievements/achievements.service.spec.ts has failing tests, but they fail identically on main (unmodified baseline) and are unrelated to this change.

…rocessing

sendBatchNotifications() filtered on unlockedAt: new Date(), an exact
instant comparison that never matches stored rows, so scheduled batch
notifications were silently never sent. Use MoreThanOrEqual(midnight
today) and process the backlog in bounded chunks of 100 via take/skip
pagination, matching resendFailedNotifications(). Add regression tests
for the corrected date filter and bounded batching.

Closes rinafcode#1391

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@ZuLu0890 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@RUKAYAT-CODER

Copy link
Copy Markdown
Contributor

Thank you for contributing to the project.

@RUKAYAT-CODER
RUKAYAT-CODER merged commit 1b332eb into rinafcode:main Aug 31, 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.

Batch achievement notifications query never matches (uses unlockedAt = now, ignores today boundary)

2 participants