Skip to content

1760 cms save content before creating slug-change redirect#1774

Open
MrDirkelz wants to merge 3 commits into
mainfrom
1760-cms-auto-redirect-on-slug-change-of-a-published-post-is-rejected-published-content-already-exists-for-slug
Open

1760 cms save content before creating slug-change redirect#1774
MrDirkelz wants to merge 3 commits into
mainfrom
1760-cms-auto-redirect-on-slug-change-of-a-published-post-is-rejected-published-content-already-exists-for-slug

Conversation

@MrDirkelz

Copy link
Copy Markdown
Collaborator

Renaming a published post's slug produced a redirect the API rejected ("Published content already exists for slug"): the redirect change request reached the API before the content slug-change, so the old slug was still occupied by published content.

Build the redirects from pre-save state, save the content first (vacating the old slug), then queue the redirects claiming it. The sequential FIFO localChanges drain guarantees the content commits before the redirect is sent.

Renaming a published post's slug produced a redirect the API rejected
("Published content already exists for slug"): the redirect change
request reached the API before the content slug-change, so the old slug
was still occupied by published content.

Build the redirects from pre-save state, save the content first (vacating
the old slug), then queue the redirects claiming it. The sequential FIFO
localChanges drain guarantees the content commits before the redirect is
sent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ivanslabbert

Copy link
Copy Markdown
Contributor

would it not be safer to create the redirect in the API? We are relying on the CMS to add the redirect, but in principle we cannot trust a client to handle mission critical operations.

toEditable.save() returns an optimistic local ack before the server
validates the change, so a lost slug-uniqueness race showed a false
"Redirect created" toast and closed the modal, only reporting failure
later via an unrelated generic toast. Wait for the queued localChanges
entry to drain (falling back to the old optimistic behavior offline)
and re-check the doc in Dexie before declaring success.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Comment on lines +4 to +28
// ponytail: works around toEditable.save()'s optimistic-only ack (shared/ is currently
// locked to the senior) by watching the localChanges queue drain instead. Delete this once
// toEditable exposes a real awaitAck option.
export async function awaitLocalChangeResolution(
docId: Uuid,
timeoutMs = 8000,
): Promise<"resolved" | "pending"> {
if (!isConnected.value) return "pending";
return new Promise((resolve) => {
const scope = effectScope(true);
const timer = setTimeout(() => finish("pending"), timeoutMs);
function finish(result: "resolved" | "pending") {
clearTimeout(timer);
scope.stop();
resolve(result);
}
scope.run(() => {
const count = useDexieLiveQuery(() => db.localChanges.where({ docId }).count(), {
initialValue: undefined as number | undefined,
});
watch(count, (n) => n === 0 && finish("resolved"), { immediate: true });
watch(isConnected, (online) => !online && finish("pending"));
});
});
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tthis is done in the wrong place

Create auto-redirects in the API after published content slug changes, return ack info for CMS confirmations, and remove CMS-side redirect queuing.
@MrDirkelz MrDirkelz self-assigned this Jul 7, 2026
@johan-bell

Copy link
Copy Markdown
Collaborator

purge() clears this.localChanges directly but doesn't resolve any pending localChangeAckWaiters. Since Redirect docs go through the local-queue path (they're always "in window" per isSyncable.ts), CreateOrEditRedirectModal.vue's saveRedirect(..., { awaitAck: true }) / removeRedirect(..., { awaitAck: true }) calls resolve via waitForLocalChangeAck. If a user saves a redirect while offline and then purges local data (Settings) before the change is ever acked, that save()/remove() call hangs forever — same failure mode the overwriteLocalChanges branch was fixed to avoid, just via a different path to losing the queued entry. Might be worth resolving (or rejecting) any outstanding waiters in purge() too, e.g. with the same synthetic-ack pattern used for overwriteLocalChanges.

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.

CMS: Auto-redirect on slug change of a published post is rejected ("Published content already exists for slug")

3 participants