Alumni — Marketplace#
Curated deals (coupons + partner-site links) from vetted partners, scoped to the BITS community. Phase 2 launches with ~20 seeded deals across categories.
Who this is for: alumni (and verified students/faculty/staff for deals scoped to the wider institute). Deal visibility honours each deal’s audience_scope, so you only see deals targeted at audiences you belong to.
Where to find it#
- Deal grid:
/app/marketplace. - A deal card opens a modal in-place; deals are not on their own URL today.
Browsing#
The grid surfaces:
- A Deals for you rail at the top, populated by the Stage 19 recommender (signals: deal views, redemption history, chapter affinity).
- A category chip filter (e.g.
food,travel,gear,services— taken from each deal’scategories text[]). - An audience filter that resolves to your
Principalserver-side; you cannot view deals you would not normally be eligible for.
Each card shows partner name + logo, the deal title and short description, the category chip, and the validity window.
Audience scoping#
A deal carries one of:
audience_scope | Visible to |
|---|---|
public | any logged-in user |
institute | verified institute users (any role) |
alumni | role = alumni |
batch | alumni whose Profile.batch_year == audience_scope_value |
chapter | members of the named chapter group |
Scoping is enforced server-side (Service.canSeeDeal in backend/internal/marketplace/service.go). You cannot bypass it via the URL.
Redeeming#
Two deal kinds (from backend/internal/marketplace/types.go):
coupon— clicking Get coupon opens the modal, callsRecordRedemption, and returns a coupon code your clipboard receives. The redemption row is logged (source = copy_code).link— clicking Open partner site redirects you outbound after recording the redemption (source = outbound_click).
Either way the redemption flow:
- Validates state — only
activedeals can be redeemed; redeeming apaused,draft, orexpireddeal returns 422 (ErrDealNotActive). - Validates the validity window — outside
[valid_from, valid_until)you get 410 Gone semantics (ErrDealOutsideWindow). - Checks the cap — if the deal has a
redemption_capand the count is at the cap, you get 429 (ErrRedemptionCapReached). - Checks idempotency — for
redemption_cap=1deals, a second redeem returns 409AlreadyExistswith the originalredeemed_attimestamp embedded in the message so the UI can render “you redeemed this on Jan 12 at 14:32”.
Reading the cap#
If a deal advertises a cap (e.g. “first 100 redemptions”), the card shows a remaining-count chip. The decrement is row-locked at the database level — no two clients can over-redeem a cap=100 deal simultaneously.
Common issues#
- “I redeemed a coupon code but it doesn’t work at the partner site” — Bits records a redemption regardless of whether the partner accepts the code. If the partner site rejects the code, contact the partner first; if you suspect a Bits-side issue, message the Marketplace admin via the listed contact email on the partner card.
- “A deal disappeared mid-flow” — the expiry job runs periodically (
marketplace.jobs.go) and flips deals whosevalid_untilhas lapsed. If you opened a card that was on the cusp of expiry, by the time you click redeem the deal may have flipped toexpiredand the call returns 410. - “I can’t see a deal someone else can” — audience scoping. Check which
audience_scopethe deal carries; if it’schapterorbatchyou have to be in scope. - “I lost my coupon code” —
RecordRedemptionis idempotent on cap=1 deals, so re-clicking surfaces the original code. For multi-redemption deals, yourDealRedemptionhistory is on the deal modal under Your redemptions.