Skip to content

Add a payment-provider circuit breaker, structured logging, and API hardening - #1913

Merged
yusuftomilola merged 2 commits into
DistinctCodes:mainfrom
phertyameen:feature/circuit-breaker-logging-swagger-body-limit
Sep 25, 2026
Merged

yusuftomilola merged 2 commits into
DistinctCodes:mainfrom
phertyameen:feature/circuit-breaker-logging-swagger-body-limit

Conversation

@phertyameen

@phertyameen phertyameen commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes four issues assigned to this account, all in the backend.

Provider circuit breaker (#1797)
progressToAwaitingConfirmation called the rail adapter directly on every request, so a degraded provider was hammered indefinitely. The outbound call is now wrapped in a per-rail opossum circuit breaker:

  • Configurable timeout, errorThresholdPercentage and resetTimeout, with a volumeThreshold so a low-traffic rail does not open on a single transient error.
  • An errorFilter so business rejections (e.g. ConflictException) do not count toward opening, while transport/timeout failures do.
  • A fallback that turns an open breaker into a clear ServiceUnavailableException (HTTP 503) rather than an opaque error, while still rethrowing genuine failures unchanged when the rail is healthy.
  • Breakers are cached per rail and created lazily, so one provider's outage cannot suppress traffic to a healthy rail. PaymentsService's constructor signature is unchanged, keeping the existing spec's construction intact; the spec was extended to cover the success path and the open-breaker path.

Structured JSON logging (#1796)
Adds a pino-backed LoggerService that promotes Nest's logger context and the current request id to real JSON fields, plus one structured access-log line per completed response (method, url, path, status, duration, request id). Enabled in production, with a LOG_JSON=true override for other environments; development keeps Nest's readable logger. No existing service constructor changed, so unit tests are unaffected.

Admin endpoints in the OpenAPI docs (#1795)
Both admin controllers already had class-level tags and most @ApiOperation decorators, so the real gap was incomplete responses: reconciliation metrics, ledger integrity, the payment sweep and the settlement run had no response documentation at all and rendered untyped in the generated document. Each now has a proper response DTO built from the real service return type, the xlsx export declares its media type, and previously undocumented @ApiQuery/@ApiParam inputs are declared. admin-swagger.spec.ts guards this with reflection so an admin handler cannot silently lose its operation or response metadata again.

Request body size limit (#1794)
The body parsers are now registered explicitly with a configurable limit (REQUEST_BODY_LIMIT, default 1mb) instead of relying on Nest's implicit defaults. Registering them manually is what makes the limit configurable, and the verify callback preserves the exact raw bytes the payment webhook's HMAC verification depends on — that requirement is called out in a comment so it is not lost in a future refactor.

Configuration

Variable Default Purpose
REQUEST_BODY_LIMIT 1mb Max JSON/urlencoded body size
LOG_JSON unset Force structured logging outside production
PAYMENT_PROVIDER_BREAKER_TIMEOUT_MS 10000 Per-attempt provider timeout
PAYMENT_PROVIDER_BREAKER_ERROR_THRESHOLD_PERCENT 50 Error ratio that opens the breaker
PAYMENT_PROVIDER_BREAKER_RESET_TIMEOUT_MS 30000 Wait before a half-open trial

Testing

Per the task constraints, no install, build, lint, or test run was performed — the maintainer runs those manually. New spec: payments/admin-swagger.spec.ts. payments.service.spec.ts was extended. backend/package-lock.json is intentionally not regenerated; the new dependencies are declared in package.json and the lockfile needs an npm install before npm ci will succeed.

New dependencies

opossum, pino.

Reviewer note

backend/src/credits/credits-admin.controller.spec.ts and backend/src/payments/payments-admin.spec.ts are already broken on main — they import modules that do not exist (./credits-admin.service, ../../common/guards/jwt-auth.guard, ../../users/entities/user.entity) and call controller methods that no longer exist. They were left untouched here as out of scope.

Closing issues

Closes #1797
Closes #1796
Closes #1795
Closes #1794

…API hardening

Wraps the outbound payment-rail initiation in a per-rail opossum circuit breaker configured from the environment, so a degraded provider is short-circuited instead of being hammered on every request. Business rejections do not count toward opening the circuit, a volume threshold keeps a low-traffic rail from tripping on one error, and an open breaker surfaces as a clear 503. The breaker is created lazily so the existing service constructor and tests are unchanged.

Adds pino-backed structured JSON logging for production (with a LOG_JSON override), promoting the Nest logger context and request id to real fields, plus one structured access-log line per completed response.

Completes the admin OpenAPI surface: reconciliation metrics, ledger integrity, payment sweep and settlement run now have typed response DTOs, and previously undocumented query/path parameters are declared, with a reflection-based spec that fails if any admin handler loses its operation or response metadata.

Configures an explicit, configurable request body size limit on the JSON and urlencoded parsers while preserving the raw-body capture the payment webhook HMAC verification depends on.

Closes DistinctCodes#1797
Closes DistinctCodes#1796
Closes DistinctCodes#1795
Closes DistinctCodes#1794
@vercel

vercel Bot commented Sep 24, 2026

Copy link
Copy Markdown

@phertyameen is attempting to deploy a commit to the naijabuz's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Sep 24, 2026

Copy link
Copy Markdown

@phertyameen 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

…er-logging-swagger-body-limit

# Conflicts:
#	backend/.env.example
#	backend/src/main.ts
#	backend/src/payments/payments-admin.controller.ts
#	backend/src/payments/payments.service.ts
@yusuftomilola
yusuftomilola merged commit 1bd30c2 into DistinctCodes:main Sep 25, 2026
1 of 7 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

2 participants