Compare commits
2
Commits
26d0b8569c
...
14c4c2a7d2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14c4c2a7d2 | ||
|
|
3b1d909e6e |
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
/** ingest_v2nav_kb.php — Re-ingest della guida UI V2 CORRETTA (sostituisce i chunk stale del 12/6). Idempotente. */
|
||||||
|
if (PHP_SAPI !== 'cli') { http_response_code(403); exit("CLI only\n"); }
|
||||||
|
require_once dirname(__DIR__).'/config/env.php';
|
||||||
|
require_once dirname(__DIR__).'/config/config.php';
|
||||||
|
require_once dirname(__DIR__).'/config/database.php';
|
||||||
|
require_once dirname(__DIR__).'/services/EmbedService.php';
|
||||||
|
require_once dirname(__DIR__).'/services/VectorService.php';
|
||||||
|
function logln($m){ echo '['.date('H:i:s')."] $m\n"; }
|
||||||
|
function uuid(){ $b=random_bytes(16); $b[6]=chr((ord($b[6])&0x0f)|0x40); $b[8]=chr((ord($b[8])&0x3f)|0x80); return vsprintf('%s%s-%s-%s-%s-%s%s%s',str_split(bin2hex($b),4)); }
|
||||||
|
function chunkText($t,$size=2000,$ov=200){ $c=[];$len=mb_strlen($t,'UTF-8');$s=0; while($s<$len){$take=min($size,$len-$s);$p=mb_substr($t,$s,$take,'UTF-8');if(trim($p)!=='')$c[]=$p;if($s+$take>=$len)break;$s+=($size-$ov);} return $c; }
|
||||||
|
$SOURCE='NIS2 Agile — Guida interfaccia V2 (Bootstrap Italia)';
|
||||||
|
$TITLE ='Interfaccia V2 NIS2 Agile — navigazione e moduli';
|
||||||
|
$f=__DIR__.'/_v2nav.md'; if(!is_file($f)){ exit("doc mancante\n"); }
|
||||||
|
$text=preg_replace('/\n{3,}/',"\n\n",trim((string)file_get_contents($f)));
|
||||||
|
$chunks=chunkText($text);
|
||||||
|
logln("testo ".strlen($text)." char -> ".count($chunks)." chunk");
|
||||||
|
$embed=new EmbedService(); $vector=new VectorService(); $vector->ensureCollection($embed->dims);
|
||||||
|
try{ $vector->deleteByFilter(['must'=>[['key'=>'scope','match'=>['value'=>'SYSTEM']],['key'=>'source','match'=>['value'=>$SOURCE]]]]); logln("rimossi chunk stale per source"); }catch(Throwable $e){ logln("warn delete: ".$e->getMessage()); }
|
||||||
|
$du=uuid(); $pts=[];
|
||||||
|
foreach($chunks as $i=>$ck){ $v=null; for($t=1;$t<=5;$t++){ try{$v=$embed->embed($ck);break;}catch(Throwable $e){ if($t==5)throw $e; sleep($t);} }
|
||||||
|
$pts[]=['id'=>uuid(),'vector'=>$v,'payload'=>['doc_uuid'=>$du,'title'=>$TITLE.($i>0?' (parte '.($i+1).')':''),'chunk'=>$ck,'entity_type'=>'guida_prodotto','source'=>$SOURCE,'lang'=>'it','scope'=>'SYSTEM','consulting_firm_id'=>null,'organization_id'=>null,'shared_with_orgs'=>[],'uploaded_by'=>0]]; }
|
||||||
|
foreach(array_chunk($pts,64) as $b) $vector->upsertBatch($b);
|
||||||
|
logln("upsert OK: ".count($pts)." chunk SYSTEM");
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
/** migrate_062_feedback_provenance.php — version-provenance su feedback_reports (std feedback-version-provenance). IDEMPOTENTE. */
|
||||||
|
if (PHP_SAPI !== 'cli') { http_response_code(403); exit("CLI only\n"); }
|
||||||
|
require_once __DIR__.'/../config/env.php'; require_once __DIR__.'/../config/database.php';
|
||||||
|
$pdo=Database::getInstance(); $db=$pdo->query('SELECT DATABASE()')->fetchColumn();
|
||||||
|
function addc($p,$db,$t,$c,$ddl){ $s=$p->prepare("SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=? AND TABLE_NAME=? AND COLUMN_NAME=?"); $s->execute([$db,$t,$c]); if($s->fetchColumn()){echo " = $t.$c\n";return;} $p->exec("ALTER TABLE `$t` ADD COLUMN $ddl"); echo " + $t.$c\n"; }
|
||||||
|
echo "Mig 062 — version-provenance feedback_reports\n";
|
||||||
|
addc($pdo,$db,'feedback_reports','client_surface',"client_surface VARCHAR(16) NULL");
|
||||||
|
addc($pdo,$db,'feedback_reports','client_version',"client_version VARCHAR(32) NULL");
|
||||||
|
addc($pdo,$db,'feedback_reports','client_build', "client_build VARCHAR(64) NULL");
|
||||||
|
echo "FATTO. Prossima mig=063.\n";
|
||||||
@@ -40,6 +40,10 @@ class FeedbackController extends BaseController
|
|||||||
$descrizione = trim($body['descrizione'] ?? '');
|
$descrizione = trim($body['descrizione'] ?? '');
|
||||||
$pageUrl = trim($body['page_url'] ?? '');
|
$pageUrl = trim($body['page_url'] ?? '');
|
||||||
$attachment = $body['attachment'] ?? null; // base64 string
|
$attachment = $body['attachment'] ?? null; // base64 string
|
||||||
|
// version-provenance (std feedback-version-provenance): superficie + release REALE del prodotto + build
|
||||||
|
$clientSurface = substr(trim((string) ($body['client_surface'] ?? '')), 0, 16) ?: null;
|
||||||
|
$clientVersion = substr(trim((string) ($body['client_version'] ?? '')), 0, 32) ?: null;
|
||||||
|
$clientBuild = substr(trim((string) ($body['client_build'] ?? '')), 0, 64) ?: null;
|
||||||
|
|
||||||
if (strlen($descrizione) < 10) {
|
if (strlen($descrizione) < 10) {
|
||||||
$this->jsonError('Descrizione troppo breve (minimo 10 caratteri).', 422);
|
$this->jsonError('Descrizione troppo breve (minimo 10 caratteri).', 422);
|
||||||
@@ -67,6 +71,9 @@ class FeedbackController extends BaseController
|
|||||||
'descrizione' => $descrizione,
|
'descrizione' => $descrizione,
|
||||||
'page_url' => $pageUrl,
|
'page_url' => $pageUrl,
|
||||||
'attachment' => $attachment,
|
'attachment' => $attachment,
|
||||||
|
'client_surface' => $clientSurface,
|
||||||
|
'client_version' => $clientVersion,
|
||||||
|
'client_build' => $clientBuild,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -45,14 +45,19 @@ class FeedbackService
|
|||||||
$descrizione = $data['descrizione'] ?? '';
|
$descrizione = $data['descrizione'] ?? '';
|
||||||
$pageUrl = $data['page_url'] ?? '';
|
$pageUrl = $data['page_url'] ?? '';
|
||||||
$attachment = $data['attachment'] ?? null;
|
$attachment = $data['attachment'] ?? null;
|
||||||
|
$clientSurface = $data['client_surface'] ?? null;
|
||||||
|
$clientVersion = $data['client_version'] ?? null;
|
||||||
|
$clientBuild = $data['client_build'] ?? null;
|
||||||
|
|
||||||
Database::query(
|
Database::query(
|
||||||
'INSERT INTO feedback_reports
|
'INSERT INTO feedback_reports
|
||||||
(organization_id, user_id, user_email, user_role, page_url,
|
(organization_id, user_id, user_email, user_role, page_url,
|
||||||
tipo, priorita, descrizione, attachment)
|
tipo, priorita, descrizione, attachment,
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
client_surface, client_version, client_build)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||||
[$orgId, $userId, $userEmail, $userRole, $pageUrl,
|
[$orgId, $userId, $userEmail, $userRole, $pageUrl,
|
||||||
$tipo, $priorita, $descrizione, $attachment]
|
$tipo, $priorita, $descrizione, $attachment,
|
||||||
|
$clientSurface, $clientVersion, $clientBuild]
|
||||||
);
|
);
|
||||||
|
|
||||||
$reportId = (int) Database::lastInsertId();
|
$reportId = (int) Database::lastInsertId();
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
-- 062_feedback_version_provenance.sql — version-provenance sulle segnalazioni (std feedback-version-provenance v1.0)
|
||||||
|
-- Record DDL. Apply autoritativo idempotente: application/cli/migrate_062_feedback_provenance.php
|
||||||
|
ALTER TABLE feedback_reports ADD COLUMN client_surface VARCHAR(16) NULL; -- web-v1|web-v2|android|ios
|
||||||
|
ALTER TABLE feedback_reports ADD COLUMN client_version VARCHAR(32) NULL; -- release REALE del prodotto (NON la versione del widget)
|
||||||
|
ALTER TABLE feedback_reports ADD COLUMN client_build VARCHAR(64) NULL;
|
||||||
@@ -44,6 +44,7 @@
|
|||||||
let _currentReportId = null;
|
let _currentReportId = null;
|
||||||
let _attachmentBase64 = null;
|
let _attachmentBase64 = null;
|
||||||
let _myReports = [];
|
let _myReports = [];
|
||||||
|
let _appVer = null; // version-provenance: release REALE del prodotto (da /version.json)
|
||||||
|
|
||||||
// ── Init ──────────────────────────────────────────────────────────────────
|
// ── Init ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -360,12 +361,18 @@
|
|||||||
|
|
||||||
_setSubmitting(true);
|
_setSubmitting(true);
|
||||||
|
|
||||||
|
// version-provenance: release REALE del prodotto + superficie + build (std feedback-version-provenance)
|
||||||
|
if (!_appVer) { try { _appVer = await (await fetch('/version.json?_=' + Date.now())).json(); } catch (e) { _appVer = {}; } }
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
tipo,
|
tipo,
|
||||||
priorita,
|
priorita,
|
||||||
descrizione,
|
descrizione,
|
||||||
page_url: pageUrl,
|
page_url: pageUrl,
|
||||||
attachment: _attachmentBase64 || null,
|
attachment: _attachmentBase64 || null,
|
||||||
|
client_surface: 'web-v2',
|
||||||
|
client_version: (_appVer && _appVer.version) || null,
|
||||||
|
client_build: (_appVer && _appVer.build) || null,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
{"version": "1.24.3", "build": "2026-06-20-v1.24.3", "date": "2026-06-20", "changelog": "Allineamento help/traduzioni/AI per la gestione documentale SGSI: (1) Help contestuale — aggiunta in Impostazioni la sezione 'Permessi documentali (ciclo di vita SGSI)' e completata la guida del Modello SGSI su editor, download Word singolo/unico e ciclo di vita; (2) Traduzioni — matrice Permessi documentali resa bilingue IT/EN (azioni, ruoli, suggerimenti); (3) AI/KB — ingerito nella knowledge base RAG (nis2_kb, scope SYSTEM) il documento 'Gestione documentale SGSI' (ciclo di vita, export Word, editor, permessi), cosi' l'assistente puo' guidare l'utente su queste funzioni."}
|
{"version": "1.24.4", "build": "2026-06-20-v1.24.4", "date": "2026-06-20", "changelog": "Version-provenance sulle segnalazioni (standard feedback-version-provenance): la tabella feedback_reports ora salva client_surface (web-v2), client_version (release reale del prodotto) e client_build; il backend (FeedbackController/FeedbackService) li persiste e il widget di segnalazione (feedback.js) li invia leggendo /version.json. Migrazione 062. Re-ingest nella KB della guida UI V2 corretta (sostituiti i chunk stale)."}
|
||||||
|
|||||||
Reference in New Issue
Block a user