insynnia/laravel-badges

Badge, trigger and award engine for Laravel. Award badges to entities via named triggers or manually โ€” idempotent and framework-native.

Maintainers

Package info

github.com/Tatanstii/laravel-badges

pkg:composer/insynnia/laravel-badges

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-06-18 00:46 UTC

This package is auto-updated.

Last update: 2026-06-18 00:54:23 UTC


README

๐Ÿ… Laravel Badges

A small, framework-native badge & achievement engine for Laravel.
Define badges, expose named triggers, and award them to entities โ€” idempotently.

Latest Version Tests Stars PHP Version Laravel License

No multi-tenancy, no billing, no dashboard. Just the badge logic โ€” drop it into any Laravel app and start awarding.

โœจ Features

  • ๐ŸŽ–๏ธ Badges with name, description, image, category and tier (bronze โ†’ platinum).
  • โšก Triggers โ€” award a badge by firing a named slug (first-login, 100-sales, โ€ฆ).
  • ๐Ÿชช Entities keyed by your external_id, auto-created on first award.
  • โ™ป๏ธ Idempotent awards โ€” firing twice never duplicates.
  • ๐Ÿ—‚๏ธ Metadata โ€” attach arbitrary JSON to badges, entities and awards.
  • ๐Ÿงฉ Bring your own HTTP โ€” ships the domain logic, stays unopinionated about routes & auth.
  • ๐Ÿงช Fully tested, portable across SQLite / MySQL / PostgreSQL.

๐Ÿ“ฆ Requirements

  • PHP 8.2+
  • Laravel 11, 12 or 13

๐Ÿš€ Installation

composer require insynnia/laravel-badges
php artisan migrate

Publish config / migrations if you want to tweak them:

php artisan vendor:publish --tag=badges-config
php artisan vendor:publish --tag=badges-migrations

๐Ÿง  Concepts

Model What it is
Badge A named award (name, description, image, category, tier, metadata).
Trigger A slug that, when fired, awards a specific badge.
Entity A recipient, identified by your own external_id (e.g. a user id).
EntityBadge The award record linking an entity to a badge (unique per pair).
fireTrigger('first-login', 'user_123')
        โ”‚
        โ–ผ
   Trigger(slug) โ”€โ”€โ–ถ Badge โ”€โ”€โ–ถ EntityBadge โ—€โ”€โ”€ Entity(external_id)
                                   (unique entity + badge)

โšก Quick start

use Insynnia\Badges\BadgeService;
use Insynnia\Badges\Models\Badge;
use Insynnia\Badges\Models\Trigger;

$badge = Badge::create(['name' => 'First Login', 'tier' => 'bronze']);
Trigger::create(['badge_id' => $badge->id, 'slug' => 'first-login']);

$badges = app(BadgeService::class);

// Fire a trigger โ€” auto-creates the entity, awards the badge once.
$result = $badges->fireTrigger('first-login', externalEntityId: 'user_123');
// ['awarded' => true, 'badge' => Badge, 'reason' => 'Badge awarded successfully.']

// Award directly by badge id (bypasses triggers).
$badges->awardManually($badge->id, 'user_123');

// Revoke.
$badges->revoke($badge->id, 'user_123');

๐Ÿ“– API reference

BadgeService is the entry point. fireTrigger() and awardManually() both return array{awarded: bool, badge: ?Badge, reason: string} and are idempotent โ€” a repeat award returns awarded => false.

Method Description
fireTrigger(string $slug, string $entityId, array $metadata = []) Fire a trigger by slug and award its badge.
awardManually(string $badgeId, string $entityId, array $metadata = []) Award a badge by id, bypassing triggers.
revoke(string $badgeId, string $entityId): bool Remove an award. Returns true if a record was deleted.

Querying

Badge::active()->byCategory('streak')->byTier('gold')->get();
$entity->badges;                       // badges an entity holds
Badge::find($id)->entities;            // entities that hold a badge
$badge->image_url;                     // resolved via the configured disk

Badge images

image_url resolves image_path through the disk in config/badges.php (defaults to public). Store the file yourself and persist its path:

$badge->update(['image_path' => $path]); // $badge->image_url is now resolvable

๐ŸŒ HTTP layer

This package ships the domain logic only โ€” no routes or controllers โ€” so it stays unopinionated about your API shape, auth and pagination. Wire BadgeService into your own controllers. A typical mapping:

Method & path Call
POST /trigger/{slug} fireTrigger($slug, $entityId, $meta)
POST /entities/{id}/badges awardManually($badgeId, $id, $meta)
DELETE /entities/{id}/badges/{badge} revoke($badgeId, $id)

๐Ÿงช Testing

composer install
composer test

๐Ÿค Contributing

PRs welcome. Please add a test for any behaviour change and run composer test before opening a pull request.

๐Ÿ”’ Security

If you discover a security issue, please email the maintainers instead of using the issue tracker.

๐Ÿ“ Changelog

See CHANGELOG.md for what has changed recently.

๐Ÿ“„ License

The MIT License (MIT). See LICENSE.