PHPackages                             quvel/core - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. quvel/core

ActiveLibrary[Framework](/categories/framework)

quvel/core
==========

Core foundation package for Quvel framework - Device management, push notifications, platform detection, distributed tracing, and more for Laravel applications

v1.2.0(4mo ago)048MITPHPPHP ^8.4CI passing

Since Nov 3Pushed 4mo agoCompare

[ Source](https://github.com/ItsIrv/quvel-api-core)[ Packagist](https://packagist.org/packages/quvel/core)[ RSS](/packages/quvel-core/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (19)Versions (4)Used By (0)

Quvel Core
==========

[](#quvel-core)

A Laravel package providing essential utilities for full-stack applications including device management, push notifications, platform detection, locale handling, distributed tracing, and more.

Installation
------------

[](#installation)

### Step 1: Add the Package

[](#step-1-add-the-package)

Install via composer:

```
composer require quvel/core
```

### Step 2: Publish Configuration

[](#step-2-publish-configuration)

Publish the configuration file to `config/quvel.php`:

```
php artisan vendor:publish --tag=quvel-config
```

This creates `config/quvel.php` with all available options.

### Step 3: Publish and Run Migrations

[](#step-3-publish-and-run-migrations)

Publish the migrations:

```
php artisan vendor:publish --tag=quvel-migrations
```

This publishes:

- `2024_01_01_000000_create_platform_settings_table` - For platform-specific settings
- `2024_01_01_000001_create_user_devices_table` - For device management

**Note**: Migration filenames include timestamps (YYYY\_MM\_DD\_HHMMSS format) to ensure they run in the correct order. The timestamps are part of Laravel's convention for managing database schema versions.

Run the migrations:

```
php artisan migrate
```

### Step 4: Configure Environment Variables

[](#step-4-configure-environment-variables)

Add the following to your `.env` file (optional, depending on features you use):

```
# Captcha (Google reCAPTCHA)
CAPTCHA_ENABLED=true
RECAPTCHA_SECRET_KEY=your-secret-key
RECAPTCHA_SITE_KEY=your-site-key
RECAPTCHA_SCORE_THRESHOLD=0.5

# Push Notifications
PUSH_ENABLED=true
PUSH_DRIVERS=fcm,apns,web

# FCM (Firebase Cloud Messaging)
FCM_SERVER_KEY=your-fcm-server-key
FCM_PROJECT_ID=your-fcm-project-id

# APNS (Apple Push Notification Service)
APNS_KEY_PATH=/path/to/apns/key.p8
APNS_KEY_ID=your-key-id
APNS_TEAM_ID=your-team-id
APNS_BUNDLE_ID=com.yourapp.bundle
APNS_ENVIRONMENT=sandbox # or 'production'

# Web Push (VAPID)
VAPID_SUBJECT=mailto:your@email.com
VAPID_PUBLIC_KEY=your-public-key
VAPID_PRIVATE_KEY=your-private-key

# Device Management
DEVICES_ENABLED=true
DEVICES_ALLOW_ANONYMOUS=false
DEVICES_CLEANUP_DAYS=90
DEVICES_MAX_PER_USER=10

# Frontend/Redirects
FRONTEND_URL=http://localhost:3000
FRONTEND_REDIRECT_MODE=universal_links # or 'custom_scheme', 'landing_page', 'web_only'
FRONTEND_CUSTOM_SCHEME=myapp
FRONTEND_LANDING_PAGE_TIMEOUT=5

# Security
SECURITY_TRUSTED_IPS=127.0.0.1,::1
SECURITY_API_KEY=your-internal-api-key
SECURITY_DISABLE_IP_CHECK=false
SECURITY_DISABLE_KEY_CHECK=false

# Tracing
TRACING_ENABLED=true
TRACING_ACCEPT_EXTERNAL=true

# Locale
LOCALE_ALLOWED=en,es,fr
LOCALE_FALLBACK=en
LOCALE_NORMALIZE=true

# Platform Detection
HEADER_PLATFORM=X-Platform
HEADER_TRACE_ID=X-Trace-ID

# Public IDs
PUBLIC_ID_DRIVER=ulid # or 'uuid'
PUBLIC_ID_COLUMN=public_id
```

### Step 5: Verify Installation

[](#step-5-verify-installation)

Check that the package is discovered:

```
php artisan package:discover
```

You should see `quvel/core` in the list.

Check available commands:

```
php artisan list
```

### Optional: Publish Additional Assets

[](#optional-publish-additional-assets)

```
# Publish API routes for device management (optional - only if you want to customize them)
php artisan vendor:publish --tag=quvel-routes

# Publish language files
php artisan vendor:publish --tag=quvel-lang

# Publish views (landing pages, etc.)
php artisan vendor:publish --tag=quvel-views
```

**Important**: Routes are disabled by default. To enable device management routes, add to your `.env`:

```
# Enable device management API routes
QUVEL_DEVICE_ROUTES_ENABLED=true

# Enable platform settings API routes
QUVEL_PLATFORM_SETTINGS_ROUTES_ENABLED=true
```

You do **not** need to publish the routes file unless you want to customize the route definitions. The routes will work from the package once enabled via environment variables.

### Troubleshooting

[](#troubleshooting)

**Package not discovered:**

- Clear bootstrap cache: `rm bootstrap/cache/*.php`
- Run: `php artisan package:discover`
- Check `composer.json` for correct repository path

**Migrations already exist:**

- Migrations are automatically loaded from the package
- Only publish if you need to customize them

**Config changes not taking effect:**

- Run: `php artisan config:clear`
- Check that `.env` values are correct

Table of Contents
-----------------

[](#table-of-contents)

- [Captcha](#captcha)
- [Device Management](#device-management)
- [Push Notifications](#push-notifications)
- [Platform Detection](#platform-detection)
- [Locale Management](#locale-management)
- [Distributed Tracing](#distributed-tracing)
- [Public IDs](#public-ids)
- [Redirects](#redirects)
- [Security](#security)
- [Middleware](#middleware)
- [Publishing Assets](#publishing-assets)

---

Captcha
-------

[](#captcha)

Protect your endpoints from bots and automated attacks using Google reCAPTCHA.

### Configuration

[](#configuration)

```
// config/quvel.php
'captcha' => [
    'enabled' => env('CAPTCHA_ENABLED', true),
    'driver' => env('CAPTCHA_DRIVER', \Quvel\Core\Captcha\GoogleRecaptchaDriver::class),
    'score_threshold' => env('RECAPTCHA_SCORE_THRESHOLD', 0.5),
    'timeout' => env('CAPTCHA_TIMEOUT', 30),
],
```

```
CAPTCHA_ENABLED=true
RECAPTCHA_SECRET_KEY=your-secret-key
RECAPTCHA_SITE_KEY=your-site-key
```

### Usage

[](#usage)

**Verify captcha:**

```
use Quvel\Core\Facades\Captcha;

$result = Captcha::verify($token, $request->ip());

if ($result->isSuccessful()) {
    // Continue with request
}

// Check reCAPTCHA v3 score
if ($result->hasScore() && $result->score >= 0.5) {
    // High confidence user
}
```

**Protect routes with middleware:**

```
Route::post('/register', function () {
    // Protected by captcha
})->middleware('captcha');

// Custom input field
Route::post('/login', function () {
    // ...
})->middleware('captcha:recaptcha_response');
```

### Custom Captcha Driver

[](#custom-captcha-driver)

```
use Quvel\Core\Contracts\CaptchaDriverInterface;
use Quvel\Core\Captcha\CaptchaVerificationResult;

class HCaptchaDriver implements CaptchaDriverInterface
{
    public function verify(string $token, ?string $ip = null, ?string $action = null): CaptchaVerificationResult
    {
        // Your verification logic
        return CaptchaVerificationResult::success();
    }

    public function supportsScoring(): bool
    {
        return false;
    }

    public function getDefaultScoreThreshold(): ?float
    {
        return null;
    }
}
```

Set in config:

```
'captcha' => [
    'driver' => \App\Captcha\HCaptchaDriver::class,
],
```

### Events

[](#events)

```
use Quvel\Core\Events\CaptchaVerifySuccess;
use Quvel\Core\Events\CaptchaVerifyFailed;

Event::listen(CaptchaVerifyFailed::class, function ($event) {
    Log::warning('Captcha failed', [
        'ip' => $event->ipAddress,
        'reason' => $event->reason,
    ]);
});
```

---

Device Management
-----------------

[](#device-management)

Track user devices across web, mobile, and desktop platforms. Register devices, manage push tokens, and maintain device lifecycle.

### Configuration

[](#configuration-1)

```
// config/quvel.php
'devices' => [
    'enabled' => env('DEVICES_ENABLED', true),
    'allow_anonymous' => env('DEVICES_ALLOW_ANONYMOUS', false),
    'cleanup_inactive_after_days' => env('DEVICES_CLEANUP_DAYS', 90),
    'max_devices_per_user' => env('DEVICES_MAX_PER_USER', 10),
],
```

### Usage

[](#usage-1)

**Register a device:**

```
use Quvel\Core\Facades\Device;

$device = Device::registerDevice([
    'device_id' => 'device-123',
    'platform' => 'ios',
    'device_name' => 'John's iPhone',
    'push_token' => 'fcm-token',
    'push_provider' => 'fcm',
]);
```

**Manage devices:**

```
// Update push token
DeviceManager::updatePushToken('device-123', 'new-token', 'fcm');

// Deactivate device
DeviceManager::deactivateDevice('device-123', 'User logged out');

// Get user's devices
$devices = DeviceManager::getUserDevices(auth()->id());
```

### Device Model

[](#device-model)

```
use Quvel\Core\Models\UserDevice;

// Get active devices for a user
$devices = UserDevice::forUser($userId)->active()->get();

// Find by device ID
$device = UserDevice::where('device_id', 'device-123')->first();

// Check if device has valid push token
if ($device->hasValidPushToken()) {
    // Send notification
}

// Platform filtering
$iosDevices = UserDevice::forPlatform('ios')->get();
```

### API Routes

[](#api-routes)

Publish and enable device routes:

```
php artisan vendor:publish --tag=quvel-routes
```

```
// config/quvel.php
'routes' => [
    'devices' => [
        'enabled' => env('QUVEL_DEVICE_ROUTES_ENABLED', false),
        'prefix' => 'api/devices',
        'name' => 'devices.',
        'middleware' => ['api', 'auth:sanctum'],
    ],
],
```

Available endpoints:

- `POST /api/devices/register` - Register a device
- `POST /api/devices/push-token` - Update push token
- `POST /api/devices/deactivate` - Deactivate device
- `GET /api/devices/list` - List user's devices

### Middleware

[](#middleware)

Automatically detect and track devices:

```
$device = $request->attributes->get('device');
$deviceId = $request->attributes->get('device_id');
```

### Events

[](#events-1)

```
use Quvel\Core\Events\DeviceRegistered;
use Quvel\Core\Events\DeviceRemoved;

Event::listen(DeviceRegistered::class, function ($event) {
    Log::info('Device registered', [
        'device_id' => $event->deviceId,
        'platform' => $event->platform,
    ]);
});
```

---

Push Notifications
------------------

[](#push-notifications)

Send push notifications to user devices across multiple platforms (FCM, APNS, Web Push). Supports device targeting and batch processing.

### Configuration

[](#configuration-2)

```
// config/quvel.php
'push' => [
    'enabled' => env('PUSH_ENABLED', true),
    'drivers' => explode(',', env('PUSH_DRIVERS', 'fcm,apns,web')),

    'fcm' => [
        'server_key' => env('FCM_SERVER_KEY'),
        'project_id' => env('FCM_PROJECT_ID'),
    ],

    'apns' => [
        'key_path' => env('APNS_KEY_PATH'),
        'key_id' => env('APNS_KEY_ID'),
        'team_id' => env('APNS_TEAM_ID'),
        'bundle_id' => env('APNS_BUNDLE_ID'),
        'environment' => env('APNS_ENVIRONMENT', 'sandbox'),
    ],

    'web_push' => [
        'vapid_subject' => env('VAPID_SUBJECT'),
        'vapid_public_key' => env('VAPID_PUBLIC_KEY'),
        'vapid_private_key' => env('VAPID_PRIVATE_KEY'),
    ],

    'batch_size' => env('PUSH_BATCH_SIZE', 1000),
],

'targeting' => [
    'default_scope' => env('TARGETING_DEFAULT_SCOPE', 'requesting_device'),
],
```

### Usage

[](#usage-2)

**Send to device:**

```
use Quvel\Core\Facades\PushNotification;

$success = PushNotification::sendToDevice(
    device: $device,
    title: 'New Message',
    body: 'You have a new message',
    data: ['message_id' => 123]
);
```

**Send to multiple devices:**

```
$results = PushNotification::sendToDevices(
    devices: $devices,
    title: 'Update Available',
    body: 'A new version is available'
);

// Returns: ['device-123' => true, 'device-456' => false, ...]
```

### Device Targeting

[](#device-targeting)

**Get target devices:**

```
use Quvel\Core\Facades\Targeting;

// Get devices for targeting scope
$devices = Targeting::getTargetDevices(
    requestingDevice: $device,
    userId: auth()->id(),
    scope: 'all_user_devices' // or 'requesting_device'
);

// Then send to those devices
PushNotification::sendToDevices($devices, $title, $body);
```

**Targeting scopes:**

- `requesting_device` - Only the device making the request
- `all_user_devices` - All of the user's active devices

### Custom Push Driver

[](#custom-push-driver)

```
use Quvel\Core\Contracts\PushDriver;
use Quvel\Core\Models\UserDevice;

class CustomPushDriver implements PushDriver
{
    public function getName(): string
    {
        return 'custom';
    }

    public function supports(string $platform): bool
    {
        return $platform === 'my-platform';
    }

    public function isConfigured(): bool
    {
        return !empty(config('services.custom_push.api_key'));
    }

    public function send(UserDevice $device, string $title, string $body, array $data = []): bool
    {
        // Your sending logic
        return true;
    }
}
```

Register in service provider:

```
app(PushManager::class)->extend('custom', function () {
    return new CustomPushDriver();
});
```

### Events

[](#events-2)

```
use Quvel\Core\Events\PushNotificationSent;
use Quvel\Core\Events\PushNotificationFailed;

Event::listen(PushNotificationSent::class, function ($event) {
    Log::info('Push sent', [
        'devices' => $event->deviceIds,
        'title' => $event->title,
    ]);
});
```

---

Platform Detection
------------------

[](#platform-detection)

Detect the platform (web, mobile, desktop) from which requests originate.

### Configuration

[](#configuration-3)

```
// config/quvel.php
'headers' => [
    'platform' => env('HEADER_PLATFORM'), // Defaults to 'X-Platform'
],
```

### Usage

[](#usage-3)

```
use Quvel\Core\Facades\PlatformDetector;

$platform = Platform::getPlatform(); // 'web', 'mobile', or 'desktop'

if (Platform::isPlatform('mobile')) {
    // Mobile-specific logic
}
```

**Platform tags:**

```
use Quvel\Core\Platform\PlatformTag;

PlatformTag::IOS->value;        // 'ios'
PlatformTag::ANDROID->value;    // 'android'
PlatformTag::ELECTRON->value;   // 'electron'
PlatformTag::TABLET->value;     // 'tablet'
PlatformTag::SCREEN_LG->value;  // 'screen:lg'

$tag = PlatformTag::tryFrom('ios');
$mode = $tag->getMainMode(); // 'mobile'
$category = $tag->getCategory(); // 'os'
```

**Available platform tags:**

- Runtime: `web`, `capacitor`, `cordova`, `electron`, `tauri`
- OS: `ios`, `android`, `macos`, `windows`, `linux`
- Form Factor: `mobile`, `tablet`, `desktop`
- Screen Sizes: `screen:xs`, `screen:sm`, `screen:md`, `screen:lg`, `screen:xl`

### Frontend Integration

[](#frontend-integration)

```
// Multi-tag platform detection (comma-separated)
// iPhone in Capacitor
fetch('/api/endpoint', {
    headers: {
        'X-Platform': 'capacitor,ios,mobile,screen:sm'
    }
});

// iPad in Safari
fetch('/api/endpoint', {
    headers: {
        'X-Platform': 'web,ios,tablet,screen:lg'
    }
});

// Electron on macOS
fetch('/api/endpoint', {
    headers: {
        'X-Platform': 'electron,macos,desktop,screen:xl'
    }
});
```

---

Locale Management
-----------------

[](#locale-management)

Automatic locale detection and management from request headers.

### Configuration

[](#configuration-4)

```
// config/quvel.php
'locale' => [
    'allowed_locales' => explode(',', env('LOCALE_ALLOWED', 'en')),
    'fallback_locale' => env('LOCALE_FALLBACK', 'en'),
    'normalize_locales' => env('LOCALE_NORMALIZE', true), // en-US -> en
],
```

### Usage

[](#usage-4)

```
use Quvel\Core\Facades\Locale;

// Detect locale from request
$locale = $request->header('Accept-Language');

// Middleware automatically detects and sets locale
// Access via Laravel's app()->getLocale()
```

Locale is detected from:

1. `Accept-Language` header
2. Falls back to configured default

---

Distributed Tracing
-------------------

[](#distributed-tracing)

Track requests across your distributed system with automatic trace ID generation and propagation.

### Configuration

[](#configuration-5)

```
// config/quvel.php
'tracing' => [
    'enabled' => env('TRACING_ENABLED', true),
    'accept_external_trace_ids' => env('TRACING_ACCEPT_EXTERNAL', true),
],

'headers' => [
    'trace_id' => env('HEADER_TRACE_ID'), // Defaults to 'X-Trace-ID'
],
```

### Usage

[](#usage-5)

```
use Quvel\Core\Facades\Trace;

// Middleware automatically generates trace IDs
// Access from Laravel's Context
use Illuminate\Support\Facades\Context;

$traceId = Context::get('trace_id');
```

### Frontend Integration

[](#frontend-integration-1)

```
const traceId = generateUUID();

fetch('/api/endpoint', {
    headers: {
        'X-Trace-ID': traceId
    }
});
```

---

Public IDs
----------

[](#public-ids)

Generate user-facing IDs (ULIDs or UUIDs) for models instead of exposing database IDs.

### Configuration

[](#configuration-6)

```
// config/quvel.php
'public_id' => [
    'driver' => env('PUBLIC_ID_DRIVER', 'ulid'), // 'ulid' or 'uuid'
    'column' => env('PUBLIC_ID_COLUMN', 'public_id'),
],
```

### Usage

[](#usage-6)

Add trait to your model:

```
use Quvel\Core\Concerns\HasPublicId;

class Order extends Model
{
    use HasPublicId;
}
```

Auto-generates public ID on creation:

```
$order = Order::create([...]);

echo $order->public_id; // '01HQ...' (ULID) or 'uuid-here'

// Find by public ID
$order = Order::wherePublicId('01HQ...')->first();
```

### Route Model Binding

[](#route-model-binding)

```
Route::get('/orders/{order:public_id}', function (Order $order) {
    return $order;
});
```

---

Redirects
---------

[](#redirects)

Smart redirects that work across web, mobile, and desktop platforms using universal links, custom schemes, or landing pages.

### Configuration

[](#configuration-7)

```
// config/quvel.php
'frontend' => [
    'url' => env('FRONTEND_URL', 'http://localhost:3000'),
    'custom_scheme' => env('FRONTEND_CUSTOM_SCHEME'),

    'redirect_mode' => env('FRONTEND_REDIRECT_MODE', 'universal_links'),
    // Options: 'universal_links', 'custom_scheme', 'landing_page', 'web_only'

    'landing_page_timeout' => env('FRONTEND_LANDING_PAGE_TIMEOUT', 5),

    'allowed_redirect_domains' => explode(',', env('FRONTEND_ALLOWED_DOMAINS', '')),
],
```

### Usage

[](#usage-7)

```
use Quvel\Core\Facades\Redirect;

// Redirect to frontend path
return Redirect::redirect('/dashboard');

// With query params
return Redirect::redirect('/orders/123', ['status' => 'new']);

// With message
return Redirect::redirectWithMessage('/login', 'Please sign in');

// Get URL without redirecting
$url = Redirect::getUrl('/profile');
```

### Redirect Modes

[](#redirect-modes)

**Universal Links** (recommended): Uses HTTPS URLs that open the app if installed, otherwise open in browser.

```
FRONTEND_REDIRECT_MODE=universal_links
FRONTEND_URL=https://app.example.com
```

**Custom Scheme**: Uses custom URL scheme (myapp://).

```
FRONTEND_REDIRECT_MODE=custom_scheme
FRONTEND_CUSTOM_SCHEME=myapp
```

**Landing Page**: Shows countdown page before redirect.

```
FRONTEND_REDIRECT_MODE=landing_page
FRONTEND_LANDING_PAGE_TIMEOUT=5
```

**Web Only**: Always redirects to web URL.

```
FRONTEND_REDIRECT_MODE=web_only
```

---

Security
--------

[](#security)

### Internal Request Validation

[](#internal-request-validation)

Protect internal endpoints from external access:

```
// config/quvel.php
'security' => [
    'internal_requests' => [
        'trusted_ips' => explode(',', env('SECURITY_TRUSTED_IPS', '127.0.0.1,::1')),
        'api_key' => env('SECURITY_API_KEY'),
        'disable_ip_check' => env('SECURITY_DISABLE_IP_CHECK', false),
        'disable_key_check' => env('SECURITY_DISABLE_KEY_CHECK', false),
    ],
],
```

**Protect routes:**

```
Route::middleware('internal-only')->group(function () {
    Route::get('/internal/stats', [StatsController::class, 'index']);
});
```

**Frontend SSR integration:**

```
// In your SSR server
fetch('http://api.internal/endpoint', {
    headers: {
        'X-SSR-Key': process.env.SECURITY_API_KEY
    }
});
```

---

Middleware
----------

[](#middleware-1)

### Available Middleware

[](#available-middleware)

```
'captcha'             // Verify captcha token
'config-gate'         // Gate access based on config
'device-detection'    // Detect and track devices
'internal-only'       // Restrict to internal requests
'locale'              // Auto-detect and set locale
'platform-detection'  // Detect platform (web/mobile/desktop)
'trace'               // Generate/propagate trace IDs
```

### Global Configuration

[](#global-configuration)

```
// config/quvel.php
'middleware' => [
    'aliases' => [
        'captcha' => \Quvel\Core\Http\Middleware\VerifyCaptcha::class,
        'config-gate' => \Quvel\Core\Http\Middleware\ConfigGate::class,
        'device-detection' => \Quvel\Core\Http\Middleware\DeviceDetection::class,
        'internal-only' => \Quvel\Core\Http\Middleware\InternalOnly::class,
        'locale' => \Quvel\Core\Http\Middleware\LocaleMiddleware::class,
        'platform-detection' => \Quvel\Core\Http\Middleware\PlatformDetection::class,
        'trace' => \Quvel\Core\Http\Middleware\TraceMiddleware::class,
    ],

    'groups' => [
        'web' => [
            'platform-detection',
            'device-detection',
            'locale',
            'trace',
        ],
        'api' => [
            'platform-detection',
            'device-detection',
            'locale',
            'trace',
        ],
    ],
],
```

---

Extending the Package
---------------------

[](#extending-the-package)

### Custom Implementations

[](#custom-implementations)

All core services use contracts and can be extended or replaced:

```
use Quvel\Core\Device\Device as BaseManager;

class CustomDeviceManager extends BaseManager
{
    public function registerDevice(array $deviceData): UserDevice
    {
        $device = parent::registerDevice($deviceData);

        // Add custom logic (webhooks, etc.)

        return $device;
    }
}

// Bind in service provider
$this->app->bind(
    \Quvel\Core\Contracts\Device::class,
    \App\Services\CustomDeviceManager::class
);
```

### Available Contracts

[](#available-contracts)

- `CaptchaVerifier`
- `CaptchaDriverInterface`
- `DeviceManager`
- `LocaleResolver`
- `PlatformDetector`
- `PublicIdGenerator`
- `PushManager`
- `PushDriver`
- `AppRedirector`
- `TraceIdGenerator`

---

Events
------

[](#events-3)

### Device Events

[](#device-events)

- `DeviceRegistered` - Device registered
- `DeviceRemoved` - Device deactivated

### Push Notification Events

[](#push-notification-events)

- `PushNotificationSent` - Notification sent successfully
- `PushNotificationFailed` - Notification failed

### Captcha Events

[](#captcha-events)

- `CaptchaVerifySuccess` - Captcha verification succeeded
- `CaptchaVerifyFailed` - Captcha verification failed

### Trace Events

[](#trace-events)

- `PublicTraceAccepted` - External trace ID accepted

---

Publishing Assets
-----------------

[](#publishing-assets)

```
# Publish everything
php artisan vendor:publish --provider="Quvel\Core\Providers\CoreServiceProvider"

# Publish specific assets
php artisan vendor:publish --tag=quvel-config
php artisan vendor:publish --tag=quvel-migrations
php artisan vendor:publish --tag=quvel-routes
php artisan vendor:publish --tag=quvel-lang
php artisan vendor:publish --tag=quvel-views
```

---

License
-------

[](#license)

MIT

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance74

Regular maintenance activity

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~24 days

Total

3

Last Release

149d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/375295562e477f54fbc56f9ab127afb51d2a0ff077212723db68456c95156cbf?d=identicon)[pdxapps](/maintainers/pdxapps)

---

Top Contributors

[![ItsIrv](https://avatars.githubusercontent.com/u/1527451?v=4)](https://github.com/ItsIrv "ItsIrv (47 commits)")

---

Tags

laravelcaptchamobilepush notificationsdistributed-tracingpwaquvelmulti-platformdevice-managementplatform-detection

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm, Rector

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/quvel-core/health.svg)

```
[![Health](https://phpackages.com/badges/quvel-core/health.svg)](https://phpackages.com/packages/quvel-core)
```

###  Alternatives

[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k12.1M99](/packages/laravel-pulse)[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.5k25.9M107](/packages/laravel-cashier)[laravel/scout

Laravel Scout provides a driver based solution to searching your Eloquent models.

1.7k49.4M479](/packages/laravel-scout)[laravel/passport

Laravel Passport provides OAuth2 server support to Laravel.

3.4k85.0M532](/packages/laravel-passport)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)[laravel/lumen-framework

The Laravel Lumen Framework.

1.5k26.2M709](/packages/laravel-lumen-framework)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
