fix(01): revise plans based on checker feedback

- Fix CSV-01 column count: 32 -> 33 (8 meta + 24 slide + 1 caption)
- Add TopicResult Pydantic model + topic_generator.txt prompt
- Make bulk generation async with background task + polling endpoint
- Add POST /api/export/{job_id}/csv for inline edit CSV download
- Split Plan 01-04 Task 2 into 2a/2b/2c (badges, slideviewer, pages)
- Update ProgressIndicator to use polling on /status endpoint
- Add --yes flag and frontend/ prerequisite note to Plan 01-01

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Michele
2026-03-08 01:40:30 +01:00
parent 3f1dbbf396
commit 696b265e4d
5 changed files with 194 additions and 82 deletions

View File

@@ -26,10 +26,10 @@ autonomous: false
must_haves:
truths:
- "L'utente vede una Dashboard con link a Genera Calendario, Genera Singolo Post, e Impostazioni"
- "L'utente compila il form Genera Calendario (obiettivo + settimane) e clicca Genera — vede progress indicator per ogni post"
- "L'utente compila il form Genera Calendario (obiettivo + settimane) e clicca Genera — vede progress indicator che si aggiorna in tempo reale tramite polling ogni 2s su /api/generate/job/{job_id}/status"
- "L'utente vede i 13 post generati come griglia di card con badge colorati PN e Schwartz"
- "L'utente clicca su una card e vede le slide con navigazione frecce laterali + caption Instagram"
- "L'utente puo' modificare il testo di una slide inline (click to edit) e le modifiche si riflettono nel CSV"
- "L'utente puo' modificare il testo di una slide inline (click to edit) e le modifiche si riflettono nel CSV scaricato tramite POST /api/export/{job_id}/csv"
- "L'utente scarica il CSV cliccando un pulsante Download CSV"
- "Post falliti appaiono come card errore con pulsante Riprova"
- "Il pulsante Genera e' disabilitato se API key non configurata, con messaggio che rimanda a Impostazioni"
@@ -63,8 +63,16 @@ must_haves:
pattern: "apiFetch"
- from: "frontend/src/pages/GenerateCalendar.tsx"
to: "frontend/src/api/hooks.ts"
via: "useMutation per POST /api/generate/bulk"
pattern: "useMutation"
via: "useMutation per POST /api/generate/bulk (async, ritorna job_id)"
pattern: "useGenerateCalendar"
- from: "frontend/src/components/ProgressIndicator.tsx"
to: "frontend/src/api/hooks.ts"
via: "useJobStatus(jobId) polling ogni 2s su GET /api/generate/job/{job_id}/status"
pattern: "useJobStatus"
- from: "frontend/src/pages/OutputReview.tsx"
to: "frontend/src/api/hooks.ts"
via: "useDownloadEditedCsv per POST /api/export/{job_id}/csv con edits inline"
pattern: "useDownloadEditedCsv"
- from: "frontend/src/pages/OutputReview.tsx"
to: "frontend/src/components/PostCard.tsx"
via: "Render griglia di PostCard"
@@ -116,6 +124,7 @@ Output: SPA React completa con tutte le pagine e componenti per il workflow: con
1. Creare frontend/src/types.ts con i tipi TypeScript che rispecchiano gli schemas Pydantic del backend:
- CalendarSlot, CalendarRequest, CalendarResponse
- SlideContent, GeneratedPost, PostResult, GenerateResponse
- JobStatus (job_id: string, status: "running" | "completed" | "failed", total: number, completed: number, current_post: number, results: PostResult[])
- Settings (api_key, llm_model, nicchie_attive, lingua, frequenza_post, brand_name, tono)
- SettingsStatus (api_key_configured: boolean, llm_model: string)
@@ -127,10 +136,12 @@ Output: SPA React completa con tutte le pagine e componenti per il workflow: con
- useSettings(): useQuery per GET /api/settings
- useSettingsStatus(): useQuery per GET /api/settings/status
- useUpdateSettings(): useMutation per PUT /api/settings
- useGenerateCalendar(): useMutation per POST /api/generate/bulk — ritorna GenerateResponse
- useGenerateCalendar(): useMutation per POST /api/generate/bulk — ritorna {job_id} (async, NON GenerateResponse)
- useGenerateSingle(): useMutation per POST /api/generate/single
- useJobStatus(jobId): useQuery per GET /api/generate/job/{jobId}/status con refetchInterval condizionale (2000ms quando running, disabilitato quando completed/failed)
- useJobResults(jobId): useQuery per GET /api/generate/job/{jobId}
- useDownloadCsv(): funzione che chiama apiDownload e triggera download browser
- useDownloadCsv(): funzione che chiama GET /api/export/{jobId}/csv e triggera download browser (CSV originale)
- useDownloadEditedCsv(): funzione che chiama POST /api/export/{jobId}/csv con results modificati e triggera download browser (CSV con edits)
- useFormats(): useQuery per GET /api/calendar/formats
4. Creare frontend/src/components/Layout.tsx:
@@ -172,8 +183,8 @@ Output: SPA React completa con tutte le pagine e componenti per il workflow: con
</action>
<verify>
- frontend/src/App.tsx ha BrowserRouter con basename="/postgenerator"
- frontend/src/api/hooks.ts ha almeno 7 hooks (settings, settingsStatus, updateSettings, generateCalendar, generateSingle, jobResults, downloadCsv)
- frontend/src/types.ts ha CalendarSlot, GeneratedPost, PostResult, Settings
- frontend/src/api/hooks.ts ha almeno 10 hooks/functions (settings, settingsStatus, updateSettings, generateCalendar, generateSingle, jobStatus, jobResults, downloadCsv, downloadEditedCsv, formats)
- frontend/src/types.ts ha CalendarSlot, GeneratedPost, PostResult, JobStatus, Settings
- Sidebar ha 4 link di navigazione
- Settings ha campo API key con tipo password
- Dashboard mostra banner se API key non configurata
@@ -185,16 +196,11 @@ Output: SPA React completa con tutte le pagine e componenti per il workflow: con
</task>
<task type="auto">
<name>Task 2: Genera Calendario, Output Review con card/slide/edit, Genera Singolo Post</name>
<name>Task 2a: Badge components e PostCard</name>
<files>
frontend/src/pages/GenerateCalendar.tsx
frontend/src/pages/GenerateSingle.tsx
frontend/src/pages/OutputReview.tsx
frontend/src/components/PostCard.tsx
frontend/src/components/SlideViewer.tsx
frontend/src/components/ProgressIndicator.tsx
frontend/src/components/BadgePN.tsx
frontend/src/components/BadgeSchwartz.tsx
frontend/src/components/PostCard.tsx
</files>
<action>
1. Creare frontend/src/components/BadgePN.tsx:
@@ -207,30 +213,78 @@ Output: SPA React completa con tutte le pagine e componenti per il workflow: con
- Colori progressivi (L5 chiaro -> L1 scuro) per indicare vicinanza all'acquisto
- Tooltip con descrizione livello
3. Creare frontend/src/components/ProgressIndicator.tsx:
- Mostra progresso generazione bulk: "Post 3/13 in generazione..."
- Barra di progresso visuale
- Lista dei post con stato: pending (grigio), processing (spinner), success (verde check), failed (rosso X)
- Animazione per il post attualmente in generazione
4. Creare frontend/src/components/PostCard.tsx:
3. Creare frontend/src/components/PostCard.tsx:
- Card per singolo post nel risultato
- Mostra: indice, tipo PN (badge), livello Schwartz (badge), formato narrativo, nicchia, data
- Se status=success: mostra cover_title come titolo card, click per espandere
- Se status=failed: card con sfondo rosso chiaro, icona errore, messaggio errore, pulsante "Riprova"
- Pulsante Riprova chiama useGenerateSingle() per rigenerare quel slot
- Click su card success -> espande per mostrare SlideViewer
- Click su card success -> espande per mostrare SlideViewer (SlideViewer placeholder prop per ora)
</action>
<verify>
- BadgePN.tsx ha 6 colori distinti per i tipi PN
- BadgeSchwartz.tsx ha 5 livelli con tooltip
- PostCard.tsx ha stati distinti per success e failed, con pulsante Riprova
- npm run build completa senza errori TypeScript
</verify>
<done>
Badge PN e Schwartz con colori distinti. PostCard con stati success/failed, badge, e placeholder per SlideViewer expansion.
</done>
</task>
5. Creare frontend/src/components/SlideViewer.tsx:
<task type="auto">
<name>Task 2b: SlideViewer con inline edit e ProgressIndicator con polling</name>
<files>
frontend/src/components/SlideViewer.tsx
frontend/src/components/ProgressIndicator.tsx
frontend/src/api/hooks.ts
</files>
<action>
1. Creare frontend/src/components/SlideViewer.tsx:
- Visualizzazione slide-by-slide con navigazione frecce laterali (stile Instagram stories)
- Mostra: slide corrente N/8, headline, body, image_keyword
- Freccia sinistra/destra per navigare
- Ogni campo testo e' EDITABILE inline: click per trasformare in input/textarea
- Le modifiche aggiornano lo stato locale (PostResult) che verra' usato per il CSV download
- Le modifiche aggiornano lo stato locale (PostResult) tramite callback onEdit prop
- Sotto le slide: caption Instagram in textarea editabile
- Keyboard navigation: frecce sinistra/destra per cambiare slide
6. Creare frontend/src/pages/GenerateCalendar.tsx:
2. Creare frontend/src/components/ProgressIndicator.tsx:
- Riceve job_id come prop
- USA POLLING: chiama GET /api/generate/job/{job_id}/status ogni 2 secondi via useJobStatus(jobId) hook
- Mostra progresso generazione bulk: "Post {completed}/{total} in generazione..."
- Barra di progresso visuale basata su completed/total dal polling response
- Lista dei post con stato: pending (grigio), processing (spinner — il current_post), success (verde check), failed (rosso X)
- Animazione per il post attualmente in generazione (current_post dal polling)
- Quando status diventa "completed": smette di pollare, chiama callback onComplete(jobId)
3. Aggiornare frontend/src/api/hooks.ts:
- Aggiungere useJobStatus(jobId): useQuery per GET /api/generate/job/{jobId}/status con refetchInterval di 2000ms quando status e' "running", disabilitato quando "completed" o "failed"
- Aggiungere useDownloadEditedCsv(): funzione che chiama POST /api/export/{jobId}/csv con i results modificati e triggera download browser
- Aggiornare useGenerateCalendar(): mutation che chiama POST /api/generate/bulk e ritorna {job_id} (non GenerateResponse, dato che ora e' async)
</action>
<verify>
- SlideViewer.tsx ha navigazione frecce e campi editabili inline con callback onEdit
- ProgressIndicator.tsx usa useJobStatus() hook con polling ogni 2 secondi
- ProgressIndicator.tsx smette di pollare quando status != "running"
- hooks.ts ha useJobStatus con refetchInterval condizionale
- hooks.ts ha useDownloadEditedCsv che chiama POST endpoint
- npm run build completa senza errori TypeScript
</verify>
<done>
SlideViewer con navigazione slide e edit inline via callback. ProgressIndicator usa polling real-time su /status endpoint per mostrare progresso per-item. API hooks aggiornati per async generation pattern (job_id + polling + POST CSV con edits).
</done>
</task>
<task type="auto">
<name>Task 2c: Pagine GenerateCalendar, OutputReview, GenerateSingle</name>
<files>
frontend/src/pages/GenerateCalendar.tsx
frontend/src/pages/GenerateSingle.tsx
frontend/src/pages/OutputReview.tsx
</files>
<action>
1. Creare frontend/src/pages/GenerateCalendar.tsx:
- Form con campi:
- Obiettivo campagna (textarea, obbligatorio, placeholder "Es: Aumentare awareness sull'AI per PMI italiane")
- Settimane (number, default 2, range 1-4)
@@ -239,23 +293,26 @@ Output: SPA React completa con tutte le pagine e componenti per il workflow: con
- Nicchie (multi-select o checkbox, prende default da Settings)
- Pulsante "Genera Calendario" con stati:
- Se API key non configurata: disabilitato, messaggio "Configura API key nelle Impostazioni"
- Se configurata: abilitato, al click mostra ProgressIndicator
- Se configurata: abilitato, al click chiama useGenerateCalendar() mutation
- FLUSSO ASYNC: al click, mutation ritorna {job_id}. La pagina mostra ProgressIndicator con job_id.
ProgressIndicator polla /status e quando status="completed" chiama onComplete che fa redirect a OutputReview con jobId.
- Usa useSettingsStatus() per controllare API key
- Usa useGenerateCalendar() mutation
- Al completamento (successo o parziale): redirect a OutputReview con jobId
7. Creare frontend/src/pages/OutputReview.tsx:
2. Creare frontend/src/pages/OutputReview.tsx:
- Riceve jobId da route params
- Carica risultati con useJobResults(jobId)
- Header con: nome campagna, conteggio successi/falliti, pulsante "Download CSV"
- Griglia di PostCard (3 colonne desktop, 2 tablet, 1 mobile)
- PostCard espandibile con SlideViewer
- Pulsante "Download CSV":
- Chiama useDownloadCsv(jobId)
- Se ci sono post falliti: mostra nota "Il CSV contiene solo i N post generati con successo"
- GESTIONE STATO EDIT INLINE:
- Mantiene stato locale dei post (copia di GenerateResponse)
- Quando utente edita una slide in SlideViewer, aggiorna lo stato locale via callback
- Il pulsante "Download CSV" invia lo stato locale modificato al backend via POST /api/export/{jobId}/csv (useDownloadEditedCsv hook)
- Questo garantisce che il CSV rifletta le modifiche inline dell'utente
- Se ci sono post falliti: mostra nota "Il CSV contiene solo i N post generati con successo"
- Se tutti i post sono falliti: messaggio "Nessun post generato con successo. Riprova."
8. Creare frontend/src/pages/GenerateSingle.tsx:
3. Creare frontend/src/pages/GenerateSingle.tsx:
- Form per generare un singolo post manualmente:
- Topic (textarea, obbligatorio)
- Tipo contenuto (select: valore, storytelling, news, riprova_sociale, coinvolgimento, promozione)
@@ -265,30 +322,23 @@ Output: SPA React completa con tutte le pagine e componenti per il workflow: con
- Al submit: chiama useGenerateSingle()
- Mostra risultato con SlideViewer direttamente nella pagina
- Pulsante download CSV per singolo post
GESTIONE STATO EDIT INLINE (importante):
- OutputReview mantiene stato locale dei post (copia di GenerateResponse)
- Quando utente edita una slide in SlideViewer, aggiorna lo stato locale
- Il pulsante Download CSV usa lo stato locale aggiornato (non l'originale dal server)
- Questo significa che il CSV riflette le modifiche dell'utente
</action>
<verify>
- GenerateCalendar.tsx ha form con obiettivo e settimane, pulsante disabilitato senza API key
- GenerateCalendar.tsx mostra ProgressIndicator con job_id dopo submit (non attende risposta sincrona)
- OutputReview.tsx mostra griglia di PostCard con badge PN e Schwartz
- SlideViewer.tsx ha navigazione frecce e campi editabili inline
- PostCard.tsx ha stati distinti per success e failed, con pulsante Riprova
- ProgressIndicator.tsx mostra progresso per-item
- OutputReview.tsx usa useDownloadEditedCsv per inviare edits al backend prima del download
- GenerateSingle.tsx ha form con select per tipo, livello, nicchia, formato
- npm run build completa senza errori TypeScript
</verify>
<done>
Web UI completa: form Genera Calendario con progress, griglia risultati con card/badge, SlideViewer con navigazione e edit inline, download CSV con modifiche utente, Genera Singolo Post, gestione errori per-item con Riprova.
Pagine complete: GenerateCalendar con form + ProgressIndicator async polling. OutputReview con griglia card, SlideViewer expansion, edit inline che si riflettono nel CSV via POST endpoint. GenerateSingle con form e anteprima.
</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<what-built>
Web UI completa con tutte le pagine: Dashboard, Genera Calendario, Output Review, Genera Singolo Post, Impostazioni. Inclusi progress indicator, griglia card con badge, navigazione slide, edit inline.
Web UI completa con tutte le pagine: Dashboard, Genera Calendario, Output Review, Genera Singolo Post, Impostazioni. Inclusi progress indicator con polling real-time, griglia card con badge, navigazione slide, edit inline con CSV export tramite POST.
</what-built>
<how-to-verify>
1. Verificare che `cd frontend && npm run build` completa senza errori
@@ -308,16 +358,20 @@ Output: SPA React completa con tutte le pagine e componenti per il workflow: con
3. Tutti i componenti importano tipi da types.ts (non definiscono tipi inline)
4. API hooks usano /postgenerator/api come base URL
5. PostCard ha due varianti visive: success (espandibile) e failed (errore + riprova)
6. SlideViewer supporta edit inline e navigazione frecce
6. SlideViewer supporta edit inline e navigazione frecce, con callback onEdit
7. GenerateCalendar disabilita pulsante se API key non configurata
8. OutputReview fa download CSV con le modifiche inline dell'utente
8. GenerateCalendar mostra ProgressIndicator con job_id (non attende risposta sincrona)
9. ProgressIndicator polla /api/generate/job/{job_id}/status ogni 2s e smette quando completato
10. OutputReview usa useDownloadEditedCsv (POST) per scaricare CSV con modifiche inline
</verification>
<success_criteria>
- Dashboard mostra stato API key e quick actions
- Settings permette configurazione API key, modello, nicchie, frequenza
- Genera Calendario ha form, progress indicator, redirect a risultati
- Output Review mostra griglia card con badge, slide viewer con edit, download CSV
- Genera Calendario ha form, async submit con job_id, ProgressIndicator con polling real-time
- ProgressIndicator polla /status e mostra progresso per-item (pending/processing/success/failed)
- Output Review mostra griglia card con badge, slide viewer con edit inline
- Download CSV invia edits al backend via POST e riceve CSV aggiornato
- Post falliti mostrano errore e pulsante Riprova
- Genera Singolo Post ha form completo con anteprima risultato
- Build frontend completa senza errori