Phase 03: Organization Layer - 2 plan(s) in 2 wave(s) - Wave 1: SwipeService CRUD + API + UI (parallel-ready) - Wave 2: Swipe-to-calendar integration (depends on 03-01) - Ready for execution Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
9.1 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | must_haves | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 03-organization-layer | 02 | execute | 2 |
|
|
true |
|
Purpose: Permette all'utente di usare idee catturate nello Swipe File come topic pre-assegnati nel calendario, combinando l'ispirazione spontanea con la generazione strategica. Output: Sezione "Topic Override" nel form Genera Calendario con picker modale da Swipe File, invio degli override alla generazione bulk.
<execution_context> @C:\Users\miche.claude/get-shit-done/workflows/execute-plan.md @C:\Users\miche.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/03-organization-layer/03-CONTEXT.md @.planning/phases/03-organization-layer/03-01-SUMMARY.md Task 1: Backend — topic_overrides in CalendarRequest + pipeline wiring backend/schemas/calendar.py backend/services/generation_pipeline.py **1. Aggiorna `backend/schemas/calendar.py`** — Aggiungi campo `topic_overrides` a `CalendarRequest`:topic_overrides: Optional[dict[int, str]] = Field(
default=None,
description="Override topic per slot specifici. Chiave: indice slot (0-12), valore: topic. "
"Gli slot con override skipperanno la generazione topic LLM.",
)
Questo campo e' un dizionario {slot_index: topic_string}. Esempio: {2: "3 errori che costano clienti", 7: "Case study dentista Milano"}.
2. Aggiorna backend/services/generation_pipeline.py — Nel metodo che genera i topic per ogni slot (dentro generate_bulk_async o il metodo chiamato da esso), dopo aver creato i CalendarSlot:
- Se
request.topic_overridesesiste e contiene l'indice dello slot corrente, usa il topic override invece di chiamare l'LLM per generare il topic. - Applica il topic override al campo
slot.topicdello slot corrispondente. - La logica e':
if topic_overrides and slot.indice in topic_overrides: slot.topic = topic_overrides[slot.indice]— skip la chiamata LLM per generare il topic per quello slot.
Assicurarsi che il campo topic venga applicato PRIMA della generazione del contenuto del carosello, perche' il topic viene passato al prompt LLM.
Pattern: Leggere attentamente generation_pipeline.py per capire dove i topic vengono generati/assegnati e inserire l'override nel punto giusto del flusso.
python -c "from backend.schemas.calendar import CalendarRequest; r = CalendarRequest(obiettivo_campagna='Test obiettivo campagna', topic_overrides={0: 'Test topic'}); print(r.topic_overrides)"stampa{0: 'Test topic'}python -c "from backend.services.generation_pipeline import GenerationPipeline; print('OK')"importa senza errori- CalendarRequest accetta
topic_overridesopzionale (dict[int, str]) - GenerationPipeline applica topic override agli slot corrispondenti prima della generazione LLM
- Slot senza override continuano a funzionare come prima (topic generato dall'LLM)
export interface CalendarRequest {
obiettivo_campagna: string
settimane?: number
nicchie?: string[] | null
frequenza_post?: number
data_inizio?: string | null
topic_overrides?: Record<number, string> | null // slot_index -> topic
}
2. Aggiungi hook useMarkSwipeUsed in frontend/src/api/hooks.ts (nella sezione Swipe File):
export function useMarkSwipeUsed() {
const queryClient = useQueryClient()
return useMutation<SwipeItem, Error, string>({
mutationFn: (id) => apiPost<SwipeItem>(`/swipe/${id}/mark-used`),
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['swipe'] }) },
})
}
3. Modifica frontend/src/pages/GenerateCalendar.tsx — Aggiungi sezione "Topic Override dallo Swipe File":
Nuovo state:
const [topicOverrides, setTopicOverrides] = useState<Record<number, { topic: string; swipeId: string }>>({})
const [showSwipePicker, setShowSwipePicker] = useState<number | null>(null) // slot index attivo
Sezione UI — Aggiungere DOPO il campo "Tono di voce" e PRIMA del checkbox Nicchie:
- Titolo: "Topic Override (opzionale)" con sottotitolo "Seleziona topic dallo Swipe File per slot specifici"
- Griglia 13 slot (indici 0-12), ognuno con:
- Label: "Slot {N+1}" (1-based per utente)
- Se override assegnato: mostra topic troncato + bottone X per rimuovere override
- Se nessun override: bottone piccolo "Da Swipe File" (icona Lightbulb) per aprire il picker
- Il picker e' un pannello/dropdown che appare inline sotto lo slot cliccato:
- Mostra lista idee dallo Swipe File (via
useSwipeItems) - Ogni idea mostra: topic, nicchia badge, badge "usato" se gia' usata
- Click su un'idea: assegna il topic allo slot, chiude picker, chiama
useMarkSwipeUsed(swipeId) - Bottone "Chiudi" per chiudere senza selezionare
- Se Swipe File vuoto: messaggio "Nessuna idea nel tuo Swipe File" con link a
/swipe-file
- Mostra lista idee dallo Swipe File (via
Modifica handleSubmit — Includi topic_overrides nella request:
const req: CalendarRequest = {
obiettivo_campagna: obiettivo.trim(),
settimane,
frequenza_post: settings?.frequenza_post ?? 3,
nicchie: customNicchie ? settings?.nicchie_attive : undefined,
topic_overrides: Object.keys(topicOverrides).length > 0
? Object.fromEntries(
Object.entries(topicOverrides).map(([k, v]) => [parseInt(k), v.topic])
)
: undefined,
}
Stile UI:
- La griglia dei 13 slot usa un layout compatto: 3-4 colonne su desktop, 1 su mobile
- Ogni slot e' una mini-card stone-800 con bordo stone-700
- Slot con override: bordo amber-500/30, background amber-500/5
- Il picker inline usa la stessa palette stone/amber
- Animazione ingresso/uscita non necessaria — keep it simple
cd frontend && npx tsc --noEmit— nessun errore TypeScriptcd frontend && npm run build— build pulita- CalendarRequest in types.ts include
topic_overrides - hooks.ts contiene
useMarkSwipeUsed - GenerateCalendar.tsx importa
useSwipeItemseuseMarkSwipeUsed - Il form Genera Calendario mostra 13 slot con possibilita' di assegnare topic override dallo Swipe File
- Click "Da Swipe File" apre picker inline con lista idee
- Selezione di un'idea assegna il topic allo slot e marca l'idea come "usata"
- Override rimovibili con bottone X
- Gli override vengono passati come
topic_overridesnella CalendarRequest alla generazione bulk - TypeScript compila senza errori
<success_criteria>
- L'utente puo' selezionare topic dallo Swipe File per slot specifici nel form Genera Calendario
- I topic selezionati vengono visualizzati nella griglia slot prima della generazione
- I topic override vengono inviati alla generazione bulk via CalendarRequest.topic_overrides
- L'idea Swipe File selezionata viene marcata come "usata" con badge visivo
- Gli override sono rimovibili (bottone X) prima di avviare la generazione
- Slot senza override continuano a generare topic automaticamente via LLM </success_criteria>