php artisan boost:add-skill fluttersdk/magic-starter-laravel
Save this content to: .cursor/rules/models.md
# Models & Traits
## Models
- Apply `ConditionallyUsesUuids` trait on every model (runtime UUID/integer PK switching)
- PHPDoc `@property` for every column, `@property-read` for accessors and computed attributes
- Type relations explicitly: `BelongsTo<User, $this>`, `HasMany<Team, $this>`, `BelongsToMany<User, $this>`
- Use `casts()` method (Laravel 11+ syntax), not `$casts` property
- Resolve related models dynamically: `MagicStarter::userModel()` in relation definitions
- BelongsToMany pivot: always chain `->using(MagicStarter::membershipModel())` and `->withPivot('role')`
- No soft deletes in `src/Models` — use `cascadeOnDelete()` on foreign keys instead. The one opt-in exception is the published Team stub (`stubs/models/Team.php`), which uses `SoftDeletes` for the restorable team delete (`Features::restorableTeams()`); the shipped `Team` model must stay free of the trait so a consumer without the `deleted_at` column keeps working
- `$fillable` array for mass assignment, not `$guarded`
## Traits
- Defensive: `method_exists($this, 'method')` before calling methods from other optional traits
- Return typed morphMany/morphTo: `MorphMany<NotificationSetting, $this>`
- HasProfilePhoto: `null` when no photo is stored; the client draws its own initials, never a generated third-party image
- HasNotifications: `prefers()` returns true by default if notification type not in registry
- HasNotifications: `routeNotificationForOneSignal()` returns `['external_id' => ['user_'.$this->getKey()]]` for OneSignal v5 alias targeting; channel driver is `FlutterSdk\MagicStarter\Notifications\Channels\OneSignalChannel`
ConditionallyUsesUuids trait on every model (runtime UUID/integer PK switching)@property for every column, @property-read for accessors and computed attributesBelongsTo<User, $this>, HasMany<Team, $this>, BelongsToMany<User, $this>casts() method (Laravel 11+ syntax), not $casts propertyMagicStarter::userModel() in relation definitions->using(MagicStarter::membershipModel()) and ->withPivot('role')src/Models — use cascadeOnDelete() on foreign keys instead. The one opt-in exception is the published Team stub (stubs/models/Team.php), which uses SoftDeletes for the restorable team delete (Features::restorableTeams()); the shipped Team model must stay free of the trait so a consumer without the deleted_at column keeps working$fillable array for mass assignment, not $guardedmethod_exists($this, 'method') before calling methods from other optional traitsMorphMany<NotificationSetting, $this>null when no photo is stored; the client draws its own initials, never a generated third-party imageprefers() returns true by default if notification type not in registryrouteNotificationForOneSignal() returns ['external_id' => ['user_'.$this->getKey()]] for OneSignal v5 alias targeting; channel driver is FlutterSdk\MagicStarter\Notifications\Channels\OneSignalChannelHow can I help you explore Laravel packages today?