Skip to content

fix: allow reusing a soft-deleted event's name - #215

Merged
morcen merged 1 commit into
mainfrom
fix/issue-83-soft-deleted-event-name-reuse
Sep 5, 2026
Merged

fix: allow reusing a soft-deleted event's name#215
morcen merged 1 commit into
mainfrom
fix/issue-83-soft-deleted-event-name-reuse

Conversation

@morcen

@morcen morcen commented Sep 4, 2026

Copy link
Copy Markdown
Owner

What was broken

Event uses SoftDeletes, and the events table has a plain (non-partial) unique index on (user_id, name). That index, and the Rule::unique('events', 'name') validation backing it in both the web and API EventControllers, did not exclude soft-deleted rows.

Repro: create an event named order.created → soft-delete it → try to create a new event named order.created again → rejected as "has already been taken," permanently — even though the original event no longer appears anywhere in the UI or API and there is no restore path in the app. For a resource that's literally named by the user (order.created, user.signup, etc.), this is a real, permanent dead end with no workaround short of picking a different name forever.

What changed

  • Added a migration that drops the plain unique index on events(user_id, name) and replaces it with a partial unique index (WHERE deleted_at IS NULL), so the DB-level constraint only applies to non-deleted rows. This raw-SQL syntax is supported identically by SQLite (used in tests) and PostgreSQL (production), so no driver branching is needed.
  • Added ->withoutTrashed() to the name uniqueness validation rule in app/Http/Controllers/EventController.php (web store/update) and app/Http/Controllers/Api/EventController.php (API store/update), so validation now matches the new DB constraint instead of rejecting a request the database would otherwise accept.
  • Added tests/Feature/SoftDeletedEventNameReuseTest.php covering:
    • reusing a soft-deleted event's name on create (web + API)
    • renaming an existing event to a soft-deleted event's name (web)
    • the original behavior is preserved: a name still in use by a non-deleted event remains rejected (web + API)

Testing

Fixes #83

🤖 Generated with Claude Code


Generated by Claude Code

Event names were permanently unreusable once soft-deleted: the DB-level
unique index on (user_id, name) and the validation rules backing it
both ignored deleted_at, so recreating an event with a previously
deleted name was rejected forever even though the app has no restore
path and the old event is invisible everywhere.

- Scope the events unique index to non-deleted rows via a partial
  index (portable across SQLite and PostgreSQL).
- Add withoutTrashed() to the name uniqueness validation in both the
  web and API EventControllers so validation matches the new
  constraint.

Fixes #83

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E1dCNHSzn1JyxZbZ147TJw
@morcen
morcen merged commit 47c2d7f into main Sep 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Soft-deleted Event names permanently block reuse due to an unscoped unique constraint/validation

1 participant