Update existing draft articles instead of erroring on a repeat Micropub post #138

Merged
jonny merged 1 commit from article-update-existing-draft into develop 2026-09-19 18:18:33 +02:00
Owner

Summary

  • ArticleService::create() now looks for an existing article with the same title before inserting: if it finds a draft, it updates that article in place; if it finds an already-published one, it throws (mapped to a 400 by MicropubController) instead of silently colliding.
  • Article's Sluggable config now sets includeTrashed => true as a safety net. Article uses SoftDeletes, and Sluggable's uniqueness check ignores trashed rows by default, so a previously soft-deleted article's title could crash a brand new insert with a raw DB unique-constraint violation rather than getting auto-suffixed.

This is the follow-up to #136: once that fix stopped swallowing exceptions, retrying a stuck "WireGuard" draft post from iA Writer surfaced exactly this - a UniqueConstraintViolationException on articles_titleurl_unique from a pre-existing trashed row with the same title.

Test plan

  • ./vendor/bin/sail test - 380 passed (3 new tests: draft-gets-updated, published-title-conflicts-with-error, trashed-slug-gets-suffixed)
  • ./vendor/bin/pint --test - clean

🤖 Generated with Claude Code

## Summary - `ArticleService::create()` now looks for an existing article with the same title before inserting: if it finds a draft, it updates that article in place; if it finds an already-published one, it throws (mapped to a 400 by `MicropubController`) instead of silently colliding. - `Article`'s Sluggable config now sets `includeTrashed => true` as a safety net. `Article` uses `SoftDeletes`, and `Sluggable`'s uniqueness check ignores trashed rows by default, so a previously soft-deleted article's title could crash a brand new insert with a raw DB unique-constraint violation rather than getting auto-suffixed. This is the follow-up to #136: once that fix stopped swallowing exceptions, retrying a stuck "WireGuard" draft post from iA Writer surfaced exactly this - a `UniqueConstraintViolationException` on `articles_titleurl_unique` from a pre-existing trashed row with the same title. ## Test plan - [x] `./vendor/bin/sail test` - 380 passed (3 new tests: draft-gets-updated, published-title-conflicts-with-error, trashed-slug-gets-suffixed) - [x] `./vendor/bin/pint --test` - clean 🤖 Generated with [Claude Code](https://claude.com/claude-code)
If a Micropub h-entry post's title matches an existing article that's
still a draft, update that article in place rather than trying to
insert a duplicate. If it matches one that's already published,
reject the request with a clear error instead of silently colliding.

Also set includeTrashed on Article's slug config as a safety net: this
model soft-deletes, and Sluggable's uniqueness check ignores trashed
rows by default, so a previously-deleted article's title could crash
new inserts with a raw unique constraint violation (this is exactly
what surfaced in Flare as a UniqueConstraintViolationException on
articles_titleurl_unique once the prior swallowed-exception fix
shipped).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
jonny merged commit eb35a0aa2d into develop 2026-09-19 18:18:33 +02:00
jonny deleted branch article-update-existing-draft 2026-09-19 18:18:33 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jonny/jonnybarnes.uk!138
No description provided.