Referral code system for PhoenixKit - complete management in a single module.
This module provides both the Ecto schema definition and business logic for managing referral codes. It includes code creation, validation, usage tracking, and system configuration.
Schema Fields
code: The referral code string (unique, required, stored upcased)description: Human-readable description of the codestatus: Boolean indicating if the code is activenumber_of_uses: Times the code has been used. Maintained byuse_code/2; not settable throughchangeset/2max_uses: Maximum number of times the code can be usedcreated_by_uuid: UUID of the admin who created the codebeneficiary_uuid: UUID of the user who benefits when this code is used (optional)date_created: When the code was createdexpiration_date: When the code expires (nil= never expires)
Core Functions
Code Management
list_codes/0- Get all referral codesget_code/1- Get a referral code by UUID (nilif not found)get_code!/1- Get a referral code by UUID (raises if not found)get_code_by_string/1- Get a referral code by its string value (case-insensitive)create_code/1- Create a new referral codeupdate_code/2- Update an existing referral codedelete_code/1- Delete a referral codegenerate_random_code/0- Generate a random code stringgenerate_unique_code/1- Generate a random code no existing code holds
Usage Tracking
use_code/2- Atomically claim one use of a code and record itget_usage_stats/1- Get usage statistics for a codelist_usage_for_code/1- Get all usage records for a codeuser_used_code?/2- Check if user has used a specific code
System Settings
enabled?/0- Check if referral codes system is enabledrequired?/0- Check if referral codes are required for registrationenable_system/0- Enable the referral codes systemdisable_system/0- Disable the referral codes systemset_required/1- Set whether referral codes are required
Usage Examples
# Check if system is enabled
if PhoenixKitReferrals.enabled?() do
# System is active
end
# Create a new referral code
{:ok, code} = PhoenixKitReferrals.create_code(%{
code: "WELCOME2024",
description: "Welcome promotion",
max_uses: 100,
created_by_uuid: admin_user.uuid,
expiration_date: ~U[2024-12-31 23:59:59.000000Z]
})
# Use a referral code during registration
case PhoenixKitReferrals.use_code("WELCOME2024", user_uuid) do
{:ok, usage} -> # Code used successfully
{:error, reason} -> # Handle error
end
Summary
Functions
Returns an %Ecto.Changeset{} for tracking referral code changes.
Creates a changeset for referral code creation and admin edits.
Counts the total number of referral codes created by a user.
Creates a referral code.
OTP apps whose templates Tailwind should scan for CSS classes.
Deletes a referral code.
Disables the referral codes system.
Enables the referral codes system.
Checks if the referral codes system is enabled.
Checks if a referral code has expired.
Generates a random 5-character alphanumeric referral code.
Generates a random code that no existing referral code already holds.
Gets a single referral code by UUID.
Same as get_code/1, but raises Ecto.NoResultsError if the code does not exist.
Gets a single referral code by its string value.
Gets the current referral codes system configuration.
Gets the maximum number of referral codes a single user can create.
Gets the maximum number of uses allowed per referral code.
Gets summary statistics for the referral codes system.
Gets usage statistics for a referral code.
Ships the referral-link capture script (URL ?referral= -> localStorage ->
auto-filled referral_code field / OAuth links) via PhoenixKit's JS bundle
extension point.
Returns the list of referral codes ordered by creation date.
Gets the most recent referral code usage records system-wide, for an admin activity feed.
Lists all usage records for a referral code.
Gets codes that are currently valid for use.
Checks if referral codes are required for user registration.
Sets the maximum number of referral codes a single user can create.
Sets the maximum number of uses allowed per referral code.
Sets whether referral codes are required for registration.
Gets the codes with the most recorded uses, for an admin leaderboard.
Updates a referral code.
Checks if a referral code has reached its usage limit.
Records usage of a referral code by a user.
Checks if a user has already used a specific referral code.
Checks if a referral code is currently valid for use.
Validates that a user hasn't exceeded their referral code creation limit.
Module version, shown on the admin Modules page. Keep in sync with mix.exs.
Functions
Returns an %Ecto.Changeset{} for tracking referral code changes.
Examples
iex> PhoenixKitReferrals.change_code(code)
%Ecto.Changeset{data: %PhoenixKitReferrals{}}
Creates a changeset for referral code creation and admin edits.
The code string is trimmed and upcased before validation, so codes are stored in one canonical case.
Validations that constrain a value being set — expiration_date in the
future, max_uses within the system limit — run only when that field is
actually changing. An already-expired code, or a code whose max_uses predates
a lowered system limit, therefore remains editable: an admin can still
deactivate it, rename it, or fix its description.
The usage counter is not castable here. It is owned by use_code/2, which
increments it atomically.
Counts the total number of referral codes created by a user.
Examples
iex> PhoenixKitReferrals.count_user_codes(1)
5
Creates a referral code.
Examples
iex> PhoenixKitReferrals.create_code(%{code: "TEST123", max_uses: 10})
{:ok, %PhoenixKitReferrals{}}
iex> PhoenixKitReferrals.create_code(%{code: ""})
{:error, %Ecto.Changeset{}}
OTP apps whose templates Tailwind should scan for CSS classes.
Deletes a referral code.
Examples
iex> PhoenixKitReferrals.delete_code(code)
{:ok, %PhoenixKitReferrals{}}
iex> PhoenixKitReferrals.delete_code(code)
{:error, %Ecto.Changeset{}}
Disables the referral codes system.
Sets the "referral_codes_enabled" setting to false.
Examples
iex> PhoenixKitReferrals.disable_system()
{:ok, %Setting{}}
Enables the referral codes system.
Sets the "referral_codes_enabled" setting to true.
Examples
iex> PhoenixKitReferrals.enable_system()
{:ok, %Setting{}}
Checks if the referral codes system is enabled.
Returns true if the "referral_codes_enabled" setting is true. Any error (e.g. the database not being available yet at startup) is rescued and treated as disabled, so callers never need to special-case boot ordering.
Examples
iex> PhoenixKitReferrals.enabled?()
false
Checks if a referral code has expired.
A code with no expiration_date never expires.
Examples
iex> PhoenixKitReferrals.expired?(code)
false
Generates a random 5-character alphanumeric referral code.
Returns a string of uppercase letters and digits, excluding the characters
that read alike in most fonts (0, O, I, 1). Characters are drawn with
replacement, so a code may repeat a character.
This does not check the code against existing codes — see
generate_unique_code/1.
Examples
iex> PhoenixKitReferrals.generate_random_code()
"A7B2K"
Generates a random code that no existing referral code already holds.
Retries up to attempts times before giving up, so a caller never has to
handle a unique-constraint violation from a generated code.
Examples
iex> PhoenixKitReferrals.generate_unique_code()
{:ok, "A7B2K"}
Gets a single referral code by UUID.
Returns the referral code if found. Any input that is not a well-formed UUID
string — including an integer id — returns nil.
Examples
iex> PhoenixKitReferrals.get_code("550e8400-e29b-41d4-a716-446655440000")
%PhoenixKitReferrals{}
iex> PhoenixKitReferrals.get_code("00000000-0000-0000-0000-000000000000")
nil
iex> PhoenixKitReferrals.get_code(123)
nil
Same as get_code/1, but raises Ecto.NoResultsError if the code does not exist.
Examples
iex> PhoenixKitReferrals.get_code!("550e8400-e29b-41d4-a716-446655440000")
%PhoenixKitReferrals{}
iex> PhoenixKitReferrals.get_code!("00000000-0000-0000-0000-000000000000")
** (Ecto.NoResultsError)
Gets a single referral code by its string value.
The lookup trims and ignores case, so a user who types their code in lowercase
still matches. Returns the referral code if found, nil otherwise.
Examples
iex> PhoenixKitReferrals.get_code_by_string("WELCOME2024")
%PhoenixKitReferrals{}
iex> PhoenixKitReferrals.get_code_by_string(" welcome2024 ")
%PhoenixKitReferrals{}
iex> PhoenixKitReferrals.get_code_by_string("INVALID")
nil
Gets the current referral codes system configuration.
Returns a map with the current settings.
Examples
iex> PhoenixKitReferrals.get_config()
%{enabled: false, required: false}
Gets the maximum number of referral codes a single user can create.
Returns the system-wide limit for referral code creation per user. Defaults to 10 if not set.
Examples
iex> PhoenixKitReferrals.get_max_codes_per_user()
10
Gets the maximum number of uses allowed per referral code.
Returns the system-wide limit for how many times a single referral code can be used. Defaults to 100 if not set.
Examples
iex> PhoenixKitReferrals.get_max_uses_per_code()
100
Gets summary statistics for the referral codes system.
Returns counts and metrics useful for admin dashboards.
Examples
iex> PhoenixKitReferrals.get_system_stats()
%{total_codes: 10, active_codes: 8, total_usage: 150, codes_with_usage: 6}
Gets usage statistics for a referral code.
Examples
iex> PhoenixKitReferrals.get_usage_stats(code_uuid)
%{total_uses: 5, unique_users: 3, last_used: ~U[...], recent_users: [...]}
Ships the referral-link capture script (URL ?referral= -> localStorage ->
auto-filled referral_code field / OAuth links) via PhoenixKit's JS bundle
extension point.
Returns the list of referral codes ordered by creation date.
Examples
iex> PhoenixKitReferrals.list_codes()
[%PhoenixKitReferrals{}, ...]
Gets the most recent referral code usage records system-wide, for an admin activity feed.
Examples
iex> PhoenixKitReferrals.list_recent_usage(10)
[%PhoenixKitReferrals.ReferralCodeUsage{}, ...]
Lists all usage records for a referral code.
Examples
iex> PhoenixKitReferrals.list_usage_for_code(code_uuid)
[%PhoenixKitReferrals.ReferralCodeUsage{}, ...]
Gets codes that are currently valid for use.
Returns codes that are active, not expired, and haven't reached usage limits.
Mirrors valid_for_use?/1, including codes with no expiration_date — those
never expire.
Examples
iex> PhoenixKitReferrals.list_valid_codes()
[%PhoenixKitReferrals{}, ...]
Checks if referral codes are required for user registration.
Returns true if the "referral_codes_required" setting is true.
Examples
iex> PhoenixKitReferrals.required?()
false
Sets the maximum number of referral codes a single user can create.
Updates the system-wide limit for referral code creation per user.
Examples
iex> PhoenixKitReferrals.set_max_codes_per_user(5)
{:ok, %Setting{}}
Sets the maximum number of uses allowed per referral code.
Updates the system-wide limit for referral code usage.
Examples
iex> PhoenixKitReferrals.set_max_uses_per_code(50)
{:ok, %Setting{}}
Sets whether referral codes are required for registration.
Examples
iex> PhoenixKitReferrals.set_required(true)
{:ok, %Setting{}}
iex> PhoenixKitReferrals.set_required(false)
{:ok, %Setting{}}
Gets the codes with the most recorded uses, for an admin leaderboard.
Only codes with at least one use are returned. Preloads :creator and
:beneficiary_user for display.
Examples
iex> PhoenixKitReferrals.top_codes(5)
[%PhoenixKitReferrals{}, ...]
Updates a referral code.
Examples
iex> PhoenixKitReferrals.update_code(code, %{description: "Updated"})
{:ok, %PhoenixKitReferrals{}}
iex> PhoenixKitReferrals.update_code(code, %{code: ""})
{:error, %Ecto.Changeset{}}
Checks if a referral code has reached its usage limit.
Examples
iex> PhoenixKitReferrals.usage_limit_reached?(code)
false
Records usage of a referral code by a user.
Claims one use of the code and writes the matching usage record in a single
transaction. The claim is a conditional UPDATE that re-checks status,
expiration, and the usage limit in the database, so two concurrent callers can
never push a code past its max_uses.
A user may use a given code only once; a repeat attempt returns
{:error, :already_used} and leaves the counter untouched.
Examples
iex> PhoenixKitReferrals.use_code("WELCOME2024", user_uuid)
{:ok, %PhoenixKitReferrals.ReferralCodeUsage{}}
iex> PhoenixKitReferrals.use_code("NOSUCHCODE", user_uuid)
{:error, :code_not_found}
iex> PhoenixKitReferrals.use_code("EXPIRED", user_uuid)
{:error, :code_expired}
Checks if a user has already used a specific referral code.
Examples
iex> PhoenixKitReferrals.user_used_code?(user_uuid, code_uuid)
false
Checks if a referral code is currently valid for use.
A code is valid if:
- It is active (status: true)
- It has not exceeded its maximum uses
- It has not expired (a code with no
expiration_datenever expires)
Examples
iex> PhoenixKitReferrals.valid_for_use?(code)
true
Validates that a user hasn't exceeded their referral code creation limit.
Checks the current number of codes created by the user against the system limit.
Returns {:ok, :valid} if within limits, {:error, reason} if limit exceeded.
Examples
iex> PhoenixKitReferrals.validate_user_code_limit(1)
{:ok, :valid}
iex> PhoenixKitReferrals.validate_user_code_limit(1)
{:error, "You have reached the maximum limit of 10 referral codes"}
Module version, shown on the admin Modules page. Keep in sync with mix.exs.