Skip to content

feat: add promo code support for distributing credits per event#535

Open
elliotBraem wants to merge 10 commits intonearai:mainfrom
elliotBraem:feat/credit-claim
Open

feat: add promo code support for distributing credits per event#535
elliotBraem wants to merge 10 commits intonearai:mainfrom
elliotBraem:feat/credit-claim

Conversation

@elliotBraem
Copy link
Copy Markdown

@elliotBraem elliotBraem commented Apr 14, 2026

Introduces promo codes (an admin route to create and deactivate, a public route to get, and a claim route validated by a session)

Promo codes are generated in batches (e.g. 100 at once) or can be individual, each unguessable (NEAR-A7K3-X9M2-P4Q8), and single-use. When a user claims one, credits expire at a configurable time, are filtered from balance calculations once expired, and stack independently per event via credit_type = 'event:{uuid}'. The claim auto-provisions an org + workspace + API key if the user has none, returning the API key in the response so they can start using credits immediately.

Key changes:

  • 3 DB migrations: V0049 (credit_expires_at on limits), V0050 (credit
    events/codes/claims tables), V0051 (per-user dedup constraint +
    composite indexes)
  • Service layer with full claim lifecycle: validate event, find
    unclaimed code, auto-provision org, add credits, atomic claim
  • Claim flow is transactionally safe: claim count increment + code
    claiming happen in a single DB transaction to prevent race conditions
  • Per-user dedup: UNIQUE(credit_event_id, user_id) prevents same user
    from claiming multiple codes per event
  • Admin routes: POST/PATCH /v1/admin/credit-events, POST/GET codes
  • Public routes: GET /v1/credit-events, GET by ID
  • Claim route: POST /v1/credit-events/{id}/claim (session auth)
  • Expired credits filtered from organization balance via
    credit_expires_at column on organization_limits_history
  • 18 E2E tests covering full lifecycle

TODO: make a frontend to demonstrate (or get access to the cloud.near.ai frontend and make the page there)


Note

High Risk
Introduces new DB tables and transactional credit-claim flows that modify credit balance calculations and add admin/public endpoints; issues could impact credit accounting and allow unintended claims if auth/constraints are wrong.

Overview
Adds Credit Events as a first-class feature: admins can create/deactivate events and generate/list promo codes, the public can list/get active events, and authenticated users can claim credits via /v1/credit-events/{id}/claim.

Implements the end-to-end claim lifecycle in the services and database layers, including promo code generation, per-user-per-event dedup (unique index), and an atomic DB transaction that increments claim_count, marks a code claimed, and records a credit_claims row.

Extends organization limits to support expiring credit grants via credit_expires_at (new migration + API fields) and updates balance aggregation to exclude expired credits. Updates OpenAPI (new tag, new schemas, and admin_token security scheme) and adds comprehensive E2E coverage for the new flows.

Reviewed by Cursor Bugbot for commit 9dc717d. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 9dc717d. Configure here.

Comment thread crates/services/src/credit_events/mod.rs
Comment thread crates/api/src/routes/credit_events.rs Outdated
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request implements a comprehensive credit event and promo code management system, enabling administrative creation of distribution campaigns and user-side credit redemptions. Significant updates include new database migrations for tracking events and claims, the integration of a credit_expires_at field across organization limit models to support expiring grants, and the introduction of several API endpoints for managing the event lifecycle. Review feedback highlights opportunities for performance optimization in promo code generation using bulk inserts, suggests refining the organization selection logic during claims for better determinism, and recommends utilizing available admin context for improved auditing.

Comment thread crates/database/src/repositories/credit_event.rs Outdated
Comment thread crates/database/src/repositories/credit_event.rs Outdated
Comment thread crates/services/src/credit_events/mod.rs Outdated
Comment thread crates/api/src/routes/credit_events.rs Outdated
Comment thread crates/api/src/routes/credit_events.rs Outdated
…aims, bulk inserts, date validation, audit trail
@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 14, 2026

You have used all of your free Bugbot PR reviews.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 15, 2026

You have used all of your free Bugbot PR reviews.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 15, 2026

You have used all of your free Bugbot PR reviews.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 15, 2026

You have used all of your free Bugbot PR reviews.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 16, 2026

You have used all of your free Bugbot PR reviews.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 16, 2026

You have used all of your free Bugbot PR reviews.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 16, 2026

You have used all of your free Bugbot PR reviews.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces Credit Events (admin-managed campaigns) and promo code claiming that grants expiring credits, plus updates credit balance calculations to exclude expired grants.

Changes:

  • Adds a new credit events service/repository layer with admin/public/claim flows.
  • Adds DB schema for credit events/codes/claims + constraints/indexes, and adds credit_expires_at to organization_limits_history.
  • Updates API routes/OpenAPI/models and adds E2E coverage for the end-to-end lifecycle and expiry filtering.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
crates/services/src/usage/ports.rs Extends org limit domain type to carry credit_expires_at.
crates/services/src/lib.rs Exposes the new credit_events module and service exports.
crates/services/src/credit_events/ports.rs Defines credit events DTOs, errors, and service/repository traits.
crates/services/src/credit_events/mod.rs Implements service logic: event CRUD, code generation, and claim lifecycle.
crates/services/src/admin/ports.rs Plumbs credit_expires_at through admin limits DTOs.
crates/database/src/repositories/organization_limits_repository_impl.rs Updates spend limit aggregation to exclude expired grants.
crates/database/src/repositories/organization_limits.rs Adds credit_expires_at persistence/queries for limits history.
crates/database/src/repositories/mod.rs Registers new credit event repositories.
crates/database/src/repositories/credit_event_repository_impl.rs Adapts DB repository errors/types to services-layer ports.
crates/database/src/repositories/credit_event.rs Implements credit events storage and transactional claim logic.
crates/database/src/repositories/admin_composite.rs Plumbs credit_expires_at into admin composite responses.
crates/database/src/models.rs Adds credit_expires_at to limits history model + adds credit event models.
crates/database/src/migrations/sql/V0049__add_credit_expires_at_to_limits.sql Adds credit_expires_at column to organization_limits_history.
crates/database/src/migrations/sql/V0050__add_credit_events.sql Creates credit events/codes/claims tables and base indexes.
crates/database/src/migrations/sql/V0051__add_credit_events_constraints.sql Adds per-user-per-event dedup constraint + performance indexes.
crates/api/tests/e2e_all/main.rs Registers new credit events E2E test module.
crates/api/tests/e2e_all/credit_events.rs Adds E2E tests for admin/public/claim flows and expiry filtering.
crates/api/src/routes/mod.rs Registers credit events routes module.
crates/api/src/routes/credit_events.rs Implements admin/public/claim HTTP endpoints and error mapping.
crates/api/src/routes/admin.rs Adds request parsing + response fields for credit_expires_at in limits routes.
crates/api/src/openapi.rs Documents credit events endpoints/schemas and adds admin_token security scheme.
crates/api/src/models.rs Adds API models for credit events and adds creditExpiresAt to limits models.
crates/api/src/lib.rs Wires credit event routes into the Axum app/router and constructs service dependencies.
crates/api/Cargo.toml Adds async-trait dependency (used across the crate ecosystem).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/api/src/models.rs Outdated
Comment thread crates/api/src/routes/credit_events.rs Outdated
Comment thread crates/api/src/routes/credit_events.rs Outdated
Comment thread crates/api/src/routes/credit_events.rs
Comment thread crates/api/src/routes/credit_events.rs
Comment thread crates/database/src/repositories/credit_event.rs
Comment thread crates/services/src/credit_events/mod.rs
Comment thread crates/services/src/credit_events/mod.rs Outdated
Comment thread crates/database/src/repositories/credit_event.rs
@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 22, 2026

You have used all of your free Bugbot PR reviews.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 22, 2026

You have used all of your free Bugbot PR reviews.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

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.

2 participants