Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message
vendra-affiliate-development
vendra-affiliate-development
misaf/vendra
claude-code
vendra-affiliate
translatable-persistence
tenant-registry
affiliate-settings
filament
pest-testing

Create, modify, review, or test the Vendra Affiliate package in packages/vendra-affiliate. Use for Affiliate, AffiliateClick, AffiliateCommission, AffiliatePayout, AffiliateReferral, referral tracking, commissions and payouts, actions, services, events, HTTP endpoints, policies, Filament resources, configuration, translations, and package wiring.

Install
php artisan boost:add-skill misaf/vendra

Save this content to: .claude/skills/vendra-affiliate-development/SKILL.md

# Vendra Affiliate

## Workflow

- Inspect `composer.json`, sibling files, and existing tests before changing the package.
- Use Laravel Boost `application-info` and `search-docs` before code changes.
- Apply `laravel-best-practices` to Laravel PHP and `pest-testing` whenever tests change.
- Apply `tailwindcss-development` only when changing Blade markup or Tailwind classes.
- Keep changes inside this package's boundary and preserve its public contracts.
- Add or update focused Pest coverage, then run `php artisan test --compact --testsuite=vendra-affiliate` and `composer stan`.

## Translatable Persistence

- Making a persisted model field translatable is an explicit domain choice unless this package already requires it.
- Every field listed in a model's `$translatable` array must definitely use a JSON database column. Keep its model traits/casts, factories, validation, Filament locale UI, API serialization, and tests translation-aware.
- A field not listed in `$translatable` must use the appropriate scalar database type and must not use Spatie Translatable, translatable slug traits, locale switchers, translated callbacks, or translation-shaped array data.

## Vendra Transitive API Policy

- Treat a Vendra dependency intentionally exposed through the public API of a directly required Vendra platform package as part of the supported public contract of that package.
- Do not add a redundant direct Composer requirement solely because source code imports a type from that exposed dependency.
- Apply this only to Vendra platform packages listed under `require`; never extend it to `require-dev`, `suggest`, incidental implementation dependencies, or third-party packages. Removing or replacing an exposed dependency is a breaking change; keep `self.version` alignment across the Vendra package graph.

- Register every table whose migration calls `TenantSchema::addTenantColumn()` with `TenantTableRegistry` in this package's service provider, preserving configured table names and connections, so `vendra-tenant:enable {tenant}` can retrofit schemas migrated before tenancy was enabled.
- Store rules a store administrator may change (the default commission percent and signup bounty, which conversions earn commission, commission auto-approval, the referral cookie lifetime and redirect URL, and the payout minimum) live in `Settings\AffiliateSettings` (group `affiliate`, tenant repository), registered with `RegistersSettings` in the service provider and seeded as the platform default by `database/settings`. `Filament\Pages\ManageAffiliateSettings` edits them in the admin System cluster; read them with `resolve(AffiliateSettings::class)`, never from config. The class implements `ShouldLogActivity`, so each change is logged with its old and new values.

## Module Boundary

Treat `packages/vendra-affiliate` as the source of affiliate domain behavior and Filament admin UI.

- Use namespace `Misaf\VendraAffiliate`.
- Keep domain models, factories, seeders, policies, observers, console commands, Filament classes, config, migrations, translations, and tests inside this module.
- Do not place affiliate domain code in the host app unless the host app is only integrating the module.
- Keep cross-module dependencies explicit in `composer.json`; do not introduce a dependency without approval.
- Tag-consuming models must use `Misaf\VendraSupport\Capabilities\HasOptionalTags` as the single source of their `tags()` relationship and pivot metadata. Keep the package tag-agnostic: define a stable package-owned tag type, use `TagIntegration` for availability and UI integration, never import the concrete Vendra Tagger model/provider or define the relationship through Spatie `HasTags`, and list Tagger only under Composer `suggest`.

## Domain Model Standards

Follow the existing affiliate, click, commission, payout, and referral models for domain behavior; do not invent a parallel affiliate-user model.

- Use `declare(strict_types=1)`, final classes, typed method signatures, and PHPDoc generics for relationships.
- Follow Laravel comment style: document with PHPDoc (array shapes, generics, `@see`) and reserve inline comments for genuinely complex logic. Match the surrounding file's density and do not add comments that restate the code.
- Prefer only the Laravel attributes already used by the affected sibling model; do not add model attributes merely because another package uses them.
- Keep the module tenant-agnostic: derive tenant awareness purely from the bound `TenantResolver` in `misaf/vendra-support` (`TenantAwareness`, `BelongsToTenant`, `TenantSchema`, `RequiresCurrentTenant`). The module must build and run whether or not a tenant provider is installed, so never reference a concrete provider such as `Misaf\VendraTenant` anywhere — models, migrations, factories, seeders, or fixtures. There is no `tenant_aware` config toggle.
- Hide `tenant_id` and keep tenant behavior centralized in the support layer; do not duplicate tenant scoping or `tenant_id` assignment in models, Filament resources, factories, or seeders. `BelongsToTenant` assigns `tenant_id` on `creating` from the current tenant.
- Reuse only the traits and conventions present on the affected sibling model; do not infer translations, media, slugs, sorting, or soft deletes from another package.
- Keep `ProcessAffiliatePayoutAction` atomic: consuming commissions, creating the payout, and creating **and approving** the Commission transaction (which settles the affiliate's wallet through the transaction module's ledger) happen in one database transaction. A payout becomes `Completed` only after its transaction is approved; on failure everything rolls back and the commissions stay `Approved` and payable. The missing-user branch records a `Failed` payout without consuming commissions.
- `TransactionCommissionSubscriber` credits deposit commissions idempotently from `TransactionApproved` for referred users' deposits; it must stay `ShouldQueueAfterCommit`, react only to Deposit-type transactions, skip platform-ledger (tenantless) transactions in `shouldQueue()` since they belong to no store and a tenant-aware job cannot run without a tenant, and never subscribe to generic `eloquent.updated` model events. Approval is final, so it reverses nothing.
- Look up a referred user's referrer with `AffiliateReferral::forUser()` (affiliate eager-loaded); conversions skip a referral whose affiliate is deleted. Never repeat the referral query inline.

## Filament Standards

Keep every resource that declares a `$cluster`, including its complete supporting tree, under `src/Filament/Clusters/Resources/` with the matching `Misaf\VendraAffiliate\Filament\Clusters\Resources` namespace and plugin discovery path. Resources without a cluster belong under `src/Filament/Resources/`.

- Register module UI through the module `Plugin` and `ServiceProvider`; do not manually wire resources in unrelated panel providers.
- Keep resource classes thin. Delegate form schemas to `Schemas/*Form.php` and table configuration to `Tables/*Table.php`.
- Use Filament v5 namespaces: form fields from `Filament\Forms\Components`, layout from `Filament\Schemas\Components`, table columns from `Filament\Tables\Columns`, filters from `Filament\Tables\Filters`, actions from `Filament\Actions`, and icons from `Filament\Support\Icons\Heroicon`.
- Use this module's translation keys (`vendra-affiliate::attributes`, `vendra-affiliate::navigation`) for labels, breadcrumbs, and navigation.
- Keep cluster resources ungrouped and assign `$navigationSort` from their package-specific `NavigationPriority` cases; never hardcode numeric resource sort values.
- Provide separate singular and plural resource labels in `en`, `de`, and `fa`: model labels use the singular key, while navigation and plural model labels use the plural key. Keep navigation labels at 24 characters or fewer.
- Prevent N+1 issues in tables and relation managers with eager loading, `withCount`, or computed state based on loaded relationships.
- Use public media visibility only when public access is actually required.

## Permissions And Navigation

Use policy enums and policies as the permission source.

- Add enum cases for every resource action the panel exposes.
- Keep policy method names aligned with Filament actions: `viewAny`, `view`, `create`, `update`, `delete`, `deleteAny`, `restore`, `restoreAny`, `forceDelete`, `forceDeleteAny`, `replicate`, and `reorder` as applicable.
- Update `PermissionPolicySeeder` when new permissions are introduced.
- Keep navigation labels and groups configurable through the module `Plugin` and `config/vendra-affiliate.php`. Do not add a `tenant_aware` config value; tenant awareness derives from the bound `TenantResolver`.

## Data And Localization

Migrations, factories, seeders, and translation files are part of the contract.

- Use package migrations in `database/migrations`, with stubs only when the install flow expects publishing.
- Use factories under `database/factories` and seeders under `database/seeders`. Keep them tenant-safe: import no concrete tenant provider and set no `tenant_id` directly; let `BelongsToTenant` assign it from the current tenant so they work with tenancy on or off.
- Keep demo fixtures deterministic and tenant-safe.
- Update all supported locales together and keep translation keys sorted.
- Preserve translation key parity tests when adding labels or attributes.

## Testing And Verification

Prefer focused Pest tests in the module.

- Keep tests purposeful and prevent unnecessary ones: cover behavior, contracts, and edge cases — not framework internals or trivially typed code. Do not duplicate coverage a focused test already proves, and do not add throwaway verification scripts (or `tinker`) when a test fits.
- Keep architecture coverage proving the module does not use Vendra Tagger or Spatie Tags directly, and test the typed relationship through the Support resolver.
- Add or update unit tests for model contracts, policy permission coverage, resolver-derived tenant awareness, navigation/config behavior, and translation parity.
- Keep Pest architecture tests in `tests/ArchTest.php`: the `php`, `security`, and `laravel` presets, plus an expectation that the module stays tenant-agnostic, e.g. `arch()->expect('Misaf\VendraAffiliate')->not->toUse('Misaf\VendraTenant')`.
- Add feature or Livewire tests when changing Filament behavior with meaningful user-visible effects.
- Run checks from the host app: `php artisan test --compact --testsuite=vendra-affiliate` and `composer stan`.
- If PHP files changed, run Pint for the touched code: `vendor/bin/pint --dirty --format agent` from the host app.

- Demo seeders declare their factory dependencies in `FACTORIES`; the shared base uses bundled fixtures when any declared factory is unavailable, including standalone Composer installs. Keep factories in development autoloading.

Vendra Affiliate

Workflow

  • Inspect composer.json, sibling files, and existing tests before changing the package.
  • Use Laravel Boost application-info and search-docs before code changes.
  • Apply laravel-best-practices to Laravel PHP and pest-testing whenever tests change.
  • Apply tailwindcss-development only when changing Blade markup or Tailwind classes.
  • Keep changes inside this package's boundary and preserve its public contracts.
  • Add or update focused Pest coverage, then run php artisan test --compact --testsuite=vendra-affiliate and composer stan.

Translatable Persistence

  • Making a persisted model field translatable is an explicit domain choice unless this package already requires it.
  • Every field listed in a model's $translatable array must definitely use a JSON database column. Keep its model traits/casts, factories, validation, Filament locale UI, API serialization, and tests translation-aware.
  • A field not listed in $translatable must use the appropriate scalar database type and must not use Spatie Translatable, translatable slug traits, locale switchers, translated callbacks, or translation-shaped array data.

Vendra Transitive API Policy

  • Treat a Vendra dependency intentionally exposed through the public API of a directly required Vendra platform package as part of the supported public contract of that package.

  • Do not add a redundant direct Composer requirement solely because source code imports a type from that exposed dependency.

  • Apply this only to Vendra platform packages listed under require; never extend it to require-dev, suggest, incidental implementation dependencies, or third-party packages. Removing or replacing an exposed dependency is a breaking change; keep self.version alignment across the Vendra package graph.

  • Register every table whose migration calls TenantSchema::addTenantColumn() with TenantTableRegistry in this package's service provider, preserving configured table names and connections, so vendra-tenant:enable {tenant} can retrofit schemas migrated before tenancy was enabled.

  • Store rules a store administrator may change (the default commission percent and signup bounty, which conversions earn commission, commission auto-approval, the referral cookie lifetime and redirect URL, and the payout minimum) live in Settings\AffiliateSettings (group affiliate, tenant repository), registered with RegistersSettings in the service provider and seeded as the platform default by database/settings. Filament\Pages\ManageAffiliateSettings edits them in the admin System cluster; read them with resolve(AffiliateSettings::class), never from config. The class implements ShouldLogActivity, so each change is logged with its old and new values.

Module Boundary

Treat packages/vendra-affiliate as the source of affiliate domain behavior and Filament admin UI.

  • Use namespace Misaf\VendraAffiliate.
  • Keep domain models, factories, seeders, policies, observers, console commands, Filament classes, config, migrations, translations, and tests inside this module.
  • Do not place affiliate domain code in the host app unless the host app is only integrating the module.
  • Keep cross-module dependencies explicit in composer.json; do not introduce a dependency without approval.
  • Tag-consuming models must use Misaf\VendraSupport\Capabilities\HasOptionalTags as the single source of their tags() relationship and pivot metadata. Keep the package tag-agnostic: define a stable package-owned tag type, use TagIntegration for availability and UI integration, never import the concrete Vendra Tagger model/provider or define the relationship through Spatie HasTags, and list Tagger only under Composer suggest.

Domain Model Standards

Follow the existing affiliate, click, commission, payout, and referral models for domain behavior; do not invent a parallel affiliate-user model.

  • Use declare(strict_types=1), final classes, typed method signatures, and PHPDoc generics for relationships.
  • Follow Laravel comment style: document with PHPDoc (array shapes, generics, @see) and reserve inline comments for genuinely complex logic. Match the surrounding file's density and do not add comments that restate the code.
  • Prefer only the Laravel attributes already used by the affected sibling model; do not add model attributes merely because another package uses them.
  • Keep the module tenant-agnostic: derive tenant awareness purely from the bound TenantResolver in misaf/vendra-support (TenantAwareness, BelongsToTenant, TenantSchema, RequiresCurrentTenant). The module must build and run whether or not a tenant provider is installed, so never reference a concrete provider such as Misaf\VendraTenant anywhere — models, migrations, factories, seeders, or fixtures. There is no tenant_aware config toggle.
  • Hide tenant_id and keep tenant behavior centralized in the support layer; do not duplicate tenant scoping or tenant_id assignment in models, Filament resources, factories, or seeders. BelongsToTenant assigns tenant_id on creating from the current tenant.
  • Reuse only the traits and conventions present on the affected sibling model; do not infer translations, media, slugs, sorting, or soft deletes from another package.
  • Keep ProcessAffiliatePayoutAction atomic: consuming commissions, creating the payout, and creating and approving the Commission transaction (which settles the affiliate's wallet through the transaction module's ledger) happen in one database transaction. A payout becomes Completed only after its transaction is approved; on failure everything rolls back and the commissions stay Approved and payable. The missing-user branch records a Failed payout without consuming commissions.
  • TransactionCommissionSubscriber credits deposit commissions idempotently from TransactionApproved for referred users' deposits; it must stay ShouldQueueAfterCommit, react only to Deposit-type transactions, skip platform-ledger (tenantless) transactions in shouldQueue() since they belong to no store and a tenant-aware job cannot run without a tenant, and never subscribe to generic eloquent.updated model events. Approval is final, so it reverses nothing.
  • Look up a referred user's referrer with AffiliateReferral::forUser() (affiliate eager-loaded); conversions skip a referral whose affiliate is deleted. Never repeat the referral query inline.

Filament Standards

Keep every resource that declares a $cluster, including its complete supporting tree, under src/Filament/Clusters/Resources/ with the matching Misaf\VendraAffiliate\Filament\Clusters\Resources namespace and plugin discovery path. Resources without a cluster belong under src/Filament/Resources/.

  • Register module UI through the module Plugin and ServiceProvider; do not manually wire resources in unrelated panel providers.
  • Keep resource classes thin. Delegate form schemas to Schemas/*Form.php and table configuration to Tables/*Table.php.
  • Use Filament v5 namespaces: form fields from Filament\Forms\Components, layout from Filament\Schemas\Components, table columns from Filament\Tables\Columns, filters from Filament\Tables\Filters, actions from Filament\Actions, and icons from Filament\Support\Icons\Heroicon.
  • Use this module's translation keys (vendra-affiliate::attributes, vendra-affiliate::navigation) for labels, breadcrumbs, and navigation.
  • Keep cluster resources ungrouped and assign $navigationSort from their package-specific NavigationPriority cases; never hardcode numeric resource sort values.
  • Provide separate singular and plural resource labels in en, de, and fa: model labels use the singular key, while navigation and plural model labels use the plural key. Keep navigation labels at 24 characters or fewer.
  • Prevent N+1 issues in tables and relation managers with eager loading, withCount, or computed state based on loaded relationships.
  • Use public media visibility only when public access is actually required.

Permissions And Navigation

Use policy enums and policies as the permission source.

  • Add enum cases for every resource action the panel exposes.
  • Keep policy method names aligned with Filament actions: viewAny, view, create, update, delete, deleteAny, restore, restoreAny, forceDelete, forceDeleteAny, replicate, and reorder as applicable.
  • Update PermissionPolicySeeder when new permissions are introduced.
  • Keep navigation labels and groups configurable through the module Plugin and config/vendra-affiliate.php. Do not add a tenant_aware config value; tenant awareness derives from the bound TenantResolver.

Data And Localization

Migrations, factories, seeders, and translation files are part of the contract.

  • Use package migrations in database/migrations, with stubs only when the install flow expects publishing.
  • Use factories under database/factories and seeders under database/seeders. Keep them tenant-safe: import no concrete tenant provider and set no tenant_id directly; let BelongsToTenant assign it from the current tenant so they work with tenancy on or off.
  • Keep demo fixtures deterministic and tenant-safe.
  • Update all supported locales together and keep translation keys sorted.
  • Preserve translation key parity tests when adding labels or attributes.

Testing And Verification

Prefer focused Pest tests in the module.

  • Keep tests purposeful and prevent unnecessary ones: cover behavior, contracts, and edge cases — not framework internals or trivially typed code. Do not duplicate coverage a focused test already proves, and do not add throwaway verification scripts (or tinker) when a test fits.

  • Keep architecture coverage proving the module does not use Vendra Tagger or Spatie Tags directly, and test the typed relationship through the Support resolver.

  • Add or update unit tests for model contracts, policy permission coverage, resolver-derived tenant awareness, navigation/config behavior, and translation parity.

  • Keep Pest architecture tests in tests/ArchTest.php: the php, security, and laravel presets, plus an expectation that the module stays tenant-agnostic, e.g. arch()->expect('Misaf\VendraAffiliate')->not->toUse('Misaf\VendraTenant').

  • Add feature or Livewire tests when changing Filament behavior with meaningful user-visible effects.

  • Run checks from the host app: php artisan test --compact --testsuite=vendra-affiliate and composer stan.

  • If PHP files changed, run Pint for the touched code: vendor/bin/pint --dirty --format agent from the host app.

  • Demo seeders declare their factory dependencies in FACTORIES; the shared base uses bundled fixtures when any declared factory is unavailable, including standalone Composer installs. Keep factories in development autoloading.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core