Critical fix
Closes a P0 data-loss vector: foreign keys subscriptions.plan_id, licenses.plan_id, licenses.user_id, and subscription_items.plan_id were declared ON DELETE CASCADE. A single DELETE FROM plans WHERE … (or User::delete()) physically wiped every dependent row — softDeletes traits did NOT protect because InnoDB / SQLite enforce FK actions below Eloquent.
What changed
- New idempotent migration
2026_05_13_090000_fix_cascade_delete_protection.phpswaps the four foreign keys toRESTRICTand addsplans.deleted_at. Planmodel gainsSoftDeletes.$plan->delete()archives;$plan->forceDelete()is blocked by the new FKs while dependents exist.Subscription::plan(),License::plan(),SubscriptionItem::plan()chain->withTrashed()so historical billing keeps resolving archived plans.
BREAKING
User::delete() no longer cascades to licenses. Apps that relied on a hard user-delete to clean up licenses now receive QueryException from the new RESTRICT constraint. Cancel/archive the licenses first. Full rationale in CHANGELOG.md v1.3.0 BREAKING section.
Upgrade
```bash
composer update fzengin19/laravel-subscription-guard
php artisan migrate
```
Tests
282 passed / 932 assertions. PHPStan level 5 clean. CI matrix green across PHP 8.3/8.4 × Laravel 11/12/13 × Ubuntu/Windows.
See CHANGELOG.md and docs/plans/2026-05-13-cascade-delete-protection-plan.md for full detail.