# Assistente AI: import intelligente, calendario da una frase, relazione di lezione

Status: validated (15/09/2026)

## Context

Gli enti perdono tempo a ricopiare elenchi di discenti, creare lezioni una per una e scrivere note per il registro.
Piano in `docs/ai/piano-ai.md`. Driver `fake` deterministico in locale, `anthropic` in produzione.

## Requirements

- Servizio `App\Services\Ai\AiClient` con driver `fake` e `anthropic` (Messages API, tool-use per JSON), log in `ai_usages`.
- Parsing e validazione del codice fiscale (deterministico) con estrazione di data di nascita, sesso, codice comune.
- Import intelligente da testo incollato con anteprima e conferma.
- Generazione del calendario lezioni da una frase, con anteprima e conferma, entro i limiti dell'aula.
- Relazione di lezione (anomalie + nota) generata a fine lezione e rigenerabile.
- Spiegazione in italiano degli errori Forma.Temp sui sync falliti.
- Vetrina aggiornata con la sezione AI, FAQ e riga in tabella prezzi.

## Acceptance criteria

1. `POST /classrooms/{id}/participants/ai-parse` con `text = "Rossi Mario RSSMRA80A01H501U mario@x.it\nBianchi Anna BNCNNA85M41F205Z"` (driver fake) risponde 200 con `rows` di 2 elementi, `rows[0].fiscal_code = "RSSMRA80A01H501U"`, `rows[1].birth_date = "1985-08-01"`, `rows[1].gender = "F"`.
2. `POST /classrooms/{id}/participants` con `fiscal_code = "RSSMRA80A01H501U"` salva `birth_date = 1980-01-01`, `gender = M`, `birth_place_code = H501`; con un CF con checksum errato risponde 422 sul campo `fiscal_code`.
3. `POST /classrooms/{id}/meetings/ai-plan` con `prompt = "3 lezioni di 2 ore, lunedì e mercoledì dalle 9, dal 6 ottobre 2026"` (fake) risponde 200 con 3 lezioni: 2026-10-06 09:00, 2026-10-07 09:00, 2026-10-12 09:00, `duration_minutes = 120`; `POST /classrooms/{id}/meetings/bulk` con quelle lezioni le crea e la pagina aula le elenca.
4. Per una lezione terminata con un partecipante presente 1h su 2h e un altro presente 2h, `POST /meetings/{id}/ai-report` (fake) salva `meetings.ai_report.anomalies` con un elemento di tipo `below_threshold` per il primo partecipante e una `note` non vuota; `GET /meetings/{id}` espone `ai_report` nelle props.
5. Un `FormatempSync` che fallisce con messaggio "koMessages: Partecipante non trovato" riceve `explanation` non vuota (fake) visibile nella pagina aula.
6. GET / contiene la sezione con id `assistente` e il testo "Import intelligente"; GET /prezzi contiene "Assistente AI"; `npm run types:check && npm run check && npm run build` e `composer test` passano.

## Out of scope

Trascrizione registrazioni, chat assistente, controllo conformità pre-consolidamento, budget per cliente in UI.
