misaf / vendra-reseller
Reseller domain and self-service panel for the Vendra platform
Requires
- php: ^8.3
- filament/filament: ^5.6.8
- illuminate/console: ^13.0
- illuminate/contracts: ^13.0
- illuminate/database: ^13.0
- illuminate/http: ^13.0
- illuminate/support: ^13.0
- misaf/laravel-email-validation: ^1.0
- misaf/vendra-localization: 1.x-dev
- misaf/vendra-property: 1.x-dev
- misaf/vendra-subscription: 1.x-dev
- misaf/vendra-support: 1.x-dev
- misaf/vendra-tenant: 1.x-dev
- misaf/vendra-transaction: 1.x-dev
- spatie/laravel-multitenancy: ^4.1.3
- spatie/laravel-package-tools: ^1.93.1
- spatie/laravel-sluggable: ^4.0.2
Requires (Dev)
- fakerphp/faker: ^1.24.1
- larastan/larastan: ^3.10.0
- laravel/boost: ^2.4.12
- laravel/pint: ^1.29.3
- misaf/vendra-testing: 1.x-dev
- mockery/mockery: ^1.6.12
- nunomaduro/collision: ^8.9.4
- orchestra/testbench: ^11.1
- pestphp/pest: ^5.0
- pestphp/pest-plugin-arch: ^5.0
- pestphp/pest-plugin-laravel: ^5.0
- pestphp/pest-plugin-livewire: ^5.0
- pestphp/pest-plugin-profanity: ^5.0
- pestphp/pest-plugin-type-coverage: ^5.0
- phpstan/extension-installer: ^1.4.3
This package is auto-updated.
Last update: 2026-08-17 00:19:57 UTC
README
The reseller domain and the reseller self-service panel for Laravel. A reseller is the billing owner of one or more properties: it holds the subscription, the plan limits are enforced against it, and its owner manages its properties from its own Filament panel.
A reseller spans several tenants, so the panel runs outside the tenant middleware stack. There is no current tenant here; everything is scoped by reseller.
Requirements
- PHP 8.3+
- Laravel 13
- Filament 5
misaf/vendra-property,misaf/vendra-subscription,misaf/vendra-transaction,misaf/vendra-tenant,misaf/vendra-localizationandmisaf/vendra-support
Installation
composer require misaf/vendra-reseller php artisan migrate
The resellers and reseller_users tables and the reseller guard,
reseller_users provider, and reseller_password_reset_tokens broker are
configured by the host application's config/auth.php and migrations.
The panel is served on reseller.<app host>, derived from app.url — nothing
here hard-codes a host.
Usage
Creating a reseller
use Misaf\VendraReseller\Actions\CreateResellerAction; $reseller = app(CreateResellerAction::class)->execute( plan: $plan, username: 'acme', email: 'owner@acme.test', password: $password, );
This creates the reseller, its first panel user (CreateResellerOwnerAction),
and the subscription to the given plan.
Offboarding
use Misaf\VendraReseller\Actions\OffboardResellerAction; app(OffboardResellerAction::class)->execute($reseller, reason: 'Contract ended');
OffboardResellerAction is the only supported removal path. Reseller's
deleting hook throws for a reseller that was never offboarded, and
Events\ResellerOffboarded is the extension point for downstream work.
The subscriber
Models\Reseller implements SubscriptionSubscriber, so plan limits are
answered by misaf/vendra-subscription and property quotas by
Misaf\VendraProperty\Support\PropertyQuota — no limit arithmetic is duplicated
here.
$reseller->isSubscriptionActive(); $reseller->activeSubscription(); $reseller->subscribedPropertyCount(); $reseller->suspendActiveProperties(); $reseller->reactivateSuspendedProperties(); $reseller->allows('feature-key');
Support\TransactionSubscriptionCharger implements the SubscriptionCharger
contract by posting an internal withdrawal against the payer's wallet through
misaf/vendra-transaction.
Subscription reactions
The subscription engine raises only generic lifecycle events. This package turns
them into reseller behaviour, wired in Providers\ResellerServiceProvider:
| Event | Listener |
|---|---|
SubscriptionActivated |
NotifyActivatedSubscriber |
SubscriptionExpiringSoon |
RemindExpiringSubscriber |
SubscriptionGraceExpired |
SuspendSubscriberProperties |
Add a new reaction as a listener here rather than pushing reseller knowledge into the subscription engine, and do not register these listeners again in the host application.
Commands
php artisan vendra-subscription:provision {name} {domain} {username} {email} \
[--reseller=] [--plan=] [--password=] [--if-missing] [--seed]
Provisions a property with its domain, owner user, and role assignment. It calls
Misaf\VendraProperty\Actions\ProvisionPropertyAction — the reseller-specific
part is only which reseller is attached (--reseller), or created and
subscribed (--plan).
Panel
Providers\ResellerPanelServiceProvider registers the panel (guard, broker,
domain, login and registration pages, widgets). Providers\ResellerServiceProvider
registers the console command and the event listeners. The split is deliberate.
Property screens are reused, not copied: the panel's resources extend
misaf/vendra-property's CreatePropertyPage, StorefrontConfigurationFields
and ReplaceDomainAction, supplying the authenticated owner as the reseller.
Resolve the acting reseller with Filament\Concerns\InteractsWithCurrentReseller;
Http\Middleware\AddResellerToRequestJobContext carries it into queued work.
Testing
Build resellers, owners, and subscriptions from the package factories and assert quota and suspension behaviour through the actions. Panel tests must not assume a current tenant.
php artisan test --compact --testsuite=vendra-reseller
License
MIT. See LICENSE.