Download the PHP package ozankurt/laravel-modules-loyalty without Composer

On this page you can find all versions of the php package ozankurt/laravel-modules-loyalty. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-modules-loyalty

KurtModules Loyalty

tests

Digital loyalty / stamp-card system for Laravel apps — collect stamps, earn rewards, redeem them, with a public card page, QR-based granting, and Apple/Google Wallet passes.

Part of the KurtModules family. Requires ozankurt/laravel-modules-core.

Requirements

A deliberate departure from the family

Every other KurtModules package is headless + Filament-only with no public views. Loyalty is the exception by design: it is a customer-facing surface, so it ships public routes, Blade views, and compiled JS/CSS assets, and no Filament panel. It still follows every other family convention (Core-based provider, anonymous publishable migrations, Pest + Testbench, SemVer).

Architecture

Status — all milestones landed ✅

Quick start

loyalty:install publishes every migration, including the tier table (loyalty_program_tiers) and the expiry columns (stamp_expiry_days / reward_expiry_days on programs, rewards_expired on cards) — so a single php artisan migrate sets up the full schema.

Define who staff are (the terminal is deny-all until you do):

Wallet passes are opt-in — set the Apple certificate / Google service-account env vars, then php artisan loyalty:wallet-check. Live pass updates need LOYALTY_WALLET_PUSH=true plus a queue worker.

HTTP modes

Pick how much of the HTTP surface the package registers with LOYALTY_HTTP_MODE (config loyalty.http.mode). The domain services + events are always available regardless — the controllers are a thin adapter over them, never the source of truth.

Mode Registers Use when
ui (default) JSON/resource endpoints + shipped HTML card page & terminal + views/assets You want the full Mars-style experience out of the box.
api JSON + resource endpoints only (state, create, claim, voucher redeem, terminal stamp/redeem, wallet passes). No Blade, no assets. You're building your own frontend but want the HTTP layer.
headless Nothing. You want to wire your own routes/controllers and call CardService / StampService / VoucherService / RedemptionService directly.

ui ⊇ api. Even in ui, the card page route honours Accept: application/json and returns state instead of HTML.

loyalty.http.mode resolves through Core's Kurt\Modules\Core\Http\HttpMode enum (identical headless/api/ui string values). The staff terminal's throttle budget lives in loyalty.http.rate_limit (maxAttempts,decayMinutes, default 60,1), registered as the shared throttle:loyalty-api limiter; the public write endpoints (create / claim / voucher redeem) keep their own tighter loyalty.routes.rate_limit budget (default 30,1).

Frontend

The behavior layer is framework-free and keyed to a stable data-* attribute contract, so the entire stylesheet is swappable without touching JS. Rebuild/extend it with your own pipeline:

Data-attribute contract (rewrite the Blade freely as long as these survive):

Attribute Role
data-loyalty-card / data-loyalty-token / data-loyalty-state-url card root + poll target
data-loyalty-stamps → data-loyalty-stamp[data-state] the stamp grid (JS toggles data-state)
data-loyalty-progress / data-loyalty-count / data-loyalty-required progress (live region)
data-loyalty-qr / data-loyalty-wallet="apple\|google" QR + wallet buttons
data-loyalty-terminal + data-loyalty-{scanner,card-input,stamp-btn,redeem-btn,terminal-result} staff terminal

Wallet setup

Both providers are opt-in and only render buttons once configured. Env vars:

Multi-tier rewards

A program can define a ladder of ProgramTier rows (loyalty_program_tiers) instead of a single repeating goal. Each tier has an absolute threshold (cumulative stamp count), a reward label, an optional reward_payload JSON (voucher config / metadata), and a position for ordering:

When a stamp crossing meets the next unmet tier threshold, that tier's reward is credited to rewards_earned and a TierReached event (carrying the Card and ProgramTier) fires, alongside the existing CardCompleted event. A single multi-stamp voucher that vaults past several thresholds credits each crossed tier.

Fully backward compatible: a program with no tier rows behaves exactly as before — the single stamps_required threshold, repeating, with the same rollover crediting for reset_on_reward = false.

Analytics

LoyaltyStatsService::overview(?int $programId, ?Carbon $since, ?Carbon $until) returns cards issued, active cards, stamps granted, rewards earned/redeemed, and the redemption rate — overall (totals) and per program (programs) — from a handful of grouped aggregate queries (no N+1). The optional program filter and date range narrow the population.

Stamp / reward expiry

Stamps and unredeemed earned rewards can expire after a configurable window. Defaults live in config/loyalty.php under expiry (LOYALTY_STAMP_EXPIRY_DAYS / LOYALTY_REWARD_EXPIRY_DAYS), and each program can override them via its stamp_expiry_days / reward_expiry_days columns. null everywhere = never expires (today's behaviour).

The command voids (zeroes) stamps on cards whose last activity is older than stamp_expiry_days, and voids unredeemed earned rewards (tracked in the new rewards_expired counter, kept separate from redemptions so analytics stay accurate) older than reward_expiry_days. Each runs inside a locked transaction and fires StampsExpired / RewardExpired. It is idempotent — a second run is a no-op. Schedule it in the consuming app:

See docs/superpowers/plans for the build plan.

Testing

CI runs the same checks on every push and pull request (.github/workflows/tests.yml), against PHP 8.4 / Laravel 13. Static analysis is held at PHPStan level 8; the suite runs on Pest 5.

License

MIT © Ozan Kurt


All versions of laravel-modules-loyalty with dependencies

PHP Build Version
Package Version
Requires php Version ^8.4
bacon/bacon-qr-code Version ^3.1
illuminate/contracts Version ^13.0
illuminate/database Version ^13.0
illuminate/support Version ^13.0
ozankurt/laravel-modules-core Version ^2.0
spatie/laravel-package-tools Version ^1.93
spatie/laravel-translatable Version ^6.11
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package ozankurt/laravel-modules-loyalty contains the following files

Loading the files please wait ...