chore: complete v1 milestone

Archived:
- milestones/v1-ROADMAP.md (full phase details)
- milestones/v1-REQUIREMENTS.md (46/46 shipped)
- milestones/v1-MILESTONE-AUDIT.md (audit report)

Created:
- MILESTONES.md (project milestone history)

Deleted:
- REQUIREMENTS.md (fresh one for next milestone)

Updated:
- PROJECT.md (requirements → Validated, decisions with outcomes)
- ROADMAP.md (collapsed to one-line v1 summary)
- STATE.md (reset for next milestone)

v1 MVP: 4 phases, 10 plans, 46 requirements, 8080 LOC
Timeline: 2 days (2026-03-07 → 2026-03-09)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Michele
2026-03-09 11:59:07 +01:00
parent d8f298463b
commit 1c9199bf38
8 changed files with 518 additions and 396 deletions

View File

@@ -0,0 +1,133 @@
---
milestone: v1
audited: 2026-03-09T11:30:00Z
status: tech_debt
scores:
requirements: 46/46
phases: 4/4
integration: 4/4
flows: 4/4
gaps: []
tech_debt:
- phase: cross-phase
items:
- "Pipeline singleton non invalidato quando API key cambia (routers/generate.py righe 109-117)"
- "Campo campagna inviato nel POST /export ma ignorato dal backend (hooks.ts riga 185)"
- "Job interrotti durante restart container non recuperabili"
- phase: 03-organization-layer
items:
- "brand_name hardcoded in generation_pipeline.py riga 290"
---
# Milestone v1 Audit Report — PostGenerator
**Milestone:** v1 — MVP Content Marketing Automation
**Audited:** 2026-03-09T11:30:00Z
**Status:** TECH_DEBT (no blockers, accumulated debt)
## Scores
| Area | Score | Details |
|------|-------|---------|
| Requirements | 46/46 | Tutti i requisiti v1 soddisfatti |
| Phases | 4/4 | Tutte le fasi completate e verificate |
| Integration | 4/4 | Cross-phase wiring verificato |
| E2E Flows | 4/4 | Tutti i flussi utente funzionanti |
## Phase Verification Summary
| Phase | Status | Score | Critical Gaps |
|-------|--------|-------|---------------|
| 01 - Core Generation Pipeline | gaps_found → RISOLTO | 3/5 → 5/5 | Slot-merge gap corretto in Phase 2 |
| 02 - Prompt Control + Output Review | passed | 16/16 | Nessuno |
| 03 - Organization Layer | passed | 5/5 | Nessuno |
| 04 - Enrichment | passed | 5/5 | Nessuno |
### Phase 1 Gap Resolution
Il gap critico originale (result.slot undefined in PostCard) e' stato **risolto**:
- `OutputReview.tsx` righe 32-41: merge CalendarSlot in PostResult via `jobData.calendar?.slots`
- `GenerateResponse.calendar` popolato correttamente da `generation_pipeline.py` riga 205
- BadgePN, BadgeSchwartz, metadata e retry/regen funzionano tutti
## Requirements Coverage
Tutti i 46 requisiti v1 sono soddisfatti:
| Area | Requirements | Status |
|------|-------------|--------|
| Calendar & Campaign | CAL-01..07 (7) | Tutti Complete |
| Format Selection | FMT-01..02 (2) | Tutti Complete |
| LLM Generation | LLM-01..06 (6) | Tutti Complete |
| Prompt System | PRM-01..05 (5) | Tutti Complete |
| CSV & Export | CSV-01..04 (4) | Tutti Complete |
| Image Keywords | IMG-01..04 (4) | Tutti Complete |
| Swipe File | SWP-01..04 (4) | Tutti Complete |
| Web UI | UI-01..08 (8) | Tutti Complete |
| Infrastructure | INF-01..06 (6) | Tutti Complete |
## E2E Flow Verification
| Flow | Status | Details |
|------|--------|---------|
| 1. Genera Calendario → Progress → Review → CSV | Funzionante | Pipeline completa, polling 2s, merge slot, download CSV con edits |
| 2. Swipe File → Topic Override → Generazione | Funzionante | CRUD swipe + picker inline + override pre-LLM + mark-used |
| 3. Prompt Editor → Genera → Rigenera singolo | Funzionante | CRUD prompts, file letti a runtime, regen con topic/notes override |
| 4. Unsplash Config → Genera → Thumbnail + CSV URLs | Funzionante | Settings API key, UnsplashService con cache, resolve keyword→URL, thumbnail lazy |
## Cross-Phase Integration
| From | To | Via | Status |
|------|----|-----|--------|
| Phase 1 (GenerationPipeline) | Phase 2 (Regen) | POST /generate/single + PostCard handleRegen | WIRED |
| Phase 1 (CalendarService) | Phase 3 (Topic Override) | CalendarRequest.topic_overrides | WIRED |
| Phase 1 (CSVBuilder) | Phase 4 (Unsplash) | image_url_map in build_csv() | WIRED |
| Phase 2 (OutputReview localResults) | Phase 4 (Thumbnails) | PostCard cover_image_keyword startsWith(http) | WIRED |
| Phase 3 (SwipeService) | Phase 1 (GenerateCalendar form) | useSwipeItems + topicOverrides state | WIRED |
| Phase 4 (UnsplashService) | Phase 1 (Pipeline) | _resolve_unsplash_keywords after batch | WIRED |
## Tech Debt
### Media Priorita'
**1. Pipeline singleton non invalidato su API key change**
- File: `backend/routers/generate.py` righe 109-117
- Impatto: Utente che cambia API key via Settings deve riavviare il container
- Fix: Invalidare `_pipeline_instance = None` nel PUT /settings quando api_key cambia
### Bassa Priorita'
**2. Campo campagna inviato inutilmente nel POST export**
- File: `frontend/src/api/hooks.ts` riga 185
- Impatto: Nessuno (Pydantic ignora campi extra), solo rumore
- Fix: Rimuovere `campagna` dal payload frontend o aggiungerlo al schema backend
**3. brand_name hardcoded in generation_pipeline.py**
- File: `backend/services/generation_pipeline.py` riga 290
- Impatto: Brand name non personalizzabile senza modifica codice
- Fix: Leggere da settings.json (commento nel codice indica intenzione futura)
**4. Job interrotti durante restart non recuperabili**
- Impatto: Job in-flight durante restart sono persi
- Fix: Salvare stato intermedio su disco durante la generazione (non prioritario per uso single-user)
### Totale: 4 items across 2 aree (1 media, 3 bassa)
## Human Verification Pending
Le seguenti verifiche richiedono il deployment su VPS e un test manuale:
1. **Web UI accessibile** su https://lab.mlhub.it/postgenerator/
2. **Generazione end-to-end** con API key Anthropic reale
3. **CSV in Excel** con caratteri italiani intatti
4. **Unsplash thumbnails** con API key Unsplash reale
5. **Persistenza dati** Swipe File dopo restart container
## Conclusion
Il milestone v1 e' **funzionalmente completo**. Tutti i 46 requisiti sono implementati e verificati a livello di codice. I 4 flussi E2E sono collegati correttamente cross-fase. Il tech debt accumulato e' minimo (4 items, nessuno bloccante) e puo' essere accettato per procedere al deploy e alla validazione umana.
---
_Audited: 2026-03-09T11:30:00Z_
_Auditor: Claude Opus 4.6 (gsd-audit-milestone orchestrator) + Claude Sonnet 4.6 (gsd-integration-checker)_

View File

@@ -0,0 +1,153 @@
# Requirements Archive: v1 MVP Content Marketing Automation
**Archived:** 2026-03-09
**Status:** SHIPPED
This is the archived requirements specification for v1.
For current requirements, see `.planning/REQUIREMENTS.md` (created for next milestone).
---
**Defined:** 2026-03-07
**Core Value:** Generare un calendario editoriale completo di caroselli Instagram strategicamente orchestrati, pronti per Canva Bulk Create, con un click dalla Web UI.
## v1 Requirements
### Calendar & Campaign Engine
- [x] **CAL-01**: Sistema genera ciclo di 13 post con distribuzione Persuasion Nurturing (4 valore, 2 storytelling, 2 news, 3 riprova sociale, 1 coinvolgimento, 1 promo)
- [x] **CAL-02**: Ogni post ha livello Schwartz assegnato secondo distribuzione (L5+L4=6, L3=4, L2=2, L1=1)
- [x] **CAL-03**: Rotazione nicchie B2B: 50% generico, 50% verticali in rotazione configurabile
- [x] **CAL-04**: Campaign Planner distribuisce post nelle 4 fasi (attira/cattura/coinvolgi/converti) nell'ordine corretto
- [x] **CAL-05**: Date di pubblicazione suggerite calcolate automaticamente (configurabile frequenza)
- [x] **CAL-06**: Topic generation ibrida: LLM auto-genera topic per ogni slot dato l'obiettivo campagna
- [x] **CAL-07**: Override manuale topic per singoli slot prima della generazione contenuti
### Format Selection
- [x] **FMT-01**: Mapping automatico tipo_contenuto x livello_schwartz -> formato narrativo (PAS, AIDA, BAB, Listicle, Storytelling, Dato+Implicazione, Obiezione+Risposta)
- [x] **FMT-02**: Tabella di mapping configurabile via file JSON (data/format_mapping.json)
### LLM Content Generation
- [x] **LLM-01**: Genera contenuto carosello completo (8 slide) tramite Claude API in formato JSON strutturato
- [x] **LLM-02**: Validazione JSON output: verifica struttura, conteggio slide, campi non vuoti
- [x] **LLM-03**: Retry automatico (1 tentativo) con istruzione correttiva se JSON non valido
- [x] **LLM-04**: Rate limiting e backoff rispettando limiti API Claude (Tier 1)
- [x] **LLM-05**: Per-item error isolation: fallimento di un singolo post non blocca il batch
- [x] **LLM-06**: Provider LLM configurabile da .env (Claude come default)
### Prompt System
- [x] **PRM-01**: Prompt esternalizzati in file .txt nella directory /prompts/ con struttura SYSTEM/USER/OUTPUT_SCHEMA
- [x] **PRM-02**: Prompt Manager carica, lista e compila prompt con variabili ({formato}, {tipo_contenuto}, {livello_schwartz}, ecc.)
- [x] **PRM-03**: Almeno 5 prompt base per MVP: PAS valore, Listicle valore, BAB storytelling, AIDA promozione, Dato news
- [x] **PRM-04**: System prompt scritto IN italiano (non "scrivi in italiano" dall'inglese)
- [x] **PRM-05**: Prompt Editor nella Web UI: visualizza, modifica e salva file prompt
### CSV & Export
- [x] **CSV-01**: CSV con header completo compatibile Canva Bulk Create (33 colonne: 8 metadati + 24 slide (8 slide x 3 campi) + 1 caption_instagram)
- [x] **CSV-02**: Encoding utf-8-sig (BOM) per compatibilita' Excel/Windows
- [x] **CSV-03**: Campi metadato (campagna, fase, tipo, formato, funzione, livello, nicchia, data) inclusi per analisi
- [x] **CSV-04**: Download CSV dalla Web UI
### Image Keywords
- [x] **IMG-01**: Genera keyword immagine per ogni slide come parte dell'output LLM
- [x] **IMG-02**: Fetch immagini da Unsplash API (opzionale, attivo solo se API key configurata)
- [x] **IMG-03**: Cache locale per evitare hit ripetuti su Unsplash (50 req/h limite free tier)
- [x] **IMG-04**: Fallback: URL placeholder se Unsplash non disponibile o non configurato
### Swipe File
- [x] **SWP-01**: CRUD per cattura rapida topic/idee (topic, nicchia, note, data)
- [x] **SWP-02**: Storage in file JSON (data/swipe_file.json)
- [x] **SWP-03**: Gestione Swipe File dalla Web UI (aggiungi, lista, elimina)
- [x] **SWP-04**: Possibilita' di usare topic dallo swipe file come override nella generazione calendario
### Web UI
- [x] **UI-01**: Dashboard con stato campagne e ultimi CSV generati
- [x] **UI-02**: Form "Genera Calendario": N settimane + obiettivo campagna + nicchie -> genera ciclo completo
- [x] **UI-03**: Form "Genera Singolo Post": topic + parametri manuali -> genera 1 carosello
- [x] **UI-04**: Output Review: anteprima caroselli generati prima dell'export (visualizzazione slide-by-slide)
- [x] **UI-05**: Prompt Editor: lista, visualizza, modifica e salva prompt
- [x] **UI-06**: Swipe File Manager: aggiungi/lista/elimina idee topic
- [x] **UI-07**: Pagina Impostazioni: provider LLM, API keys, nicchie attive, lingua, frequenza pubblicazione
- [x] **UI-08**: Progress indicator durante generazione bulk (stato per singolo post)
### Infrastructure & Deploy
- [x] **INF-01**: Backend FastAPI con API REST per tutte le operazioni
- [x] **INF-02**: Frontend React + Tailwind CSS (SPA servita da FastAPI)
- [x] **INF-03**: Single container Docker (multi-stage build: Node build React, Python serve tutto)
- [x] **INF-04**: Deploy su VPS Hostinger su subpath /postgenerator/ con nginx lab-router
- [x] **INF-05**: Configurazione via .env (API keys, provider LLM, lingua, frequenza, nicchie)
- [x] **INF-06**: File-based storage: prompts/, outputs/, data/ (no database)
## v2 Requirements (Deferred)
### Campaign History & Analytics
- **V2-01**: Storico campagne con browsing e ricerca
- **V2-02**: Note performance per campagna (engagement, reach manuale)
- **V2-03**: A/B analysis per nicchia (confronto performance tra target)
### Advanced Generation
- **V2-04**: Generazione multi-lingua (inglese oltre italiano)
- **V2-05**: Template prompt per nicchia specifica (es: pas_valore_dentisti.txt)
- **V2-06**: Configurazione mix Persuasion Nurturing personalizzabile (non solo 13 post fissi)
### Integration
- **V2-07**: Webhook/API per triggering generazione da n8n
- **V2-08**: Export diretto via Canva API (bypass CSV)
## Out of Scope
| Feature | Reason |
|---------|--------|
| Pubblicazione diretta su Instagram | Il sistema produce CSV, la pubblicazione e' manuale via Canva |
| Scheduling automatico | Le date sono suggerite, la pianificazione e' manuale |
| Multi-utente / autenticazione | Uso personale di Michele, single-user |
| Database relazionale | File system sufficiente per MVP, complessita' non giustificata |
| Template Canva generation | I template si creano manualmente su Canva |
| Real-time analytics Instagram | Dominio diverso, richiede Instagram API con review |
| Video/Reel generation | Solo caroselli per MVP |
## Traceability
| Requirement | Phase | Status |
|-------------|-------|--------|
| CAL-01..07 | Phase 1 | Complete |
| FMT-01..02 | Phase 1 | Complete |
| LLM-01..06 | Phase 1 | Complete |
| PRM-01..04 | Phase 1 | Complete |
| PRM-05 | Phase 2 | Complete |
| CSV-01..04 | Phase 1 | Complete |
| IMG-01, IMG-04 | Phase 1 | Complete |
| IMG-02..03 | Phase 4 | Complete |
| SWP-01..04 | Phase 3 | Complete |
| UI-01..04, UI-07..08 | Phase 1 | Complete |
| UI-05 | Phase 2 | Complete |
| UI-06 | Phase 3 | Complete |
| INF-01..06 | Phase 1 | Complete |
**Coverage:**
- v1 requirements: 46 total
- Shipped: 46
- Dropped: 0
- Adjusted: 0
---
## Milestone Summary
**Shipped:** 46 of 46 v1 requirements
**Adjusted:** None — all requirements implemented as originally specified
**Dropped:** None
---
*Archived: 2026-03-09 as part of v1 milestone completion*

View File

@@ -0,0 +1,103 @@
# Milestone v1: MVP Content Marketing Automation
**Status:** SHIPPED 2026-03-09
**Phases:** 1-4
**Total Plans:** 10
## Overview
PostGenerator trasforma framework strategici di content marketing (Persuasion Nurturing + livelli Schwartz) in caroselli Instagram pronti per Canva Bulk Create. Il percorso di sviluppo segue una logica precisa: prima costruire la pipeline di generazione end-to-end funzionante (Fase 1), poi dare il controllo sulla qualita' dell'output tramite editor di prompt e anteprima (Fase 2), poi aggiungere gli strumenti organizzativi per un workflow sostenibile (Fase 3), infine arricchire con integrazioni opzionali (Fase 4). Ogni fase consegna un sistema verificabile e utilizzabile indipendentemente dalla successiva.
## Phases
### Phase 1: Core Generation Pipeline
**Goal**: L'utente puo' generare un calendario di 13 caroselli completi e scaricare un CSV valido per Canva Bulk Create con un click dalla Web UI deployata su VPS.
**Depends on**: Nothing (first phase)
**Requirements**: INF-01..06, CAL-01..07, FMT-01..02, LLM-01..06, PRM-01..04, CSV-01..04, IMG-01, IMG-04, UI-01..04, UI-07, UI-08
**Plans**: 4 plans
Plans:
- [x] 01-01: Infrastructure setup — FastAPI skeleton + React SPA + Docker multi-stage build + subpath /postgenerator/ (19 files, 6 min)
- [x] 01-02: Core services — CalendarService + FormatSelector + PromptService + costanti dominio + 7 prompt italiani (16 files, 9 min)
- [x] 01-03: LLM pipeline — LLMService + CSVBuilder + GenerationPipeline + API routers (9 files, 8 min)
- [x] 01-04: Web UI — Dashboard + Genera Calendario + Output Review + Genera Singolo + Settings (16 files, 10 min)
**Completed**: 2026-03-08
---
### Phase 2: Prompt Control + Output Review
**Goal**: L'utente puo' modificare i prompt direttamente dalla Web UI senza toccare il codice, rigenerare singoli post insoddisfacenti, e rivedere l'anteprima completa di ogni carosello prima di esportare il CSV.
**Depends on**: Phase 1
**Requirements**: PRM-05, UI-05
**Plans**: 2 plans
Plans:
- [x] 02-01: Prompt Editor — backend prompts router CRUD + frontend pagina PromptEditor con lista, textarea, variabili, badge modificato/default (7 files, 5 min)
- [x] 02-02: Per-item regeneration — bottone Rigenera con popover inline, badge rigenerato, summary counter (2 files, 4 min)
**Completed**: 2026-03-08
---
### Phase 3: Organization Layer
**Goal**: L'utente puo' salvare rapidamente idee e topic interessanti in un Swipe File consultabile, e ritrovare e ri-scaricare calendari generati in sessioni precedenti.
**Depends on**: Phase 1
**Requirements**: SWP-01..04, UI-06
**Plans**: 2 plans
Plans:
- [x] 03-01: SwipeService CRUD — backend + Pydantic schemas + FastAPI router + pagina SwipeFile UI (9 files, 5 min)
- [x] 03-02: Swipe-to-calendar integration — topic_overrides in CalendarRequest + picker Swipe File nel form Genera Calendario (5 files, 3 min)
**Completed**: 2026-03-09
---
### Phase 4: Enrichment
**Goal**: L'utente con API key Unsplash configurata vede URL immagini reali nel CSV invece di placeholder; l'utente puo' passare voci dello Swipe File come contesto durante la generazione topic per risultati piu' aderenti alle proprie osservazioni.
**Depends on**: Phase 3
**Requirements**: IMG-02, IMG-03
**Plans**: 2 plans
Plans:
- [x] 04-01: UnsplashService backend — cache disco + traduzione IT->EN + integrazione pipeline/CSV (6 files, 5 min)
- [x] 04-02: Frontend Unsplash UI — campo API key in Settings, thumbnail cover in PostCard, hint OutputReview (4 files, 3 min)
**Completed**: 2026-03-09
---
## Milestone Summary
**Key Decisions:**
- Claude API come LLM provider (familiarita' ecosistema, qualita' output italiano)
- FastAPI + React (separazione, UI ricca, coerenza con VPS echosystem)
- File system storage senza DB (semplicita' MVP, prompt e config editabili)
- root_path SOLO via Uvicorn --root-path (mai nel costruttore FastAPI)
- CSV encoding utf-8-sig (BOM) per compatibilita' Excel/Windows
- CANVA_FIELDS 33 colonne locked con assert a load-time
- Pipeline singleton con fallback da disco per persistenza job
- Design stone/amber B2B (non gradienti viola generici)
- Risoluzione Unsplash UNA SOLA VOLTA dopo batch LLM
- Dizionario statico IT->EN (~30 keyword B2B) per traduzione keyword Unsplash
**Issues Resolved:**
- Slot-merge gap (result.slot undefined in PostCard) risolto in Phase 2
- PromptService lazy init per sincronizzazione con lifespan FastAPI
- Import mancante apiFetch in hooks.ts
- .gitignore troppo aggressivo su backend/data/
**Technical Debt Incurred:**
- Pipeline singleton non invalidato quando API key cambia (routers/generate.py)
- Campo campagna inviato nel POST /export ma ignorato dal backend (hooks.ts)
- brand_name hardcoded in generation_pipeline.py
- Job interrotti durante restart container non recuperabili
---
_For current project status, see .planning/ROADMAP.md_