Files
Michele 05988f4be5 docs(03): create phase plan
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>
2026-03-08 23:21:41 +01:00

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
03-01
frontend/src/pages/GenerateCalendar.tsx
frontend/src/api/hooks.ts
true
truths artifacts key_links
L'utente puo' aprire un picker dallo Swipe File nel form Genera Calendario e selezionare un topic come override per uno slot specifico
Dopo la selezione, l'idea nello Swipe File viene marcata come 'usata' con badge visivo
L'utente vede i topic override selezionati nel form prima di avviare la generazione
I topic override selezionati vengono passati alla generazione bulk e applicati agli slot corrispondenti
path provides contains
frontend/src/pages/GenerateCalendar.tsx Sezione override topic con picker da Swipe File integrato nel form swipe
from to via pattern
frontend/src/pages/GenerateCalendar.tsx /api/swipe useSwipeItems hook + useMarkSwipeUsed useSwipeItems|markUsed
from to via pattern
frontend/src/pages/GenerateCalendar.tsx /api/generate/bulk CalendarRequest with topic_overrides topic_overrides
Integrazione Swipe File nel form Genera Calendario: meccanismo per selezionare topic dallo Swipe File come override per slot specifici prima della generazione batch.

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_overrides esiste 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.topic dello 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_overrides opzionale (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)
Task 2: Frontend — Picker Swipe File nel form Genera Calendario + mark used frontend/src/pages/GenerateCalendar.tsx frontend/src/api/hooks.ts frontend/src/types.ts **1. Aggiorna `frontend/src/types.ts`** — Aggiungi `topic_overrides` a `CalendarRequest`:
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

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 TypeScript
  • cd frontend && npm run build — build pulita
  • CalendarRequest in types.ts include topic_overrides
  • hooks.ts contiene useMarkSwipeUsed
  • GenerateCalendar.tsx importa useSwipeItems e useMarkSwipeUsed
  • 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_overrides nella CalendarRequest alla generazione bulk
  • TypeScript compila senza errori
1. Frontend: `cd frontend && npx tsc --noEmit && npm run build` — build pulita 2. Backend: `python -c "from backend.schemas.calendar import CalendarRequest; print(CalendarRequest.model_fields.keys())"` include topic_overrides 3. CalendarRequest in types.ts include topic_overrides 4. GenerateCalendar.tsx ha griglia 13 slot con bottoni picker 5. Hook useMarkSwipeUsed presente in hooks.ts 6. La generazione bulk riceve e applica topic_overrides

<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>
After completion, create `.planning/phases/03-organization-layer/03-02-SUMMARY.md`