Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Gift Card

Gift Card is a prepaid credit system that allows users to redeem balance into their account. Gift cards have a secret code, a fixed monetary value, an expiration date, and can only be used once. Administrators can generate gift cards in bulk or create special cards with custom secrets.

Core Concept

A Gift Card represents:

  • Secret code: Unique 64-character alphanumeric string for redemption
  • Amount: Fixed value credited to user’s balance upon redemption
  • Expiration: Time limit after which the card becomes invalid
  • Single-use: Once redeemed, the card is permanently marked as used

Data Model

pub struct GiftCard {
    pub id: i32,
    pub secret: String,                     // 64-char alphanumeric code
    pub amount: Decimal,                    // Value to credit
    pub used_by: Option<Uuid>,              // User who redeemed (if any)
    pub created_at: PrimitiveDateTime,      // Creation timestamp
    pub redeem_at: Option<PrimitiveDateTime>, // When it was redeemed
    pub valid_until: PrimitiveDateTime,     // Expiration date
}

Gift Card Lifecycle

1. Generation

Gift cards are created by administrators through bulk generation or special creation:

Bulk Generation (AdminGenerateGiftCard):

  • Generates N cards with identical amount and expiration
  • Secrets are randomly generated (64-character alphanumeric)
  • Returns list of secret codes for distribution
  • Uses hash set to ensure uniqueness before database insertion

Special Creation (AdminCreateSpecialGiftCard):

  • Creates a single card with custom secret (e.g., promotional codes like “WELCOME2025”)
  • Useful for marketing campaigns or personalized gifts
  • Secret must be unique (database constraint)

Permissions: Moderator, SuperAdmin, CustomerSupport

2. Distribution

Gift cards exist as secret codes. Administrators must distribute these codes to users through external channels (email, physical cards, promotional materials). The system does not handle distribution automatically.

3. Redemption

Users redeem gift cards through GiftCardService::RedeemGiftCard:

Flow:

  1. User submits secret code
  2. System looks up valid gift card (not used, not expired)
  3. Validates user exists
  4. Transaction begins:
    • Add card amount to user’s available balance
    • Log balance change (type: Deposit, reason: “Redeem Gift Card”)
    • Mark card as used with used_by and redeem_at
  5. Transaction commits

Validation Order:

  1. Card exists by secret → CardNotFound
  2. Card not already used → AlreadyUsed
  3. Card not expired (valid_until > NOW()) → Expired
  4. User exists → UserNotFound
  5. Transaction succeeds → Success

Important: The validation provides specific error reasons. If a card is found but invalid, the system distinguishes between “already used” and “expired” to provide clear feedback.

4. Expiration

Expired cards remain in the database but cannot be redeemed:

  • Query filter: valid_until > NOW() AND used_by IS NULL
  • Redemption attempt returns Expired result
  • No automatic cleanup of expired cards (historical record)

User Operations

Redeem Gift Card

Service: GiftCardService::RedeemGiftCard

Users provide a secret code to add balance to their account.

Result Types:

  • Success: Balance credited successfully
  • CardNotFound: Secret doesn’t exist in database
  • AlreadyUsed: Card was previously redeemed by any user
  • Expired: Card’s valid_until date has passed
  • UserNotFound: Requesting user account doesn’t exist (edge case)

Transaction Safety: The redemption process is fully transactional. If the balance update fails, the card remains unused. This prevents double-redemption and ensures balance consistency.

Admin Operations

All gift card admin operations are exposed through ManageService and require appropriate admin roles.

Generate Gift Cards

Operation: AdminGenerateGiftCard

Bulk-creates gift cards with identical configuration.

Parameters:

  • number: How many cards to generate (batch size)
  • amount: Value of each card
  • valid_until: Expiration timestamp for all cards

Returns: List of secret codes (strings)

Use Cases:

  • Promotional campaigns (e.g., 1000 cards worth $10 each)
  • Customer rewards programs
  • Event giveaways

Note: The operation returns the secret codes in the response. These should be securely stored or distributed immediately, as they cannot be retrieved later (secrets are logged as [REDACTED] in debug output for security).

Create Special Gift Card

Operation: AdminCreateSpecialGiftCard

Creates a single card with a custom secret.

Parameters:

  • secret: Custom code (e.g., “NEWYEAR2025”)
  • amount: Card value
  • valid_until: Expiration timestamp

Use Cases:

  • Marketing promotions with memorable codes
  • Influencer partnerships with branded codes
  • VIP customer gifts

Database Constraint: The secret must be unique across all gift cards (used or unused). Attempting to create a duplicate secret will fail.

List Gift Cards

Operation: AdminListGiftCards

Retrieves gift cards with optional filtering and pagination.

Filters:

  • filter_id: Specific card ID
  • filter_secret: Partial or exact secret match
  • filter_is_used: Show only used or unused cards
  • filter_used_by: Cards redeemed by specific user
  • limit, page: Pagination controls

Use Cases:

  • Finding cards redeemed by a user (customer support)
  • Checking if a secret exists before creation
  • Monitoring unused expired cards
  • Audit trail of card usage

Delete Gift Cards

Operation: AdminDeleteGiftCards

Permanently removes gift cards from the database.

Parameters: List of card IDs to delete

Permissions: Moderator, SuperAdmin (more restricted than other operations)

Use Cases:

  • Removing expired promotional campaigns
  • Cleaning up unused cards after campaign ends

Warning: Deleting a redeemed card does not affect user balance. The balance change log remains intact with the reason “Redeem Gift Card”, but the reference to the card is lost.

Integration with Balance System

Gift card redemption is the primary way users add funds to their account (other than admin top-ups).

Balance Credit Flow

When a gift card is redeemed:

  1. User’s available_balance increases by card amount
  2. A UserBalanceChangeLog entry is created:
    • change_type: Deposit
    • amount: Card value (positive)
    • reason: “Redeem Gift Card”
  3. User can immediately use the balance to pay for orders

See Account Balance for complete balance system documentation.

Transaction Integrity

The redemption uses database transactions with row-level locking:

  • SELECT ... FOR UPDATE on gift card prevents concurrent redemption
  • Balance update and card marking happen atomically
  • If balance update fails (user not found), card remains unused

Security Considerations

Secret Generation

Secrets are 64-character random alphanumeric strings (A-Z, a-z, 0-9):

  • Entropy: ~380 bits (62^64 combinations)
  • Collision probability: Negligible even for millions of cards
  • Not cryptographically signed or verifiable offline

Uniqueness: The system generates secrets in memory using a HashSet before database insertion, ensuring no duplicates in a batch. Database constraint provides final uniqueness guarantee.

Debug Output Redaction

The GiftCard struct implements custom Debug to redact secrets:

.field("secret", &"[REDACTED]")

This prevents accidental secret leakage in logs, error messages, or debug traces.

No Secret Recovery

Once generated, secrets cannot be retrieved by ID. Admins must save the secret codes from the generation response. This is intentional—secrets are meant to be distributed, not stored centrally.

Database Schema

Key schema details (from migrations/20250922063531_gift_card_system.sql):

Table: shop.gift_card

id          SERIAL PRIMARY KEY
secret      VARCHAR(255) NOT NULL UNIQUE
amount      NUMERIC NOT NULL
used_by     UUID REFERENCES auth.user_profile(id)
created_at  TIMESTAMP NOT NULL DEFAULT NOW()
redeem_at   TIMESTAMP
valid_until TIMESTAMP NOT NULL

Indexes:

  • (secret): Fast lookup by secret (primary redemption path)
  • (secret) WHERE used_by IS NULL: Fast lookup for valid cards
  • (valid_until) WHERE used_by IS NULL: Expiration queries
  • (used_by): Find cards redeemed by a user

Foreign Key: used_by references user profile with ON DELETE RESTRICT, preventing user deletion if they’ve redeemed cards.

Frontend Integration Points

User Redemption Flow

  1. Input Field: Provide text input for secret code (64 characters)

  2. Validation: Optional client-side format check (alphanumeric, length)

  3. Submission: Call RedeemGiftCard with the secret

  4. Result Handling:

    • Success: Show success message, update balance display
    • CardNotFound: “Invalid gift card code”
    • AlreadyUsed: “This gift card has already been redeemed”
    • Expired: “This gift card has expired”
    • UserNotFound: Generic error (should never happen)
  5. Balance Refresh: Fetch updated balance after successful redemption

Admin Management UI

Generate Cards:

  • Form with number, amount, expiration date
  • Display generated secrets in a list (with copy buttons)
  • Warn user to save secrets before leaving page

List Cards:

  • Table with columns: ID, Secret (masked/copyable), Amount, Status (Used/Unused), Used By, Created, Redeemed, Expires
  • Filters for used/unused, user, date ranges
  • Search by secret or ID

Create Special Card:

  • Form with custom secret input, amount, expiration
  • Validate secret format before submission
  • Handle duplicate secret error clearly

Design Decisions

Why Single-Use Only?

Gift cards are one-time redeemable by design:

  • Simplifies balance tracking (single deposit event)
  • Prevents confusion about remaining card balance
  • Matches traditional physical gift card behavior
  • Users can check their balance history for redemptions

For recurring credits or subscriptions, use coupon system or scheduled balance deposits instead.

Why No Secret Retrieval?

Secrets are treated as bearer tokens:

  • Admin generates and distributes them
  • System validates but doesn’t need to recall them
  • Reduces risk of centralized secret exposure
  • Aligns with physical gift card model (code is on the card)

Admins can search by secret if a user provides it (customer support), but cannot list all secrets.

Why Soft Delete Not Supported?

Unlike coupons (which have is_active), gift cards are either used or deleted:

  • Once distributed, cards shouldn’t be “disabled” (already in user’s hands)
  • Unused cards can be deleted if campaign is cancelled
  • Used cards should be kept for audit trail (don’t delete redeemed cards)

Why Expiration is Required?

All gift cards must have a valid_until date:

  • Prevents indefinite liability on the system
  • Aligns with legal/financial regulations for prepaid instruments
  • Encourages timely redemption
  • Allows cleanup of old campaigns

Set far-future dates (e.g., 10 years) for effectively non-expiring cards if needed.


See Also: