diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 07f5bc6..57dc46f 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -66,7 +66,7 @@ Plans: **Plans**: 2 plans Plans: -- [ ] 03-01-PLAN.md — SwipeService CRUD backend + Pydantic schemas + FastAPI router + pagina SwipeFile UI con form aggiunta, modifica inline, eliminazione con conferma, filtro nicchia (Wave 1) +- [x] 03-01-PLAN.md — SwipeService CRUD backend + Pydantic schemas + FastAPI router + pagina SwipeFile UI con form aggiunta, modifica inline, eliminazione con conferma, filtro nicchia (Wave 1) - [ ] 03-02-PLAN.md — Swipe-to-calendar integration: topic_overrides in CalendarRequest + picker Swipe File nel form Genera Calendario con mark-used (Wave 2) --- @@ -95,5 +95,5 @@ 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 | 0/2 | Not started | - | +| 3. Organization Layer | 1/2 | In progress | - | | 4. Enrichment | 0/1 | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 583a74f..fe64999 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -5,23 +5,23 @@ See: .planning/PROJECT.md (updated 2026-03-07) **Core value:** Generare un calendario di 13 caroselli Instagram strategicamente orchestrati, pronti per Canva Bulk Create, con un click dalla Web UI. -**Current focus:** Phase 2 COMPLETA — Prompt Control + Output Review +**Current focus:** Phase 3 — Organization Layer (Plan 1/2 completato) ## Current Position -Phase: 2 of 4 (Prompt Control + Output Review) -Plan: 2 of 2 in current phase — PHASE COMPLETE -Status: Phase 2 complete — ready for Phase 3 or deploy -Last activity: 2026-03-08 — Completed 02-02-PLAN.md (Per-item Regeneration + Summary Counter) +Phase: 3 of 4 (Organization Layer) +Plan: 1 of 2 in current phase — In progress +Status: In progress — Plan 03-01 completo, manca 03-02 +Last activity: 2026-03-09 — Completed 03-01-PLAN.md (SwipeService + pagina SwipeFile) -Progress: [██████░░░░] 66% (6/9 piani totali) +Progress: [███████░░░] 77% (7/9 piani totali) ## Performance Metrics **Velocity:** -- Total plans completed: 6 -- Average duration: ~7 min -- Total execution time: 42 min +- Total plans completed: 7 +- Average duration: ~6.5 min +- Total execution time: 47 min **By Phase:** @@ -29,10 +29,11 @@ Progress: [██████░░░░] 66% (6/9 piani totali) |-------|-------|-------|----------| | 01-core-generation-pipeline | 4/4 COMPLETA | 33 min | 8 min | | 02-prompt-control-output-review | 2/2 COMPLETA | 9 min | 4.5 min | +| 03-organization-layer | 1/2 In corso | 5 min | 5 min | **Recent Trend:** -- Last 5 plans: 9 min, 8 min, 10 min, 5 min, 4 min -- Trend: velocita' in aumento +- Last 5 plans: 8 min, 10 min, 5 min, 4 min, 5 min +- Trend: stabile intorno a 5 min *Updated after each plan completion* @@ -62,21 +63,26 @@ Recent decisions affecting current work: - [02-01]: PromptService init lazy via _get_prompt_service() per sincronizzazione con lifespan directory - [02-02]: Regen notes passate via campo tono in GenerateRequest (pragmatico, no backend changes) - [02-02]: Edit detection manuale via JSON.stringify comparison (trascurabile con 13 post) +- [03-01]: SwipeService lazy init identico a PromptService (DATA_PATH creato nel lifespan FastAPI) +- [03-01]: IDs brevi uuid4.hex[:12] — leggibili, no rischio collisione con volumi Swipe File +- [03-01]: PUT con comportamento PATCH-like per nicchia/note — None cancella il valore +- [03-01]: Filtro nicchia derivato dinamicamente da items (no config separata) ### Blockers/Concerns - [Phase 1]: Validare token usage reale per batch 13 post con claude-sonnet-4-5 — inter_request_delay=2.0s configurato, da validare in produzione - [Phase 1]: Baseline qualita' prompt italiani da validare dopo prima generazione reale -- [Deploy]: Phase 2 completa — serve vps-lab-deploy per testare end-to-end il sistema +- [Deploy]: Phase 2+3 plan1 complete — serve vps-lab-deploy per testare end-to-end il sistema +- [03-02]: La route `/swipe-file` e il hook `useSwipeItems` sono pronti per l'integrazione nel form Genera Calendario ## Session Continuity -Last session: 2026-03-08 -Stopped at: Completed 02-02-PLAN.md (Per-item Regeneration + Summary Counter) — Phase 2 COMPLETE +Last session: 2026-03-09 +Stopped at: Completed 03-01-PLAN.md (SwipeService + SwipeFile UI) — Plan 1/2 Phase 3 Resume file: None ## Next Actions -1. `vps-lab-deploy` per deployare su VPS e testare end-to-end -2. Pianificare Phase 3 (Canva-ready CSV polish + advanced export) -3. Eseguire Phase 3 +1. Eseguire 03-02-PLAN.md (Swipe-to-calendar integration: topic_overrides + picker Swipe File) +2. `vps-lab-deploy` per deployare su VPS e testare end-to-end il sistema +3. Pianificare Phase 4 (Enrichment: Unsplash integration) diff --git a/.planning/phases/03-organization-layer/03-01-SUMMARY.md b/.planning/phases/03-organization-layer/03-01-SUMMARY.md new file mode 100644 index 0000000..30b5247 --- /dev/null +++ b/.planning/phases/03-organization-layer/03-01-SUMMARY.md @@ -0,0 +1,130 @@ +--- +phase: 03 +plan: 01 +subsystem: organization-layer +tags: [swipe-file, fastapi, pydantic, tanstack-query, react, json-persistence, crud] +requires: + - 01-01 (FastAPI skeleton + React SPA + Docker) + - 01-04 (Web UI con palette stone/amber) + - 02-01 (pattern lazy init PromptService) +provides: + - SwipeService CRUD su data/swipe_file.json + - 5 endpoint REST /api/swipe (list, add, update, delete, mark-used) + - Pagina SwipeFile UI con form, filtro nicchia, modifica inline, eliminazione con conferma + - TanStack Query hooks per CRUD swipe +affects: + - 03-02 (Swipe-to-calendar integration: useSwipeItems per picker nel form Genera Calendario) + - 04-01 (Enrichment: mark-used per tracking utilizzo topic) +tech-stack: + added: [] + patterns: + - lazy-init singleton (stessa tecnica di PromptService) + - json-file persistence (lista di dict, no ORM) + - controlled inline editing (editingId + editForm state) + - filter chips pattern (filterNicchia state + uniqueNicchie derived) +key-files: + created: + - backend/schemas/swipe.py + - backend/services/swipe_service.py + - backend/routers/swipe.py + - frontend/src/pages/SwipeFile.tsx + modified: + - backend/main.py + - frontend/src/types.ts + - frontend/src/api/hooks.ts + - frontend/src/components/Sidebar.tsx + - frontend/src/App.tsx +key-decisions: + - "SwipeService lazy init identico a PromptService (DATA_PATH creato nel lifespan FastAPI)" + - "IDs brevi uuid4.hex[:12] per comodita' nei log e nei test" + - "update_item non sovrascrive nicchia/note con None se il campo non e' nel payload — comportamento PATCH-like via PUT" + - "apiFetch importato esplicitamente in hooks.ts per il DELETE (non coperto da apiGet/apiPost/apiPut)" + - "Filtro nicchia derivato da items esistenti (no configurazione separata)" +metrics: + duration: "5 min" + completed: "2026-03-09" +--- + +# Phase 3 Plan 01: SwipeService CRUD + pagina SwipeFile UI completa + +**One-liner:** SwipeService CRUD su JSON + 5 endpoint REST FastAPI + pagina SwipeFile con form, filtro nicchia, modifica inline e dialog conferma eliminazione. + +## Performance + +- **Duration:** ~5 min +- **Tasks:** 2/2 completati +- **Deviations:** 1 (regola 3 — bug fix import) + +## Accomplishments + +1. **SwipeService** — CRUD completo su `data/swipe_file.json` con ordinamento cronologico inverso, ID brevi, timestamp ISO UTC, mark_used +2. **Backend FastAPI** — 5 endpoint REST (`GET /`, `POST /`, `PUT /{id}`, `DELETE /{id}`, `POST /{id}/mark-used`), lazy init, error handling con ValueError → 404 +3. **Frontend types** — 4 interfacce TypeScript (`SwipeItem`, `SwipeItemCreate`, `SwipeItemUpdate`, `SwipeListResponse`) allineate agli schemi Pydantic +4. **TanStack Query hooks** — 4 hook (`useSwipeItems`, `useAddSwipeItem`, `useUpdateSwipeItem`, `useDeleteSwipeItem`) con invalidazione cache +5. **Pagina SwipeFile** — Form aggiunta rapida inline, lista con `SwipeCard`, filtro per nicchia via chip, modifica inline con `editingId` state, dialog conferma eliminazione, badge "Usato", data relativa senza librerie +6. **Navigazione** — Voce "Swipe File" con `Lightbulb` icon aggiunta alla Sidebar tra Prompt Editor e Impostazioni +7. **Route** — `/swipe-file` registrata in App.tsx + +## Task Commits + +| Task | Name | Commit | Files | +|------|------|--------|-------| +| 1 | Backend SwipeService + schemas + router | d64c7f4 | backend/schemas/swipe.py, backend/services/swipe_service.py, backend/routers/swipe.py, backend/main.py | +| 2 | Frontend SwipeFile UI + hooks + navigazione | d379789 | frontend/src/pages/SwipeFile.tsx, frontend/src/types.ts, frontend/src/api/hooks.ts, frontend/src/components/Sidebar.tsx, frontend/src/App.tsx | + +## Files Created + +| File | Scopo | +|------|-------| +| `backend/schemas/swipe.py` | Pydantic models: SwipeItem, SwipeItemCreate, SwipeItemUpdate, SwipeListResponse | +| `backend/services/swipe_service.py` | SwipeService: _load/_save/list_items/add_item/update_item/delete_item/mark_used | +| `backend/routers/swipe.py` | FastAPI router: 5 endpoint REST, lazy init, ValueError -> 404 | +| `frontend/src/pages/SwipeFile.tsx` | Pagina completa con form, lista, filtro, edit inline, delete confirm | + +## Files Modified + +| File | Modifica | +|------|----------| +| `backend/main.py` | Aggiunto import swipe router e `app.include_router(swipe.router)` | +| `frontend/src/types.ts` | Aggiunta sezione Swipe File con 4 interfacce TypeScript | +| `frontend/src/api/hooks.ts` | Aggiunta sezione Swipe File con 4 hook TanStack Query + import `apiFetch` | +| `frontend/src/components/Sidebar.tsx` | Aggiunto import `Lightbulb` e voce nav "Swipe File" | +| `frontend/src/App.tsx` | Aggiunto import `SwipeFile` e `` | + +## Decisions Made + +| Decisione | Motivo | Data | +|-----------|--------|------| +| Lazy init SwipeService identico a PromptService | DATA_PATH creato nel lifespan FastAPI, non al momento dell'import | 2026-03-09 | +| IDs brevi `uuid4.hex[:12]` | Leggibili nei log, non c'e' rischio collisione con volumi Swipe File | 2026-03-09 | +| PUT con comportamento PATCH-like per nicchia/note | Permette di cancellare il valore passando None esplicito, senza sovrascrivere campi omessi | 2026-03-09 | +| Filtro nicchia derivato dinamicamente da items | No configurazione separata, sempre allineato ai dati reali | 2026-03-09 | +| Nessuna libreria per data relativa | Logica semplice basata su differenza ms, riduce bundle size | 2026-03-09 | + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 3 - Blocking] Import mancante di `apiFetch` in hooks.ts** + +- **Found during:** Verifica build frontend (Task 2) +- **Issue:** `useDeleteSwipeItem` usava `apiFetch` che non era importato dal modulo `./client` +- **Fix:** Aggiunto `apiFetch` all'import esistente in `hooks.ts` (riga 13) +- **Files modified:** `frontend/src/api/hooks.ts` +- **Commit:** d379789 (incluso nel commit del task, non separato) + +## Issues Encountered + +Nessun problema bloccante. La build frontend al primo tentativo ha rilevato il missing import `apiFetch`, risolto immediatamente (deviation Rule 3). + +## Next Phase Readiness + +**Phase 3 Plan 02 (Swipe-to-calendar integration):** +- `useSwipeItems()` hook disponibile per il picker nel form Genera Calendario +- `mark_used` endpoint pronto per segnare topic usati +- Interfacce TypeScript `SwipeItem` disponibili in `types.ts` + +**Dipendenze soddisfatte:** +- SwipeService stabile e testato con import check Python +- Build frontend pulita (TypeScript + Vite) +- 5 endpoint REST registrati e accessibili