Skip to content

[GF-BE-09] Build promo codes and discount backend module #1084

Description

@yusuftomilola

Problem

There is no promo code or discount system on ManageHub. Admins cannot create promotional codes for onboarding campaigns, corporate rates, or seasonal discounts. Members have no way to apply a discount at checkout, which limits the platform's marketing flexibility.

Proposed Solution

Create a new NestJS module at backend/src/promo-codes/.

Entity: PromoCode

  • id (UUID), code (string, unique — stored uppercase)
  • discountType (enum: percentage | fixed_amount)
  • discountValue (integer — percentage 1–100, or fixed kobo amount)
  • maxUses (integer, nullable — null = unlimited)
  • usedCount (integer, default 0)
  • minBookingAmount (integer, kobo — minimum booking value to qualify, default 0)
  • applicableWorkspaceTypes (array of WorkspaceType enum, nullable — null = all types)
  • expiresAt (timestamp, nullable)
  • isActive (boolean, default true)
  • createdAt, updatedAt

Entity: PromoCodeUsage

  • id (UUID), promoCodeId (FK), userId (FK), bookingId (FK)
  • discountApplied (integer, kobo), usedAt (timestamp)

Endpoints:

Method Path Access
POST /promo-codes Admin
GET /promo-codes Admin
PATCH /promo-codes/:id Admin
DELETE /promo-codes/:id Admin
POST /promo-codes/validate Authenticated member

POST /promo-codes/validate accepts { code, workspaceId, bookingAmount } and returns { valid: boolean, discountType, discountValue, finalAmount, message }. The payment service then reads this when initialising a booking payment.

Acceptance Criteria

  • Both entities created with migrations
  • code is normalised to uppercase on save
  • POST /promo-codes/validate checks: code exists, isActive, not expired, under maxUses, workspace type matches, booking amount meets minBookingAmount
  • A user cannot use the same promo code more than once (enforced via PromoCodeUsage unique constraint on promoCodeId + userId)
  • usedCount increments atomically when a payment using the code succeeds (hook into handle-webhook.provider.ts)
  • PromoCodesModule is registered in AppModule

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions