feat(backend): harden Admin Dashboard Service — rate limiting, signature verification, SQL optimization, error recovery#1006
Merged
emdevelopa merged 1 commit intoJun 25, 2026
Conversation
…nature verification, SQL optimization, and error recovery
- Require signed, rate-limited requests on /api/metrics/* (revenue summary,
revenue by asset, volume over time) via requireApiKeyAuth({ requireSignature: true })
and a new per-merchant dashboard metrics rate limiter (Redis-backed when available).
- Add createDashboardMetricsRateLimit / getDashboardMetricsRateLimitKey to lib/rate-limit.js.
- Fix a missing metricService import in routes/metrics.js (route threw ReferenceError
on every call) and remove a duplicated inline SQL volume query in favor of the
shared metricService.getVolumeOverTime implementation.
- Merge the two sequential last-month/current-month revenue queries in
metricService.getMonthlySummary into a single conditional-aggregation query,
halving DB round trips for that endpoint.
- Add retry-with-backoff and circuit-breaker protection (reusing the existing
lib/db.js circuit breaker) around all metricService DB calls so transient
connection errors no longer surface as hard failures.
- Convert routes/metrics.js to a router factory (createMetricsRouter) for
rate-limiter dependency injection, matching the existing payments/merchants pattern.
- Add unit/route tests covering the new rate limiter, signature requirement,
combined summary query, and retry/circuit-breaker behavior.
|
@Akanimoh12 is attempting to deploy a commit to the Emmanuel's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@Akanimoh12 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! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR hardens the Admin Dashboard Service (the
/api/metrics/*revenue/volume reporting endpoints and their backingmetricService) across four areas: rate limiting, request signature verification, SQL query efficiency, and DB error recovery.createDashboardMetricsRateLimit/getDashboardMetricsRateLimitKeyinlib/rate-limit.js, following the same per-merchant (falling back to hashed API key, then IP) keying pattern already used for merchant security actions and SEP-10 endpoints. Wired into/api/metrics/summary,/api/metrics/revenue, and/api/metrics/volumevia a Redis-backed store when Redis is available, matching the existing wiring inapp.js.requireApiKeyAuth({ requireSignature: true }), enforcing the existing HMACx-api-signature/x-api-timestamprequest-signing scheme (already used by sensitive merchant routes) instead of relying on the API key alone.metricServiceimport inroutes/metrics.js— the route referencedmetricServicewithout importing it, which meant/api/metrics/summaryand/api/metrics/revenuewould throw aReferenceErroron every request./api/metrics/volumehandler that re-implementedmetricService.getVolumeOverTimeinstead of calling it.metricService.getMonthlySummaryinto a single query using conditional aggregation (FILTER (WHERE ...)), halving the DB round trips for that endpoint while still using the existing(merchant_id, status, created_at)index.metricServiceDB calls now go through retry-with-backoff and the shared circuit breaker fromlib/db.js(the same circuit breaker already protecting auth and audit-log writes), so transient connection errors are retried instead of surfacing as hard failures to the dashboard.Also converted
routes/metrics.jsfrom a static router export to acreateMetricsRouterfactory so the rate limiter can be injected, matching the existing factory pattern used byroutes/payments.jsandroutes/merchants.js.Test plan
lib/rate-limit.test.jscoverage forcreateDashboardMetricsRateLimit/getDashboardMetricsRateLimitKeyservices/metricService.test.jscovering the combined summary query, zero-activity asset filtering, retry-then-succeed, and non-retryable failure pathsroutes/metrics.test.jscovering signature enforcement, rate-limit rejection (429), and successful delegation tometricServicefor all three routesnpm testinbackend/) to confirm no regressionsCloses #927
Closes #928
Closes #929
Closes #930