Schválení přes druhou cestu negeneruje slug → profil 404
import { Aside } from ‘@astrojs/starlight/components’;
Symptom
Sekce “Symptom”Admin schválí umělce, klikne na jeho veřejný profil → „Stránka nenalezena” (404). Profil přitom v DB existuje, je approved=true, není smazaný ani blokovaný.
Root cause
Sekce “Root cause”Veřejný profil se routuje na /autor/<url_slug>. Schválený umělec měl url_slug prázdný, takže odkaz vedl na /autor/ (prázdný segment) → žádná shoda routy → 404.
Proč byl slug prázdný: existovaly dvě cesty schvalování, a jen jedna generovala slug.
// Cesta A — dedikovaný approve endpoint (pending-artists POST): slug SE generoval ✓if (!artist.url_slug) { updates.url_slug = await generateUniqueArtistSlug(db, artist);}
// Cesta B — obecný edit uživatele (users PUT): slug se NEgeneroval ✗if (admin_approved !== undefined) { updates.admin_approved = admin_approved; if (admin_approved) { updates.approved_at = new Date().toISOString(); // ... žádné slug-gen → zůstane prázdné }}Admin schválil umělce přes editační formulář (Cesta B, PUT), ne přes dedikované tlačítko „schválit” (Cesta A). Pravidlo „při schválení vygeneruj slug” žilo jen v jedné z obou cest.
Fix
Sekce “Fix”Slug-gen vytáhnout do jednoho sdíleného helperu a zavolat ze všech approve cest:
// lib/slug.ts — jediný zdroj pravdyexport async function generateUniqueArtistSlug(db, p) { const base = slugify(p.pseudonym || `${p.first_name}-${p.last_name}`) || `artist-${p.id.slice(0, 8)}`; let slug = base, suffix = 1; while (true) { const { data } = await db.from('profiles') .select('id').eq('url_slug', slug).neq('id', p.id).limit(1); if (!data?.length) break; slug = `${base}-${++suffix}`; } return slug;}// Cesta B (users PUT) — doplněnoif (admin_approved) { const target = await loadProfile(user_id); if (target?.role === 'artist' && !target.url_slug) { updates.url_slug = await generateUniqueArtistSlug(db, target); }}Cesta A přepsána na stejný helper. Náprava dat: backfill slugů pro už schválené umělce s prázdným url_slug.
Jak se tomu vyvarovat v jiných systémech
Sekce “Jak se tomu vyvarovat v jiných systémech”- Detection: najdi všechny zápisy stavového flagu (
approved = true,status = 'active',published = true) a ověř, že každá cesta dělá i navazující odvozené kroky (slug, počítadla, notifikace). Pokud je odvozený krok jen u jedné, máš drift. - Anti-pattern: stejné netriviální pravidlo zkopírované do druhé cesty (copy-paste), nebo přítomné jen v „hlavní” cestě a chybějící v „edit/admin override” cestě.
- Lepší přístup: (1) jeden sdílený helper volaný ze všech cest; (2) ještě lépe DB trigger /
generated column, pokud jde o čistě datové odvození (slug z jména) — pak je nezávislé na aplikační cestě; (3) test: schval entitu každou cestou a ověř, že odvozená pole (slug) jsou vyplněná.
Sister bugs / související
Sekce “Sister bugs / související”- Změna stavu tiše přepíše vlastníka záznamu — jiný případ, kdy vedlejší efekt na write cestě nebyl konzistentní napříč vstupy.
- Refaktor tiše zahodí funkci — stejná rodina: chování existuje v jedné cestě/verzi a chybí v druhé, bez chyby.