feat: event-filtered webhooks, real admin metrics, consistent pagination (closes #192, #193, #196) - #263
Merged
cypriannwokolo2-creator merged 1 commit intoAug 26, 2026
Conversation
- cocor-tech#192: webhook dispatcher now filters deliveries per webhook event-type subscription, retries with exponential backoff, and records every attempt (delivered/failed/skipped) in a new webhook_deliveries table exposed via GET /webhooks/:id/deliveries. Registration persists to Postgres with the actual webhooks schema (url/events/secret_hash/is_active). - cocor-tech#193: /admin/metrics returns real aggregates (users, circles, contributions, payouts, active users, 30d new users, volume) plus a time-bucketed daily volume series, computed by a new internal/domain/admin package and cached in-memory for 60s. - cocor-tech#196: standard pagination metadata now includes hasMore (meta.hasMore / pagination.has_more); circle GetRounds/GetPayouts accept client page and page_size params and return consistent meta. - Drive-by: fix swap handler compile errors against the response package so the repo builds. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
|
@YazarAyobami 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
Implements three Stellar Wave issues in one cohesive backend change:
GET /admin/metricsnow returns real aggregate metrics instead of a hardcodedtotalVolumeUSD: 0, including time-bucketed daily volume series and caching for expensive aggregates.hasMore, and the circleGetRounds/GetPayoutsendpoints now accept clientpage/page_sizeparams.Changes
#192 — Event-filtered webhook delivery
webhook/service.goWebhookRegistrationnow carriesEvents,IsActive,LastDeliveryAt, andFailureCount; empty event list = subscribe to all events.PostgresRepositorywas rewritten to match the actualwebhooksschema (url,events,secret_hash,is_active,last_delivery_at,failure_count) — the previous queries referenced columns that don't exist in migration 010.DispatchPayload(ctx, eventType, payload, maxRetries)now filters active webhooks by subscription (skipped webhooks get askippeddelivery log entry), retries failures with exponential backoff, updateslast_delivery_at/failure_count, and logs each attempt towebhook_deliveries.Delete,UpdateDeliveryOutcome,LogDelivery,ListDeliveries.internal/database/migrations/037_create_webhook_deliveries.{up,down}.sql— new delivery-log table with indexes on(webhook_id, created_at)and(event_type, created_at).internal/api/handler/webhook_handler.go— registrations now persist through the repository (with a generated HMAC secret) instead of an in-memory map; addedGET /webhooks/:id/deliveries(owner-only, paginated) to inspect delivery history.internal/api/router.go— registers the new deliveries route.#193 — Real admin metrics
internal/domain/adminpackage:model.go—Metrics(users, circles, contributions, payouts, active users, 30d new users, contribution/payout volume, total volume, 30d volume) andDailyVolumePoint.repository.go/repository_pg.go— aggregate SQL: totals, active users (activity in the trailing window), volume from confirmed contributions + payouts, and agenerate_series-backed per-day volume series.service.go—Servicewith an in-memory TTL cache (default 60s) for the expensive aggregates; errors are never cached.internal/api/handler/admin_handler.go—GetMetricsserves the aggregates (flat response keeps legacytotalUsers/totalCircles/activeCircles/totalVolumeUSDkeys), accepts an optional?days=window (default 30, max 365).cmd/api-server/main.go— wires the new service.#196 — Consistent pagination metadata
pkg/response/response.go—PaginationMetaandPaginationnow includehasMore/has_morecomputed byNewPaginationMeta(page < totalPages).internal/api/handler/circle_handler.go:GetPayoutsacceptspage/page_sizeinstead of a fixed1, 50.GetRoundsacceptspage/page_size(applied to the underlying contribution/payout history queries) and now returnsmeta; rounds are sorted by round number for a deterministic response.pagination.Parse+OKWithMeta, so they automatically inherit the newhasMorefield.Drive-by fix
internal/api/handler/swap_handler.go— the swap endpoints calledresponse.Error(...)with the wrong signature and didn't compile against the currentpkg/response; replaced with the standard response helpers so the repo builds cleanly.Tests
webhook/service_test.go— event-type filtering (subscribed vs non-subscribed +skippedlog), empty-subscription = all events, retry-until-success with attempt logging, retry exhaustion →failedlog, network-error logging; fake repo made thread-safe for the async dispatcher.internal/domain/admin/service_test.go— cache hit, cache expiry, per-window cache isolation, error propagation (never cached), default TTL.internal/api/handler/admin_handler_test.go—GetMetricsreturns real aggregates (non-zerototalVolumeUSD).internal/api/handler/circle_pagination_test.go—GetPayouts/GetRoundshonor clientpage/page_sizeand returnhasMoremetadata.pkg/response/response_test.go— assertshasMore/has_morepresence and edge cases.tests/integration/api_routes_test.go— webhook routes now run against an in-memory repo implementing the expanded interface.Verification
go build ./...— passes.go vet ./...— passes.go test ./... -count=1— all tests pass. (Note:TestConstantTimeCompareTimingis a pre-existing timing flake that only fails under-race, unchanged by this PR.)Notes
totalVolumeUSDis the sum of contribution + payout volume until per-currency conversion rates are wired in (documented ininternal/domain/admin/model.go).secret_hashcolumn continues to store the raw HMAC secret so incoming signature verification (POST /webhooks/incoming/:id) keeps working (existing convention, now documented inscanWebhook).