diff --git a/.planning/STATE.md b/.planning/STATE.md index 4d456d2..2a4d23b 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -10,27 +10,27 @@ See: .planning/PROJECT.md (updated 2026-03-07) ## Current Position Phase: 1 of 4 (Core Generation Pipeline) -Plan: 1 of 4 in current phase -Status: In progress — Plan 01 completato, pronto per Plan 02 -Last activity: 2026-03-08 — Completato 01-01-PLAN.md (infrastructure skeleton) +Plan: 2 of 4 in current phase +Status: In progress — Plan 02 completato (parallelo con Plan 01) +Last activity: 2026-03-08 — Completato 01-02-PLAN.md (servizi dominio + prompt) -Progress: [█░░░░░░░░░] 6% (1/16 piani totali stimati) +Progress: [██░░░░░░░░] 12% (2/16 piani totali stimati) ## Performance Metrics **Velocity:** -- Total plans completed: 1 -- Average duration: 6 min -- Total execution time: 6 min +- Total plans completed: 2 +- Average duration: ~7 min +- Total execution time: 15 min **By Phase:** | Phase | Plans | Total | Avg/Plan | |-------|-------|-------|----------| -| 01-core-generation-pipeline | 1/4 | 6 min | 6 min | +| 01-core-generation-pipeline | 2/4 | 15 min | 7 min | **Recent Trend:** -- Last 5 plans: 6 min +- Last 5 plans: 6 min, 9 min - Trend: baseline stabilita *Updated after each plan completion* @@ -52,6 +52,10 @@ Recent decisions affecting current work: - [01-01]: SPAStaticFiles montato come ultima operazione in main.py — pattern stabilito - [01-01]: fastapi[standard]==0.135.1, anthropic==0.84.0 pinned in requirements.txt - [01-01]: docker-compose NO porte esposte, named volume postgenerator-data per persistenza +- [01-02]: CANVA_FIELDS 33 colonne con _image_keyword (non URL) — URL Unsplash in Phase 4 +- [01-02]: Distribuzione L3 split: valore-L3 in Cattura, riprova_sociale-L3 in Coinvolgi +- [01-02]: PromptService usa ValueError per variabili mancanti — fail esplicito non silenzioso +- [01-02]: Nicchie 50/50: slot pari=generico, slot dispari=verticale in rotazione ### Pending Todos @@ -59,12 +63,12 @@ None. ### Blockers/Concerns -- [Phase 1]: Canva field schema (placeholder names) non ancora definiti — devono essere locked come CANVA_FIELDS prima di scrivere codice generazione o LLM output schema (da affrontare in 01-02) +- [Phase 1 RISOLTO in 01-02]: CANVA_FIELDS locked con 33 colonne e assert a load-time - [Phase 1]: Validare token usage reale per batch 13 post con claude-sonnet-4-5 contro limite Tier 1 (8,000 OTPM) — necessario inter-request delay configurabile (2-3s) (da affrontare in 01-03) - [Phase 1]: Baseline qualita' prompt italiani da validare dopo prima generazione reale (post 01-03) ## Session Continuity -Last session: 2026-03-08T00:55:40Z -Stopped at: Completato 01-01-PLAN.md — Infrastructure skeleton (FastAPI + React/Vite/Docker) +Last session: 2026-03-08T01:00:34Z +Stopped at: Completato 01-02-PLAN.md — Servizi dominio + prompt .txt italiani Resume file: None diff --git a/.planning/phases/01-core-generation-pipeline/01-02-SUMMARY.md b/.planning/phases/01-core-generation-pipeline/01-02-SUMMARY.md new file mode 100644 index 0000000..9693804 --- /dev/null +++ b/.planning/phases/01-core-generation-pipeline/01-02-SUMMARY.md @@ -0,0 +1,159 @@ +--- +phase: 01-core-generation-pipeline +plan: 02 +subsystem: domain-logic +tags: [python, pydantic, calendar, prompts, constants, domain-model] + +# Dependency graph +requires: + - phase: 01-core-generation-pipeline (plan 01) + provides: backend/config.py con PROMPTS_PATH, struttura directory base +provides: + - CalendarService con generate_calendar() — 13 slot PN+Schwartz+fasi+nicchie+date + - FormatSelector con select_format() — matrice 30 combinazioni tipo x livello + - PromptService con load/list/compile — gestione prompt .txt con variabili + - CANVA_FIELDS locked (33 colonne) — schema CSV Canva definitivo + - 7 prompt .txt in italiano — system_prompt + topic_generator + 5 formati narrativi + - Pydantic schemas — CalendarSlot, GeneratedPost, TopicResult, PostResult +affects: + - 01-03 (LLMService userà PromptService e CalendarService) + - 01-04 (CSVBuilder userà CANVA_FIELDS e GeneratedPost schema) + +# Tech tracking +tech-stack: + added: [] + patterns: + - "Costanti LOCKED con assert a load-time per prevenire drift accidentale" + - "Pydantic Field con constraints espliciti (max_length, ge, min_length)" + - "Distribuzione PN/Schwartz verificata a doppio controllo: constants + calendar_service" + - "Prompt template con {{variabile}} doppia graffa (distingue da f-string e Jinja)" + +key-files: + created: + - backend/constants.py + - backend/schemas/__init__.py + - backend/schemas/calendar.py + - backend/schemas/generate.py + - backend/services/__init__.py + - backend/services/format_selector.py + - backend/services/calendar_service.py + - backend/services/prompt_service.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 + - backend/data/prompts/aida_promozione.txt + - backend/data/prompts/dato_news.txt + modified: + - .gitignore (fix: backend/data/ non più ignorato interamente) + +key-decisions: + - "CANVA_FIELDS usa _image_keyword (non _image_url): keyword testuali ora, URL Unsplash in Phase 4" + - "Distribuzione L3: 4 slot totali — 2 da valore (Cattura) + 2 da riprova_sociale (Coinvolgi)" + - "Nicchie: 50% generico (slot pari), 50% verticali in rotazione (slot dispari)" + - "PromptService ValueError per variabili mancanti: fail esplicito, non silenzioso" + +patterns-established: + - "Servizi puri: zero dipendenze HTTP, zero I/O async — testabili con pytest sincrono" + - "FormatSelector iniettabile in CalendarService (dependency injection per test)" + - "Prompt .txt scritti in italiano nativo — non tradotti da inglese" + +# Metrics +duration: 9min +completed: 2026-03-08 +--- + +# Phase 1 Plan 02: Servizi core di dominio — CalendarService, FormatSelector, PromptService, 7 prompt italiani + +**CalendarService genera 13 slot PN+Schwartz con distribuzione locked, FormatSelector mappa 30 combinazioni tipo x livello, PromptService compila 7 prompt .txt scritti in italiano con sostituzione variabili {{...}}** + +## Performance + +- **Duration:** 9 min +- **Started:** 2026-03-08T00:51:34Z +- **Completed:** 2026-03-08T01:00:34Z +- **Tasks:** 2 +- **Files modified:** 16 + +## Accomplishments + +- CalendarService produce esattamente 13 slot con distribuzione PN corretta (4v+2s+2n+3r+1c+1p) e Schwartz corretta (L5=3,L4=3,L3=4,L2=2,L1=1), ordinati per fase funnel, con rotazione nicchie e calcolo date +- CANVA_FIELDS locked come costante con assert a load-time — 33 colonne definitive per CSV Canva Bulk Create +- FormatSelector mappa tutte le 30 combinazioni (6 tipi x 5 livelli) da format_mapping.json con fallback "PAS" +- PromptService carica/compila/lista prompt .txt con sostituzione {{variabile}} e ValueError esplicito per variabili mancanti +- 7 prompt .txt scritti interamente in italiano: system_prompt, topic_generator, pas_valore, listicle_valore, bab_storytelling, aida_promozione, dato_news — tutti con schema output JSON esplicito +- Pydantic schemas completi: CalendarSlot, CalendarRequest, CalendarResponse, SlideContent, GeneratedPost, TopicResult, GenerateRequest, PostResult, GenerateResponse + +## Task Commits + +Ogni task è stato committato atomicamente: + +1. **Task 1: Costanti, schemas, FormatSelector** - `209d896` (feat) +2. **Task 2: CalendarService, PromptService, prompt .txt** - `ef9b947` (feat) + +**Plan metadata:** (questo commit) (docs: complete plan) + +## Files Created/Modified + +- `backend/constants.py` — CANVA_FIELDS (33), PERSUASION_DISTRIBUTION, SCHWARTZ_DISTRIBUTION, FORMATI_NARRATIVI, FUNZIONI_CONTENUTO, FASI_CAMPAGNA, NICCHIE_DEFAULT, POST_PER_CICLO +- `backend/schemas/calendar.py` — CalendarSlot, CalendarRequest, CalendarResponse con field constraints +- `backend/schemas/generate.py` — SlideContent, GeneratedPost, TopicResult, GenerateRequest, PostResult, GenerateResponse +- `backend/data/format_mapping.json` — matrice 6 tipi x 5 livelli -> formato narrativo +- `backend/services/format_selector.py` — FormatSelector: carica JSON, select_format con fallback, get_mapping +- `backend/services/calendar_service.py` — CalendarService: generate_calendar, ordinamento funnel, rotazione nicchie, calcolo date +- `backend/services/prompt_service.py` — PromptService: list_prompts, load_prompt, compile_prompt, save_prompt, get_required_variables +- `backend/data/prompts/system_prompt.txt` — esperto content marketing B2B italiano, regole tono, struttura 8 slide +- `backend/data/prompts/topic_generator.txt` — genera topic per slot con guida livelli L1-L5 +- `backend/data/prompts/pas_valore.txt` — formato PAS per post valore, schema JSON GeneratedPost +- `backend/data/prompts/listicle_valore.txt` — formato Listicle con 6 punti numerati +- `backend/data/prompts/bab_storytelling.txt` — formato BAB: Before→After→Bridge narrativo +- `backend/data/prompts/aida_promozione.txt` — formato AIDA per conversione, variabile call_to_action +- `backend/data/prompts/dato_news.txt` — Dato+Implicazione per news di settore +- `.gitignore` — fix: backend/data/ ignorato troppo aggressivamente (Regola 1 - Bug) + +## Decisions Made + +- **CANVA_FIELDS usa _image_keyword**: Le colonne immagine contengono keyword testuali, non URL. L'integrazione Unsplash arriva in Phase 4. Mantiene il CSV utile anche senza API Unsplash. +- **Distribuzione L3 split tra fasi**: I 4 slot L3 sono divisi tra "Cattura" (valore) e "Coinvolgi" (riprova_sociale). La logica è che chi conosce la soluzione (L3) ma non ancora il prodotto va nutrito sia con educazione che con prova sociale. +- **Nicchie 50/50**: Slot pari = generico, slot dispari = verticale in rotazione. Garantisce copertura del pubblico generico senza ignorare le nicchie specifiche. +- **PromptService fail esplicito**: ValueError per variabili mancanti invece di lasciare {{variabile}} nel testo. Un prompt con variabili non sostituite manderebbe al LLM istruzioni rotte. + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Regola 1 - Bug] Fix .gitignore: backend/data/ era ignorato troppo aggressivamente** + +- **Trovato durante:** Task 1 (staging dei file) +- **Problema:** Il pattern `data/` in .gitignore matchava anche `backend/data/`, impedendo di committare `format_mapping.json` e i file prompt .txt che sono file sorgente, non dati runtime +- **Fix:** Cambiato `data/` a `/data/` (solo root) e aggiunto le sottocartelle runtime specifiche (`backend/data/outputs/`, `backend/data/campaigns/`, `backend/data/config/`) +- **Files modificati:** `.gitignore` +- **Verifica:** `git check-ignore -v backend/data/format_mapping.json` → non ignorato +- **Committato in:** `209d896` (parte del Task 1 commit) + +--- + +**Totale deviazioni:** 1 auto-fixed (1 bug) +**Impatto sul piano:** Necessaria per committare file sorgente. Nessuno scope creep. + +## Issues Encountered + +Nessun problema durante l'implementazione — piano eseguito secondo le specifiche. + +## User Setup Required + +Nessuno — nessun servizio esterno richiede configurazione per questi file di dominio puro. + +## Next Phase Readiness + +- CalendarService e PromptService pronti per essere usati da LLMService (Plan 03) +- CANVA_FIELDS locked — CSVBuilder (Plan 04) può iniziare a usarlo +- 7 prompt in italiano pronti — LLMService userà PromptService.compile_prompt() per prepararli +- Tutti i servizi sono puri (zero async, zero HTTP) — testabili indipendentemente +- Nessun blocco: Plan 03 può proseguire + +--- +*Phase: 01-core-generation-pipeline* +*Completed: 2026-03-08*