Skip to content

feat(admin): add read and moderation endpoints over merchants - #56

Merged
codebestia merged 1 commit into
ShadeProtocol:mainfrom
Damola09:feat/admin-merchant-endpoints
Aug 29, 2026
Merged

feat(admin): add read and moderation endpoints over merchants#56
codebestia merged 1 commit into
ShadeProtocol:mainfrom
Damola09:feat/admin-merchant-endpoints

Conversation

@Damola09

@Damola09 Damola09 commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Closes #42

Adds GET /admin/merchants (filter/sort/paginate), GET /admin/merchants/:id, GET /admin/merchants/:id/invoices (delegates to the existing listInvoices), GET /admin/merchants/:id/analytics, and POST /admin/merchants/:id/block behind requireSuperAdmin. No schema change.

Two things worth a reviewer's attention:

  • The block route moves from PATCH (any admin) to POST + requireSuperAdmin, per the issue. That is a breaking change for any existing PATCH caller; the old integration test was rewritten accordingly.
  • Blocking is off-chain only. set_merchant_status needs the on-chain admin's signature, which this backend cannot produce — the deferral is noted in code, not silently skipped.

Unblocking is out of scope; a test asserts no unblock route answers.

Full suite green: 47 suites / 441 tests. tsc --noEmit clean, eslint 0 errors.

Summary by CodeRabbit

  • New Features
    • Added an admin merchant dashboard with merchant listing, filtering, sorting, pagination, details, invoice history, and analytics.
    • Added merchant-specific invoice and status-based subscription insights.
    • Merchant blocking now supports an optional reason recorded in audit metadata.
  • Bug Fixes
    • Improved validation and error handling for merchant queries and blocking requests.
    • Restricted merchant blocking to super administrators and updated the action to use POST.
  • Tests
    • Added coverage for dashboard endpoints, access controls, validation, analytics, and audit metadata.

Adds the admin dashboard's merchant surface. No schema change is required —
every field served here already exists on Merchant, Invoice, MerchantAnalytics
and Subscription.

GET /admin/merchants lists merchants with limit/offset pagination reusing the
DEFAULT_LIMIT/MAX_LIMIT convention from invoice.validation.ts, filters on
active, verified, category and a case-insensitive search across businessName,
email and address, and sorts by createdAt, merchantId or businessName in either
direction, defaulting to createdAt desc. Booleans are parsed strictly: a query
string carries no real boolean, so only the literals "true" and "false" are
accepted rather than coercing anything truthy and silently filtering on the
wrong value.

GET /admin/merchants/:id serves the merchant detail through sanitizeMerchant,
which already withholds the OTP columns an admin has no reason to see.

GET /admin/merchants/:id/invoices delegates to the existing
listInvoices(merchantId, filters, pagination) and parses its query with
parseInvoiceListQuery, so the admin-scoped response shape and accepted filters
cannot drift from the merchant-facing route. The merchant is resolved first so
an unknown id is a 404 rather than an empty page.

GET /admin/merchants/:id/analytics adds getMerchantAdminAnalytics: per-token
volume, fees and transaction counts from MerchantAnalytics, plus live
status-grouped invoice and subscription counts. Subscription.merchantId is a
direct scalar, so the subscription grouping needs no join through
SubscriptionPlan. BigInt counters are serialized as strings, matching how
analytics.services.ts already reports them.

POST /admin/merchants/:id/block replaces the previous PATCH route and is now
gated by requireSuperAdmin, so a non-superadmin admin gets a 403. It sets
Merchant.active = false and records exactly one merchant.blocked AdminLog entry,
carrying an optional { reason } in the metadata. This is off-chain only: the
contract's set_merchant_status(admin, merchant_id, status) requires the on-chain
admin's signature, which this backend cannot produce, so reconciling the
on-chain status is deferred to separate work rather than silently skipped —
the same off-chain-first pattern used for invoice amendment.

Unblocking is deliberately not implemented. Only blocking was in scope; a test
asserts no unblock route answers, so its absence is explicit rather than an
oversight.
@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6beb76c3-1d55-4a03-b8f8-0bf07b20a3ce

📥 Commits

Reviewing files that changed from the base of the PR and between 8c09acf and e8be536.

📒 Files selected for processing (6)
  • src/controllers/admin-merchant.controllers.ts
  • src/routes/admin/merchant.routes.ts
  • src/services/merchant.services.ts
  • src/utils/merchant.validation.ts
  • tests/integration/admin.merchant.routes.test.ts
  • tests/unit/merchant.validation.test.ts

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Changes

Admin merchant endpoints

Layer / File(s) Summary
Query and block request validation
src/utils/merchant.validation.ts, tests/unit/merchant.validation.test.ts
Added typed parsing for filters, sorting, pagination, and block reasons. Added unit coverage for valid and invalid inputs.
Admin merchant service operations
src/services/merchant.services.ts
Added paginated merchant listing, merchant detail retrieval, and analytics aggregation. Analytics serializes BigInt counters as strings.
Admin merchant HTTP wiring and control
src/controllers/admin-merchant.controllers.ts, src/routes/admin/merchant.routes.ts
Added authenticated GET endpoints for merchants, invoices, and analytics. Changed blocking to a superadmin-only POST route with validation, audit metadata, and centralized error handling.
Endpoint and authorization coverage
tests/integration/admin.merchant.routes.test.ts
Added integration coverage for read endpoints, filters, pagination, analytics, superadmin blocking, audit metadata, validation errors, and the absent unblock route.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🔵 Low · up to e8be5

Merchant blocking now changes the persisted off-chain status, but the moderation audit record can still be missing if audit storage fails after the status update succeeds. The PR is mergeable with explicit owner awareness that audit completeness should be made transactional or reliably recoverable.

Suggested reviewers: dannyorji

Sequence Diagram(s)

sequenceDiagram
  participant Admin
  participant MerchantRoutes
  participant AdminMerchantControllers
  participant MerchantServices
  participant Prisma

  Admin->>MerchantRoutes: Request merchant admin endpoint
  MerchantRoutes->>AdminMerchantControllers: Apply authentication and invoke controller
  AdminMerchantControllers->>MerchantServices: Validate query and request data
  MerchantServices->>Prisma: Query merchant, invoice, subscription, or analytics data
  Prisma-->>MerchantServices: Return requested data
  MerchantServices-->>AdminMerchantControllers: Return service result
  AdminMerchantControllers-->>Admin: Return JSON response
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary changes: admin merchant read endpoints and moderation through blocking.
Linked Issues check ✅ Passed The changes implement the linked issue objectives [#42], including merchant listing, detail retrieval, invoice listing, analytics, super-admin-only blocking, audit metadata, off-chain handling, and no…
Out of Scope Changes check ✅ Passed The changes stay within the linked issue scope [#42]. The added validation, error handling, routes, services, and tests directly support the requested merchant read and moderation endpoints.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 6…
Full details: Linked Issues check

Explanation

The changes implement the linked issue objectives [#42], including merchant listing, detail retrieval, invoice listing, analytics, super-admin-only blocking, audit metadata, off-chain handling, and no schema changes. Unblocking remains out of scope.

Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 6 files.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@codebestia

Copy link
Copy Markdown
Contributor

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@codebestia codebestia left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM!
Thank you for your contribution.

@codebestia
codebestia merged commit 68b0464 into ShadeProtocol:main Aug 29, 2026
3 checks passed
@grantfox-oss grantfox-oss Bot mentioned this pull request Aug 29, 2026
8 tasks
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.

Admin Merchant Endpoints

2 participants