[FEAT] Sistema Segnalazioni & Risoluzione AI (feedback)
Adattato da alltax.it — il sistema più maturo testato con utenti reali.
Backend:
- FeedbackController: 6 endpoint (submit, mine, list, show, update, resolve)
- FeedbackService: createReport + classifyWithAI + broadcastResolution
- AIService::classifyFeedback() — 10s timeout, 500 token, JSON puro
- EmailService::sendFeedbackResolved() — broadcast email org
- DB migration 014: tabella feedback_reports
Frontend:
- feedback.js: FAB rosso #EF4444, modal 2 fasi (form → AI → password gate)
- Tab "Le mie segnalazioni" con badge status
- Auto-init su tutte le pagine autenticate (common.js::checkAuth)
- api.js: 6 metodi client; style.css: stili completi
Worker:
- scripts/feedback-worker.php: cron ogni 30 min
→ docker exec nis2-agile-devenv + Claude Code CLI
→ risoluzione autonoma con POST /api/feedback/{id}/resolve
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
3b51b5bd95
commit
1382530189
@@ -310,6 +310,77 @@ PROMPT;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Classifica una segnalazione feedback/bug per il sistema di ticketing interno
|
||||
*
|
||||
* @param string $tipo Tipo segnalazione (bug|ux|funzionalita|domanda|altro)
|
||||
* @param string $descrizione Testo della segnalazione (non contiene PII org)
|
||||
* @return array ['categoria', 'priorita', 'suggerimento', 'risposta_utente']
|
||||
*/
|
||||
public function classifyFeedback(string $tipo, string $descrizione): array
|
||||
{
|
||||
$prompt = <<<PROMPT
|
||||
Sei un assistente tecnico per una piattaforma SaaS di compliance NIS2.
|
||||
Analizza la seguente segnalazione e rispondi SOLO con un oggetto JSON valido.
|
||||
|
||||
Tipo segnalazione: {$tipo}
|
||||
Descrizione: {$descrizione}
|
||||
|
||||
Rispondi con questo JSON (senza markdown, solo JSON puro):
|
||||
{
|
||||
"categoria": "una tra: autenticazione, dashboard, rischi, incidenti, policy, assessment, formazione, fornitori, asset, report, impostazioni, performance, interfaccia, documentazione, altro",
|
||||
"priorita": "una tra: alta, media, bassa",
|
||||
"suggerimento": "suggerimento tecnico breve per il team di sviluppo (max 150 caratteri)",
|
||||
"risposta_utente": "risposta leggibile e rassicurante per l'utente finale in italiano (max 200 caratteri)"
|
||||
}
|
||||
|
||||
Criteri priorità:
|
||||
- alta: blocca funzionalità critica (compliance, accesso, salvataggio dati)
|
||||
- media: degrada l'esperienza ma esiste un workaround
|
||||
- bassa: miglioria estetica o funzionalità secondaria
|
||||
PROMPT;
|
||||
|
||||
$ch = curl_init($this->baseUrl);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Content-Type: application/json',
|
||||
'x-api-key: ' . $this->apiKey,
|
||||
'anthropic-version: 2023-06-01',
|
||||
],
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => json_encode([
|
||||
'model' => $this->model,
|
||||
'max_tokens' => 500,
|
||||
'system' => 'Sei un assistente tecnico. Rispondi SEMPRE con JSON puro, senza markdown né testo aggiuntivo.',
|
||||
'messages' => [['role' => 'user', 'content' => $prompt]],
|
||||
]),
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 10,
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$curlError = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($curlError || $httpCode !== 200) {
|
||||
throw new RuntimeException("classifyFeedback AI error [{$httpCode}]: {$curlError}");
|
||||
}
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$text = $data['content'][0]['text'] ?? '';
|
||||
|
||||
$result = $this->parseJsonResponse($text);
|
||||
|
||||
// Normalizza priorità
|
||||
$validP = ['alta', 'media', 'bassa'];
|
||||
if (!in_array($result['priorita'] ?? '', $validP)) {
|
||||
$result['priorita'] = 'media';
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analisi cross-organizzazione per consulenti (L4)
|
||||
* Riceve dati già aggregati e anonimizzati dal controller.
|
||||
|
||||
Reference in New Issue
Block a user