Přeskočit na obsah

Klient drží id konceptu, který mezitím odeslal cron — každý další save/send končí 404

import { Aside } from ‘@astrojs/starlight/components’;

Uživatel klikne v e-mailovém klientovi na Odeslat a dostane „Chyba při odeslání e-mailu”. Každý další pokus selže stejně — „vůbec nejde odeslat”. V serverovém error logu nic; v access logu reverse proxy série identických 404 na endpoint konceptů, pár sekund po sobě (autosave + opakované kliky).

Odeslání je řešené jako „undo send”: klik na Odeslat koncept jen naplánuje (scheduledAt = now + 12 s) a minutový cron ho odešle — záznam tím přestane být konceptem (isDraft = false). Race:

  1. Seznam složek se ale neobnovuje průběžně, takže odeslaný koncept zůstal viditelný ve složce Naplánované/Koncepty.
  2. Klik na tento „duchový” řádek otevřel compose s draftIdRef = <staré id> — a dřívější confirm-flow výsledek požadavku na zrušení plánu vůbec nekontroloval (fetch(...).catch(() => {})).
  3. Server na update konceptu správně vrací 404 Koncept nenalezen. (záznam už není isDraft), jenže:
    • autosave 404 tiše polykal a zkoušel to samé id donekonečna,
    • Odeslat ukázal jen generickou hlášku bez data.error — skutečný důvod nebyl vidět.

Tři vrstvy:

// 1) Recovery: mrtvé id zahodit a založit nový koncept (obsah okna = zdroj pravdy)
let res = await postDraft(payloadWithId);
if (res.status === 404 && draftIdRef.current) {
draftIdRef.current = null;
res = await postDraft(payloadWithoutId);
}
// 2) Detail ze serveru vždy do UI
const json = await res.json().catch(() => null);
if (!res.ok) toast.error(json?.error ? `Chyba při odeslání: ${json.error}` : "Chyba při odeslání.");
  1. Zavřít vstupní cesty do „duchového” stavu: před otevřením konceptu k editaci ověřit jeho stav na serveru (GET /:id → když už není koncept, jen obnovit seznam); akce „zrušit plán” kontroluje res.ok a při chybě ukáže serverový důvod; refetch seznamu je stale-while-revalidate, aby stav složek neujížděl.

Jak to příště odhalit dřív

Sekce “Jak to příště odhalit dřív”
  • Access log reverse proxy (status kódy + časové rozestupy) prozradí smyčku 404 i tam, kde aplikační log mlčí — 4xx se běžně neloguje jako error.
  • Integrační test na „stale id”: vytvořit záznam s isDraft=false a POSTnout update s jeho id — musí vrátit 404 s čitelným error.
  • Pravidlo pro UI: žádný toast.error("Obecná chyba") bez pokusu přečíst data.error z odpovědi.
Přidal aiarchitekt.cz · 10. 7. 2026 2:00
Provozuje aiarchitekt.cz