Skip to content

✨ server: add debt repayment notification#722

Open
aguxez wants to merge 1 commit intomainfrom
debt-repay
Open

✨ server: add debt repayment notification#722
aguxez wants to merge 1 commit intomainfrom
debt-repay

Conversation

@aguxez
Copy link
Copy Markdown
Contributor

@aguxez aguxez commented Feb 5, 2026

closes #337

Summary by CodeRabbit

Release Notes

  • New Features
    • Added debt repayment notifications to alert users when their debts reach maturity
    • Automatic maturity checks scheduled at regular intervals to monitor debt status
    • Push notifications sent when debt requires user attention

Open with Devin

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Feb 5, 2026

🦋 Changeset detected

Latest commit: 8fdcd04

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@exactly/server Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 5, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR introduces a debt repayment notification system using BullMQ queues. It adds a maturity queue for periodically checking user debts across 24h and 1h windows, processing accounts in batches, selecting between market and previewer implementations, and triggering push notifications via Redis-based deduplication.

Changes

Cohort / File(s) Summary
Changeset
.changeset/dull-candies-cheer.md
Adds patch-level changeset documenting the debt repayment notification feature for @exactly/server.
Maturity Queue Core
server/queues/maturityQueue.ts
New BullMQ queue module implementing debt maturity checks with configurable implementations (previewer or market), batch processing (size 250), Redis-based idempotent notifications, Sentry instrumentation, and automatic rescheduling for 1h windows.
Maturity Queue Tests
server/test/queues/maturityQueue.test.ts
Comprehensive test suite validating job scheduling, debt processing across both implementations, Redis deduplication, notification triggering, rescheduling logic, and environment-driven implementation selection.
Server Integration
server/index.ts
Integrates maturity queue lifecycle: imports worker initialization and queue close functions, invokes initializeMaturityWorker() and scheduleMaturityChecks() on startup (non-VITEST), and includes closeMaturityQueue() in shutdown cleanup sequence.
Maturity Utility
server/utils/hasMaturity.ts
New utility function decoding 64-bit bitmap to check maturity presence: lower 32 bits store base maturity, upper 32 bits hold bit-packed flags for maturity intervals (0-223 offsets).
Maturity Utility Tests
server/test/utils/hasMaturity.test.ts
Unit tests covering zero/aligned/misaligned maturity checks, bitmap edge cases, offset boundaries, and packed bitmaps with multiple bits.
Test Mock Updates
server/test/api/auth.test.ts, server/test/api/registration.test.ts
Refactors redis mock to expose both default export and new named export requestRedis, each referencing the same mock instance with get/set/del methods.

Sequence Diagram

sequenceDiagram
    participant Scheduler as Scheduler
    participant Queue as BullMQ Queue
    participant Worker as Maturity Worker
    participant DB as Database
    participant Contract as Contract (Market/Previewer)
    participant Redis as Redis
    participant Sentry as Sentry
    participant Push as Push Notifications

    Scheduler->>Queue: scheduleMaturityChecks() creates<br/>CHECK_DEBTS jobs (24h, 1h)
    Queue->>Worker: Job available
    Worker->>DB: Read accounts in batch (250)
    Worker->>Contract: Query debt status<br/>(implementation-dependent)
    Contract->>Worker: Debt results per user
    Worker->>Redis: Check notification<br/>idempotency key
    alt Debt exists & not notified
        Worker->>Redis: Write idempotency key
        Worker->>Push: Send push notification
    end
    Worker->>Sentry: Log metrics & breadcrumbs<br/>(contract calls, errors, results)
    alt Window is "1h"
        Worker->>Queue: Schedule next maturity checks<br/>(increment maturity)
    end
    Worker->>Queue: Mark job complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • nfmelendez
  • cruzdanilo
  • franm91
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title accurately reflects the main change: adding a debt repayment notification feature to the server, which includes a maturity check queue, worker initialization, and notification logic.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch debt-repay

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.

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @aguxez, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a critical new feature to proactively notify users about their upcoming debt maturities. It establishes a robust server-side queueing system using BullMQ to periodically check user debt positions on the blockchain. Depending on configuration, it leverages either direct market contract interactions or a previewer contract to identify at-risk users. Timely push notifications are then dispatched via OneSignal, with Redis ensuring that users receive alerts only once per window, aiming to help users manage their debts and avoid potential liquidations.

Highlights

  • New Debt Maturity Notification System: Introduced a new BullMQ queue (maturityQueue) responsible for scheduling and processing debt repayment notifications to users.
  • Flexible Debt Checking Implementation: Implemented two distinct methods for checking user debt positions on-chain: one directly interacting with market contracts and another utilizing a previewer contract, configurable via an environment variable.
  • Push Notification Integration: Integrated with OneSignal to send push notifications to users whose debts are approaching maturity, with Redis used to prevent duplicate notifications within a 24-hour window.
  • Robust Error Handling and Monitoring: Incorporated Sentry for comprehensive error tracking and breadcrumbs for monitoring the activity and performance of the new maturity queue.
  • Comprehensive Testing: Added extensive unit tests for the new maturityQueue and the hasMaturity utility function to ensure reliability and correctness.
Changelog
  • server/index.ts
    • Integrated the new maturityQueue for proper initialization and graceful shutdown of the debt notification system.
    • Ensured scheduleMaturityChecks is called on server startup, with error capture via Sentry.
  • server/queues/constants.ts
    • Defined new QueueName.MATURITY and MaturityJob.CHECK_DEBTS constants for the debt notification queue.
  • server/queues/markets.ts
    • Added a new file to define DEBT_NOTIFICATION_MARKETS, specifying which markets are relevant for debt notifications.
  • server/queues/maturityQueue.ts
    • Implemented the core logic for the maturityQueue, including job processing, debt checking against blockchain contracts, and sending push notifications.
    • Introduced a configurable implementation type ('market' or 'previewer') for debt checking.
    • Utilized Redis to manage notification idempotency, preventing repeated alerts for the same debt within a set timeframe.
    • Added Sentry integration for error reporting and activity tracking within the queue worker.
    • Provided functions for scheduling maturity checks and gracefully closing the queue and worker.
  • server/test/queues/maturityQueue.test.ts
    • Added comprehensive unit tests for the maturityQueue processor, covering various scenarios for debt detection and notification logic under both 'market' and 'previewer' implementations.
    • Included tests for job scheduling and handling of duplicate notifications.
  • server/test/utils/fixedLibrary.test.ts
    • Introduced unit tests for the hasMaturity utility function, verifying its correctness across different encoded values and maturities.
  • server/utils/createCredential.ts
    • Removed an unnecessary JSDoc comment for WebhookNotReadyError.
  • server/utils/fixedLibrary.ts
    • Added a new utility function hasMaturity to efficiently check for the presence of a specific maturity within a packed bigint representation.
  • server/utils/redis.ts
    • Updated the Redis client configuration to set maxRetriesPerRequest to null, optimizing connection behavior.
Activity
  • This pull request is the second part of a two-part stack, building upon previous changes related to the system.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

gemini-code-assist[bot]

This comment was marked as resolved.

@sentry
Copy link
Copy Markdown

sentry bot commented Feb 5, 2026

Codecov Report

❌ Patch coverage is 95.91837% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.70%. Comparing base (b709bcc) to head (8fdcd04).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
server/utils/maturity.ts 95.91% 5 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #722      +/-   ##
==========================================
+ Coverage   72.21%   72.70%   +0.49%     
==========================================
  Files         227      228       +1     
  Lines        8388     8552     +164     
  Branches     2699     2757      +58     
==========================================
+ Hits         6057     6218     +161     
- Misses       2109     2112       +3     
  Partials      222      222              
Flag Coverage Δ
e2e 70.81% <89.11%> (-1.40%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the feature/webhook-queue branch 4 times, most recently from 4bce409 to a5d5c22 Compare March 6, 2026 12:49
chatgpt-codex-connector[bot]

This comment was marked as resolved.

sentry[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 7 additional findings in Devin Review.

Open in Devin Review

chatgpt-codex-connector[bot]

This comment was marked as resolved.

sentry[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

⚠️ 1 issue in files not directly in the diff

⚠️ Missing positionAmount === 0n guard causes potential BigInt division-by-zero crash (src/components/pay/Pay.tsx:93-94)

The allMaturities computation in Pay.tsx does not filter out positions where positionAmount === 0n (line 94), unlike the sibling components OverduePayments.tsx:51 and UpcomingPayments.tsx:50 which both have explicit if (positionAmount === 0n) continue; guards. This accumulated value flows into FirstMaturityCard at src/components/pay/Pay.tsx:366 where (previewValue * WAD) / positionAmount would throw a BigInt division-by-zero error, crashing the Payments screen.

View 6 additional findings in Devin Review.

Open in Devin Review

sentry[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

sentry[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dccde14c19

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

callsPerAccount: totalAccountsProcessed > 0 ? totalContractCalls / totalAccountsProcessed : 0,
},
});
if (totalRpcFailures > 0 && totalRpcFailures >= totalAccountsProcessed / 2) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Fail and retry when any account read is rejected

The new threshold gate only throws when totalRpcFailures >= totalAccountsProcessed / 2, which means partial RPC outages still complete the job successfully while silently dropping affected accounts from notification delivery. In a common case (e.g., 1–2 transient readContract failures in a larger batch), those users never get retried for this one-time reminder window, so notifications are permanently missed even though BullMQ retries are configured.

Useful? React with 👍 / 👎.

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 95157734d5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 10 additional findings in Devin Review.

Open in Devin Review

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8fdcd04d52

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

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.

server: notifications before due date

1 participant