Skip to Content
Routes (HTTP URLs)marketing-admin.routes.ts

marketing-admin.routes.ts

Mount: /api/v1/admin/marketing (nested inside admin.route.ts)

Staff-only API for sponsors and coupon deals. The router is mounted as a sub-router by admin.route.ts, which already applies authMiddleware + adminMiddleware.

Guards

  • authMiddleware (logged in)
  • adminMiddleware (super admin OR adminRole)
  • requirePermission(PERMISSIONS.VIEW_STATS) on every route

All marketing reads and writes currently share one permission (VIEW_STATS). Tighten this with a dedicated MANAGE_MARKETING permission when staff specialisation is needed.

Sponsors

MethodPathBody / queryPurpose
GET/sponsors?page&limit&cursorList sponsors (cursor or page+limit)
POST/sponsors{ name, profileLink, phone?, email? }Create a sponsor (profile link must be http/https URL)
GET/sponsors/:idFetch one sponsor
PATCH/sponsors/:idpartial sponsor fields incl. notesUpdate sponsor

Deals

MethodPathBody / queryPurpose
GET/deals?page&limit&cursorAll deals with sponsor join
GET/sponsors/:sponsorId/deals?page&limit&cursorDeals for one sponsor
POST/sponsors/:sponsorId/deals{ startDate, type, offerAmount?, finalAmount?, status?, endDate? }Create deal; if status === 'done', auto-assigns a unique coupon code
PATCH/sponsors/:sponsorId/deals/:dealIdpartial: status, amounts, endDateUpdate deal; coupon is assigned/cleared as status crosses done

Deal validation rules

  • status === 'pending'endDate must be omitted.
  • status === 'done' | 'canceled'endDate is required and must be a parseable date string.
  • type ∈ values exported by MARKETING_DEAL_TYPES (marketing-deal.model.ts).
  • statusMARKETING_DEAL_STATUSES.
  • offerAmount and finalAmount may be null or non-negative numbers; the older dealAmount field is read for backward compatibility and surfaced in JSON as finalAmount.

Coupon code lifecycle

  • A deal becomes done → the service calls assignUniqueDealCouponCode(sponsorName) (see marketing-deal-coupon.service.ts).
  • The generated couponCode is returned in dealToJson for the admin UI.
  • During user onboarding (PATCH /api/v1/users/me/onboarding), the same coupon code is validated and persisted on the user.

Pagination

All list endpoints support either:

  • Page mode (deprecated)?page=&limit= returning { items, total, page, limit } plus a Deprecation: true response header.
  • Cursor mode (preferred)?cursor=&limit= returning { items, nextCursor, hasMore, limit } via the shared cursor-pagination.ts util (sorted by createdAt desc, _id desc).

Clients should migrate to cursor mode; page mode remains for compatibility with the current admin UI.

Last updated on