docs(04): complete enrichment phase
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -138,8 +138,8 @@
|
||||
| CSV-03 | Phase 1 | Complete |
|
||||
| CSV-04 | Phase 1 | Complete |
|
||||
| IMG-01 | Phase 1 | Complete |
|
||||
| IMG-02 | Phase 4 | Pending |
|
||||
| IMG-03 | Phase 4 | Pending |
|
||||
| IMG-02 | Phase 4 | Complete |
|
||||
| IMG-03 | Phase 4 | Complete |
|
||||
| IMG-04 | Phase 1 | Complete |
|
||||
| SWP-01 | Phase 3 | Complete |
|
||||
| SWP-02 | Phase 3 | Complete |
|
||||
@@ -167,4 +167,4 @@
|
||||
|
||||
---
|
||||
*Requirements defined: 2026-03-07*
|
||||
*Last updated: 2026-03-09 — Phase 3 requirements marked Complete*
|
||||
*Last updated: 2026-03-09 — Phase 4 requirements marked Complete*
|
||||
|
||||
@@ -15,7 +15,7 @@ Decimal phases appear between their surrounding integers in numeric order.
|
||||
- [x] **Phase 1: Core Generation Pipeline** - Infrastruttura + pipeline calendario → LLM → CSV funzionante end-to-end
|
||||
- [x] **Phase 2: Prompt Control + Output Review** - Editor prompt via UI e anteprima caroselli prima dell'export
|
||||
- [x] **Phase 3: Organization Layer** - Swipe File e gestione storico campagne per workflow sostenibile
|
||||
- [ ] **Phase 4: Enrichment** - Integrazione Unsplash, context injection da Swipe File, polish UI
|
||||
- [x] **Phase 4: Enrichment** - Integrazione Unsplash, context injection da Swipe File, polish UI
|
||||
|
||||
## Phase Details
|
||||
|
||||
@@ -82,8 +82,8 @@ Plans:
|
||||
**Plans**: 2 plans
|
||||
|
||||
Plans:
|
||||
- [ ] 04-01-PLAN.md — UnsplashService backend + Settings unsplash_api_key + integrazione pipeline/CSV con risoluzione keyword -> URL (Wave 1)
|
||||
- [ ] 04-02-PLAN.md — Frontend: campo Unsplash in Settings, thumbnail cover in PostCard, hint OutputReview (Wave 2)
|
||||
- [x] 04-01-PLAN.md — UnsplashService backend + Settings unsplash_api_key + integrazione pipeline/CSV con risoluzione keyword -> URL (Wave 1)
|
||||
- [x] 04-02-PLAN.md — Frontend: campo Unsplash in Settings, thumbnail cover in PostCard, hint OutputReview (Wave 2)
|
||||
|
||||
---
|
||||
|
||||
@@ -97,4 +97,4 @@ Phases execute in numeric order: 1 → 2 → 3 → 4
|
||||
| 1. Core Generation Pipeline | 4/4 | Complete | 2026-03-08 |
|
||||
| 2. Prompt Control + Output Review | 2/2 | Complete | 2026-03-08 |
|
||||
| 3. Organization Layer | 2/2 | Complete | 2026-03-09 |
|
||||
| 4. Enrichment | 0/2 | Not started | - |
|
||||
| 4. Enrichment | 2/2 | Complete | 2026-03-09 |
|
||||
|
||||
112
.planning/phases/04-enrichment/04-VERIFICATION.md
Normal file
112
.planning/phases/04-enrichment/04-VERIFICATION.md
Normal file
@@ -0,0 +1,112 @@
|
||||
---
|
||||
phase: 04-enrichment
|
||||
verified: 2026-03-09T08:30:00Z
|
||||
status: passed
|
||||
score: 5/5 must-haves verified
|
||||
---
|
||||
|
||||
# Phase 4: Enrichment Verification Report
|
||||
|
||||
**Phase Goal:** URL immagini reali nel CSV quando API key Unsplash configurata.
|
||||
**Verified:** 2026-03-09T08:30:00Z
|
||||
**Status:** PASSED
|
||||
**Re-verification:** No - initial verification
|
||||
|
||||
## Note on Phase Goal vs. Implementation Scope
|
||||
|
||||
The ROADMAP.md phase goal mentions two features: Unsplash integration AND Swipe File context injection. The CONTEXT.md for phase 4 explicitly resolves this: context injection from Swipe File is already covered by topic_overrides in Phase 3 and is deferred to v2. The ROADMAP success criteria (3 items) cover ONLY Unsplash. Requirements mapped to this phase are IMG-02 and IMG-03 only.
|
||||
|
||||
## Goal Achievement
|
||||
|
||||
### Observable Truths
|
||||
|
||||
| # | Truth | Status | Evidence |
|
||||
|---|-------|--------|----------|
|
||||
| 1 | Se API key Unsplash configurata, il CSV contiene URL immagini reali | VERIFIED | _resolve_image() in CSVBuilder applica image_url_map su cover, slides s2-s7 e CTA. _resolve_unsplash_keywords() legge settings, crea UnsplashService, risolve keyword uniche e passa image_url_map a build_csv() |
|
||||
| 2 | Se Unsplash non configurato o rate limit, il CSV usa keyword testuali senza errori | VERIFIED | unsplash_api_key None: ritorna None subito. _resolve_image() ritorna keyword originale quando image_url_map e None. Rate limit: flag _rate_limited=True quando X-Ratelimit-Remaining < 5, keyword restanti usano fallback testuale |
|
||||
| 3 | Cache locale evita chiamate duplicate per keyword identiche | VERIFIED | resolve_keywords() controlla self._cache in-memory prima di ogni API call. Cache disco in data/unsplash_cache.json caricata all-init, salvata dopo ogni batch con nuove entries |
|
||||
| 4 | Frontend mostra campo per configurare API key Unsplash | VERIFIED | Settings.tsx: sezione Immagini con input unsplash_api_key, toggle visibilita separato, helper text condizionale, delete-if-empty nel submit |
|
||||
| 5 | PostCard mostra thumbnail quando cover_image_keyword e URL reale | VERIFIED | PostCard.tsx riga 185: startsWith(http) guard, img w-20 h-14 object-cover loading=lazy onError-fallback |
|
||||
|
||||
**Score:** 5/5 truths verified
|
||||
|
||||
### Required Artifacts
|
||||
|
||||
| Artifact | Lines | Status | Details |
|
||||
|----------|-------|--------|---------|
|
||||
| backend/services/unsplash_service.py | 333 | VERIFIED | search_photo(), resolve_keywords(), _load_cache(), _save_cache(), close(). Dizionario IT->EN 30+ keyword B2B. 1 retry su errori rete. Rate limit via X-Ratelimit-Remaining header. |
|
||||
| backend/schemas/settings.py | 54 | VERIFIED | unsplash_api_key: Optional[str] Field a riga 51 |
|
||||
| backend/routers/settings.py | 172 | VERIFIED | unsplash_api_key_masked in SettingsResponse (riga 50), unsplash_api_key_configured in SettingsStatusResponse (riga 38), None-preserving merge nel PUT (righe 157-158) |
|
||||
| backend/services/csv_builder.py | 214 | VERIFIED | _resolve_image() a riga 120. Applicato su cover_image_keyword (188), label_image_keyword per slides (197), cta_image_keyword (207). build_csv() e build_csv_content() accettano image_url_map opzionale. |
|
||||
| backend/services/generation_pipeline.py | 685 | VERIFIED | image_url_map in JobStatus dataclass (riga 74), _resolve_unsplash_keywords() dopo il loop slot (riga 382), serializzato in _save_job_to_disk() (riga 628), deserializzato in _load_job_from_disk() (riga 672) |
|
||||
| backend/routers/export.py | 161 | VERIFIED | Riga 117: image_url_map = job_data.get(image_url_map), passata a build_csv_content() a riga 136 |
|
||||
| frontend/src/types.ts | 215 | VERIFIED | unsplash_api_key in Settings (riga 149), unsplash_api_key_configured: boolean in SettingsStatus (riga 155) |
|
||||
| frontend/src/pages/Settings.tsx | 289 | VERIFIED | Sezione Immagini righe 151-179, state showUnsplashKey separato, helper text condizionale, delete-if-empty nel submit |
|
||||
| frontend/src/components/PostCard.tsx | 299 | VERIFIED | Righe 185-195: startsWith(http) guard, img w-20 h-14 object-cover rounded-md loading=lazy, onError hide |
|
||||
| frontend/src/pages/OutputReview.tsx | 215 | VERIFIED | Righe 161-172: useSettingsStatus() importato e usato, hint condizionale su \!unsplash_api_key_configured con Link to=/impostazioni |
|
||||
|
||||
### Key Link Verification
|
||||
|
||||
| From | To | Via | Status | Details |
|
||||
|------|----|-----|--------|---------|
|
||||
| generation_pipeline.py | unsplash_service.py | UnsplashService.resolve_keywords() | WIRED | Import riga 34, istanza creata e usata in _resolve_unsplash_keywords() righe 587-601 |
|
||||
| generation_pipeline.py | csv_builder.py | image_url_map passata a build_csv() | WIRED | Riga 400: image_url_map=image_url_map passata a self._csv.build_csv() |
|
||||
| csv_builder.py | image_url_map | _resolve_image() su cover/slides/cta | WIRED | 3 call sites verificate: righe 188, 197, 207 |
|
||||
| export.py | image_url_map dal job JSON | job_data.get(image_url_map) -> build_csv_content() | WIRED | Riga 117 recupera, riga 136 passa al builder |
|
||||
| Settings.tsx | unsplash_api_key nel form | Input controlled, delete-if-empty nel submit | WIRED | Righe 160-161 input, 72-74 logica submit difensiva |
|
||||
| OutputReview.tsx | useSettingsStatus | unsplash_api_key_configured per hint | WIRED | Riga 16 import, 24 hook, 161 conditional render |
|
||||
| PostCard.tsx | cover_image_keyword | startsWith(http) per thumbnail condizionale | WIRED | Riga 185: conditional render basato su valore della prop |
|
||||
| routers/settings.py | unsplash_api_key in Settings | GET/PUT con campo mascherato e None-preserving merge | WIRED | Righe 108, 131, 157-158, 171 |
|
||||
|
||||
### Requirements Coverage
|
||||
|
||||
| Requirement | Description | Status | Evidence |
|
||||
|-------------|-------------|--------|----------|
|
||||
| IMG-02 | Fetch immagini Unsplash, attivo solo se API key configurata | SATISFIED | UnsplashService con httpx.AsyncClient, attivato solo quando unsplash_api_key non None |
|
||||
| IMG-03 | Cache locale per evitare hit ripetuti (50 req/h limite free tier) | SATISFIED | Cache in-memory self._cache + file JSON su disco data/unsplash_cache.json, persistente tra riavvii container |
|
||||
|
||||
### Anti-Patterns Found
|
||||
|
||||
Nessun anti-pattern bloccante rilevato.
|
||||
|
||||
| File | Pattern | Severity | Impact |
|
||||
|------|---------|----------|--------|
|
||||
| Nessuno | - | - | - |
|
||||
|
||||
### Human Verification Required
|
||||
|
||||
**1. Risoluzione Unsplash end-to-end**
|
||||
|
||||
Test: Configurare una API key Unsplash valida in Impostazioni, avviare generazione bulk, scaricare il CSV.
|
||||
Expected: Le colonne *_image_keyword nel CSV contengono URL https://images.unsplash.com/... invece di keyword testuali.
|
||||
Why human: Richiede API key Unsplash reale e connessione di rete verso api.unsplash.com.
|
||||
|
||||
**2. Thumbnail visibile in OutputReview**
|
||||
|
||||
Test: Dopo una generazione con Unsplash configurato, aprire OutputReview.
|
||||
Expected: PostCard mostrano thumbnail 80x56px sotto il cover_title. Se URL non carica, img si nasconde silenziosamente.
|
||||
Why human: Richiede URL Unsplash reali per verificare il rendering nel browser.
|
||||
|
||||
**3. Hint scompare dopo configurazione**
|
||||
|
||||
Test: Aprire OutputReview senza Unsplash configurato (hint visibile), configurare la key, tornare in OutputReview.
|
||||
Expected: L-hint suggerimento scompare automaticamente.
|
||||
Why human: Richiede interazione multi-step con la UI live.
|
||||
|
||||
**4. Cache disco sopravvive al riavvio container**
|
||||
|
||||
Test: Generazione con Unsplash, riavvio container Docker, seconda generazione con stesse keyword.
|
||||
Expected: Log mostrano Cache Unsplash caricata all-avvio e Cache hit durante la seconda risoluzione.
|
||||
Why human: Richiede accesso ai log del container Docker su VPS.
|
||||
|
||||
## Gaps Summary
|
||||
|
||||
Nessun gap trovato. Tutti gli artifact della fase 4 esistono, sono sostanziali e correttamente collegati.
|
||||
|
||||
La seconda parte del goal ROADMAP (Swipe File context injection) e stata esplicitamente esclusa dallo scope dalla decisione documentata in 04-CONTEXT.md e classificata come Deferred v2. I 3 success criteria del ROADMAP per Phase 4 coprono esclusivamente l-integrazione Unsplash, completamente implementata.
|
||||
|
||||
---
|
||||
|
||||
_Verified: 2026-03-09T08:30:00Z_
|
||||
_Verifier: Claude Sonnet 4.6 (gsd-verifier)_
|
||||
|
||||
Reference in New Issue
Block a user