laravel-soft-delete-trashlisted
Install: claude install-skill Yaz-inc/yazinc-ai-toolkit
# Laravel Soft Delete + Unified Trash
Cross-module recycle bin: soft delete with **who deleted**, unified admin trash page, optional **30-day auto purge**.
## When to use
- Multiple modules need delete with undo
- Super admin manages all trashed records in one place
- Compliance: retention period before permanent delete
## Stack
- Laravel `SoftDeletes` via custom `TracksSoftDeletes` trait
- `TrashController` + `trash:cleanup` command
- Pairs with `laravel-activity-logger` for audit on restore/purge
## TracksSoftDeletes trait
Extends `SoftDeletes` to:
- Set `deleted_by` from `auth()->id()` on soft delete (`saveQuietly`)
- Clear `deleted_by` on restore
- Optional `hasProtectedRelationships()` — block delete if children exist
- Scopes: `expiredTrash($days)`, `withinSafetyPeriod($days)`
- Methods: `getTrashDisplayName()`, `getTrashModuleName()` (override per model)
Template: [templates/TracksSoftDeletes.php.example](../../templates/TracksSoftDeletes.php.example)
## Migration per model
```php
$table->softDeletes();
$table->unsignedBigInteger('deleted_by')->nullable();
$table->foreign('deleted_by')->references('id')->on('users')->nullOnDelete();
```
Model:
```php
use App\Traits\TracksSoftDeletes;
class Item extends Model
{
use TracksSoftDeletes;
}
```
## TrashController pattern
- `$trashableModels` map: slug => Model::class
- `index`: loop `onlyTrashed()->with('deletedByUser')`, compute days until expiry
- `restore($module, $id)`: `$model->restore()`, log via Ac