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

@@ -14,6 +14,7 @@ files_modified:
- backend/schemas/generate.py
- backend/data/format_mapping.json
- backend/data/prompts/system_prompt.txt
- backend/data/prompts/topic_generator.txt
- backend/data/prompts/pas_valore.txt
- backend/data/prompts/listicle_valore.txt
- backend/data/prompts/bab_storytelling.txt
@@ -47,7 +48,7 @@ must_haves:
provides: "CalendarSlot, CalendarRequest, CalendarResponse Pydantic models"
contains: "class CalendarSlot"
- path: "backend/schemas/generate.py"
provides: "SlideContent, GeneratedPost Pydantic models per output LLM e CSV"
provides: "SlideContent, GeneratedPost, TopicResult Pydantic models per output LLM e CSV"
contains: "class GeneratedPost"
- path: "backend/data/format_mapping.json"
provides: "Tabella mapping tipo_contenuto x livello_schwartz -> formato narrativo"
@@ -158,6 +159,7 @@ Output: Servizi Python testabili indipendentemente, 5 prompt .txt in italiano, s
4. Creare backend/schemas/generate.py con Pydantic models:
- SlideContent: headline (str), body (str), image_keyword (str)
- GeneratedPost: cover_title (str), cover_subtitle (str), cover_image_keyword (str), slides (list[SlideContent] — 6 slide centrali s2-s7), cta_text (str), cta_subtext (str), cta_image_keyword (str), caption_instagram (str)
- TopicResult: topic (str) — Pydantic model per validare output LLM della generazione topic. Usato da LLMService.generate_topic() con lo stesso loop retry/validation delle altre generazioni.
- GenerateRequest: slot (CalendarSlot), obiettivo_campagna (str), brand_name (Optional[str]), tono (Optional[str])
- PostResult: slot_index (int), status (Literal["success", "failed", "pending"]), post (Optional[GeneratedPost]), error (Optional[str])
- GenerateResponse: campagna (str), results (list[PostResult]), total (int), success_count (int), failed_count (int)
@@ -178,7 +180,7 @@ Output: Servizi Python testabili indipendentemente, 5 prompt .txt in italiano, s
<verify>
- backend/constants.py: CANVA_FIELDS ha esattamente 33 elementi, PERSUASION_DISTRIBUTION somma a 13, SCHWARTZ_DISTRIBUTION somma a 13
- backend/schemas/calendar.py: CalendarSlot importabile, CalendarRequest ha campo obiettivo_campagna
- backend/schemas/generate.py: GeneratedPost ha slides come list[SlideContent], PostResult ha campo status
- backend/schemas/generate.py: GeneratedPost ha slides come list[SlideContent], PostResult ha campo status, TopicResult ha campo topic (str)
- backend/data/format_mapping.json: contiene tutte le 6 chiavi tipo_contenuto, ciascuna con 5 livelli
- backend/services/format_selector.py: FormatSelector ha metodo select_format
</verify>
@@ -193,6 +195,7 @@ Output: Servizi Python testabili indipendentemente, 5 prompt .txt in italiano, s
backend/services/calendar_service.py
backend/services/prompt_service.py
backend/data/prompts/system_prompt.txt
backend/data/prompts/topic_generator.txt
backend/data/prompts/pas_valore.txt
backend/data/prompts/listicle_valore.txt
backend/data/prompts/bab_storytelling.txt
@@ -240,6 +243,13 @@ Output: Servizi Python testabili indipendentemente, 5 prompt .txt in italiano, s
- Lingua: italiano naturale, NON tradotto dall'inglese
- Output: JSON strutturato con i campi specificati nello schema
backend/data/prompts/topic_generator.txt (prompt per generazione topic):
- Variabili: {{obiettivo_campagna}}, {{tipo_contenuto}}, {{livello_schwartz}}, {{target_nicchia}}, {{fase_campagna}}
- Istruzioni: genera UN topic specifico e concreto per un post Instagram carosello
- Il topic deve essere rilevante per l'obiettivo campagna, il tipo di contenuto e la nicchia
- Output: JSON con campo "topic" (stringa, max 100 caratteri)
- Scritto IN italiano come tutti gli altri prompt
backend/data/prompts/pas_valore.txt (formato PAS per post valore):
- Sezioni: SYSTEM (ref system_prompt), USER, OUTPUT_SCHEMA
- Variabili: {{obiettivo_campagna}}, {{target_nicchia}}, {{livello_schwartz}}, {{topic}}, {{brand_name}}
@@ -277,13 +287,13 @@ Output: Servizi Python testabili indipendentemente, 5 prompt .txt in italiano, s
- CalendarService.generate_calendar() con CalendarRequest(obiettivo_campagna="test", settimane=2) produce CalendarResponse con esattamente 13 slot
- Distribuzione PN: contare tipi -> 4 valore, 2 storytelling, 2 news, 3 riprova, 1 coinvolgimento, 1 promo
- Distribuzione Schwartz: contare livelli -> L5=3, L4=3, L3=4, L2=2, L1=1
- PromptService.list_prompts() ritorna almeno 6 file (system + 5 base)
- PromptService.list_prompts() ritorna almeno 7 file (system + topic_generator + 5 base)
- PromptService.compile_prompt("pas_valore", {"obiettivo_campagna": "test", ...}) sostituisce tutte le variabili senza errori
- Tutti i prompt .txt contengono SOLO testo italiano, nessuna istruzione in inglese
- Nessun prompt contiene numeri hardcoded per slide count — usano {{num_slides}} o la struttura e' definita nell'output schema
</verify>
<done>
CalendarService genera 13 slot con distribuzione PN e Schwartz corretta, assegna fasi campagna, calcola date, ruota nicchie. PromptService carica e compila prompt con variabili {{...}}. 5 prompt base + system prompt scritti IN italiano, con output JSON schema esplicito. Nessun valore hardcoded nei template.
CalendarService genera 13 slot con distribuzione PN e Schwartz corretta, assegna fasi campagna, calcola date, ruota nicchie. PromptService carica e compila prompt con variabili {{...}}. 5 prompt base + system prompt + topic_generator prompt scritti IN italiano, con output JSON schema esplicito. Nessun valore hardcoded nei template.
</done>
</task>