Files
ThothII/docs/plans/2026-08-26-metadata-catalog-from-thothai.md
T

37 KiB

Metadata Catalog di ThothII: ricognizione ThothAI e percorso incrementale

Data: 2026-08-26; aggiornato 2026-08-27 Stato: ricognizione e progettazione completate; navigazione, CRUD Workspace Database, Catalog Table, Catalog Column, Catalog Relationship e sincronizzazione durevole dello schema implementati il 2026-08-27. Generazione AI e integrazione con il workflow core restano negli step successivi.

Obiettivo

ThothII deve introdurre un contesto amministrativo separato, il Metadata Catalog, per gestire il database associato a ciascun workspace, la sua struttura fisica introspezionata e i metadati semantici oggi rappresentati da schema/annotations.yaml.

Il programma procede per step indipendenti. Il primo step ha aggiunto l'accesso dalla sidebar; il secondo ha sostituito la superficie vuota con il CRUD di configurazione, il PostgreSQL interno e i test di connessione; gli step successivi hanno aggiunto navigazione gerarchica, colonne, relazioni fisiche e sincronizzazione durevole dell'intero schema. Non introduce ancora generazione AI o integrazione con il workflow core.

Questa analisi usa come riferimento il working tree legacy osservato in Thoth/ThothAI. Non è stato verificato che quel contenuto corrisponda a una release o a un tag canonico; i percorsi e i comportamenti descrivono il sorgente disponibile il 2026-08-26.

Decisioni già confermate

  1. Ogni Workspace Database appartiene a un solo workspace tramite un workspace_id obbligatorio e univoco; un workspace può avere al massimo un Workspace Database. Poiché i workspace non sono righe del catalogo PostgreSQL, l'associazione è un riferimento logico validato contro thoth-workspaces.yaml, non una foreign key SQL.
  2. Il CRUD non crea né rinomina workspace. Identità e lista ordinata dei workspace restano autorevoli in thoth-workspaces.yaml; il catalogo conserva il loro identificatore stabile.
  3. La struttura fisica viene acquisita interrogando il database esterno tramite i dati di connessione registrati per il Workspace Database.
  4. I contenuti semantici equivalenti a annotations.yaml vengono generati con l'AI e conservati nel PostgreSQL interno.
  5. Per PSD è prevista l'importazione delle annotations esistenti. Gli altri database partiranno dalla struttura introspezionata e genereranno i metadati semantici da zero.
  6. annotations.yaml sarà sostituito anche come input del core in uno step futuro. Il repository è in fase di test e non è richiesta la conservazione delle sessioni esistenti durante il cutover.
  7. La gestione catalogo resta una superficie separata dal processo NL→SQL. La futura integrazione deve essere esplicita e non deve modificare fasi, gate o semantica del workflow.
  8. Il link iniziale è visibile agli utenti con workspace.manage, usa stato React locale e non introduce un router.
  9. La pagina iniziale è vuota, segue il tema, nasconde l'intera colonna core e non interrompe una sessione live. Le azioni di apertura, resume o creazione sessione riportano al core.
  10. La compatibilità con il modello ThothAI è semantica, non una copia letterale: configurazione e contenuti semantici sono campi relazionali mutabili, mentre identità e appartenenza della struttura fisica derivano dall'introspezione; i segreti restano nel secret store e lo stato dei job non viene mescolato ai dati amministrativi.
  11. Il CRUD amministra il Metadata Catalog e non esegue DDL sul database esterno, che resta read-only.
  12. La prima versione supporta PostgreSQL; il confine di introspezione dovrà permettere di aggiungere altri dialetti senza cambiare il modello del catalogo.
  13. I segreti dei Workspace Database riusano il secret store cifrato di ThothII. Il catalogo conserva riferimenti ai segreti e nessuna API, esportazione o log ne restituisce i valori.
  14. La UI usa AG Grid Community per la lista master e un pannello React separato per il dettaglio; non dipende dalle funzionalità master-detail di AG Grid Enterprise.
  15. Un Workspace Database il cui workspace_id scompare dal catalogo YAML non viene cancellato automaticamente: diventa orphaned e può soltanto essere recuperato, riassegnato o eliminato esplicitamente da un amministratore.
  16. La prima vertical slice gestisce configurazione del Workspace Database, riferimenti ai segreti, test di connessione e stato. La seconda gestisce le Catalog Table: la collezione e i nomi sono controllati dall'introspezione, mentre la descrizione curata è modificabile. Le slice successive hanno aggiunto Catalog Column, Catalog Relationship e sincronizzazione durevole dello schema.
  17. Il modello non conserva il name libero di ThothAI: nome e ID visualizzati appartengono al workspace YAML, mentre database_name identifica il database PostgreSQL esterno.
  18. Database management supporta i tre trasporti già riconosciuti da ThothII: postgres_direct, rest_api e ssh_tunnel. PSD rimane un solo Workspace Database: usa la connessione diretta sul server e l'endpoint REST in locale tramite una Database Binding specifica dell'installazione. Questo supporto non abilita automaticamente ssh_tunnel nel runtime NL→SQL.
  19. Una configurazione può essere salvata prima di una connessione riuscita. Il test separato produce uno stato untested, reachable o failed; attivazione e introspezione richiedono uno stato raggiungibile.
  20. Il CRUD e il test di connessione richiedono database.manage; inserimento e sostituzione dei segreti continuano a richiedere workspace.secrets.manage.
  21. Il Workspace Database e il modo di raggiungerlo sono entità distinte. Ogni catalogo di installazione conserva una sola Database Binding attiva per workspace: PSD usa rest_api in locale e postgres_direct sul server senza duplicare il Workspace Database.
  22. Nel modello finale il Metadata Catalog è autorevole per engine, database_name, schema, capacità e binding. Lo YAML resta autorevole per identità e contenuti del workspace; i campi DWH correnti saranno importati, confrontati e rimossi soltanto durante un cutover esplicito.
  23. La lista master è l'unione fra workspace YAML e record del catalogo: mostra workspace unconfigured, database configurati e record orphaned.
  24. Ogni introspezione registra le capability disponibili. Una capability unavailable non viene rappresentata come una collezione osservata ma vuota; REST può completare con successo anche quando indici o enum non sono supportati.
  25. Il Metadata Catalog non introduce snapshot, draft o pubblicazioni. Configurazione e contenuti semantici, inclusi quelli futuri generati dall'AI, sono normali campi modificabili; la struttura osservata cambia soltanto con una sincronizzazione esplicita.
  26. Il normale Delete elimina realmente il Workspace Database, la Database Binding e i relativi record catalogo e segreti. Non modifica il DWH esterno né il repository YAML; il workspace torna visibile nella lista master come unconfigured.
  27. La prima versione gestisce un solo schema obbligatorio per Workspace Database, identificato dalla coppia database_name + schema; per PSD la coppia è postgres + datawarehouse.
  28. I record mantengono soltanto created_at, updated_at e un contatore version per optimistic concurrency. Non esistono storico delle revisioni, rollback o audit applicativo delle modifiche.
  29. workspace_databases conserva soltanto UUID, workspace_id unique, engine, database_name, schema, timestamp e version. Il nome visualizzato appartiene al workspace YAML.
  30. Ogni Workspace Database ha al massimo una riga database_bindings. Una singola tabella usa check constraint dipendenti da transport per i campi direct, REST e SSH; non esiste un flag active, perché ciascuna installazione conserva una sola binding.
  31. rest_api configura il Thoth REST Connector tipizzato: base URL, autenticazione e TLS sono dati della binding, mentre path RPC e shape delle risposte appartengono al contratto applicativo e non sono liberamente configurabili.
  32. Il test connessione usa soltanto una configurazione già salvata ed è associato alla sua version. Ogni modifica della binding o dei segreti invalida il risultato precedente e riporta lo stato a untested.
  33. Password, API key e chiavi sono write-only: l'API espone soltanto configured, un campo vuoto conserva il valore esistente e la sostituzione è un'azione esplicita. Delete rimuove anche i segreti associati.
  34. La pagina usa AG Grid come master e un form React come detail, con sezioni Database, Connection e TLS/SSH condizionali. Non esiste un'azione globale Add database: ogni riga unconfigured offre Configure catalog, apre il form già vincolato a quello specifico workspace YAML e crea il record soltanto al Save; workspace_id non è selezionabile né modificabile.
  35. La grid mostra separatamente revisione/Evidence del workspace, binding runtime NL→SQL e configurazione del Metadata Catalog, oltre a database, schema, endpoint e ultimo aggiornamento. Su schermi piccoli il dettaglio occupa il pannello completo. Il cambio riga con modifiche non salvate e Delete richiedono conferma, senza conferma testuale tipizzata.
  36. La Database Binding conserva connection_status, tested_version, last_tested_at, un codice errore e un messaggio breve sanificato. Non conserva stack trace, DSN, credenziali o output grezzo del driver.
  37. Le API vivono sotto /api/catalog: list/create di /databases, get/patch/delete di /databases/:id, sostituzione dei segreti sotto /databases/:id/secrets, test connessione sotto /databases/:id/test e list/patch/sync delle tabelle sotto /databases/:id/tables.
  38. GET /api/catalog/databases restituisce l'intera master list unificata; AG Grid Community applica client-side ricerca, filtri e ordinamento. La prima versione non introduce paginazione server o funzionalità AG Grid Enterprise.
  39. Il Metadata Catalog vive nello stesso processo Fastify come modulo isolato con repository, service, route, diagnostica e readiness proprie. L'indisponibilità del catalogo non modifica sessioni, SSE o health del core e non giustifica ancora un microservizio separato.
  40. Il backend mantiene pg@8.22.0 e aggiunge kysely@0.29.5 per query e transazioni tipizzate. Le migrazioni Kysely sono timestampate, compilate con il backend ed eseguite da un comando catalog:migrate separato; l'applicazione non migra automaticamente il database all'avvio.
  41. Lo stack aggiunge un servizio interno catalog-db con volume persistente, ruolo runtime DML, ruolo migrator DDL e job one-shot catalog-migrate. Un catalogo indisponibile produce 503 sulle sole route catalogo.
  42. La prima vertical slice è amministrativa: scrive il catalogo ma non cambia ancora il runtime di sessioni e workflow, che continua a usare YAML e binding correnti fino al cutover esplicito.
  43. Configure precompila senza salvare engine, database e schema dal descriptor e i dati non sensibili dalla binding effettiva. L'amministratore verifica, inserisce i segreti e salva; non esiste importazione silenziosa.
  44. Unit e route test usano un repository fake; una suite PostgreSQL Testcontainers separata verifica migrazioni, constraint, transazioni, optimistic concurrency e cascade. SQLite ed emulatori non sono sostituti ammessi per questi test.
  45. La navigazione delle entità catalogo è gerarchica e senza scorciatoie globali: Databases → Database → Overview | Tables → Table. Non esistono una voce globale Tables, un filtro globale Database o una preselezione implicita; Columns continuerà sotto Table e Relationships sotto Database.
  46. Una Catalog Table conserva nome fisico, source_comment, descrizione curata nullable, generated_description nullable per lo step AI futuro, version e timestamp. La UI mostra come tre campi indipendenti senza fallback visivo: source comment read-only, generated description modificabile e description modificabile. I valori null restano celle e controlli vuoti.
  47. Le Catalog Table non possono essere aggiunte o rinominate manualmente. Un amministratore può però ripulire esplicitamente le proiezioni nel Metadata Catalog senza modificare il database esterno; Sync tables legge le tabelle PostgreSQL ordinarie e partizionate dello schema scelto, mentre viste e materialized view sono escluse.
  48. La sincronizzazione è esplicita. La scansione avviene fuori dalla transazione del catalogo; il diff viene applicato atomicamente soltanto se la version del Workspace Database è ancora quella sottoposta a scansione. Una scansione fallita non modifica il catalogo.
  49. Tabelle nuove vengono create, i commenti sorgente vengono aggiornati e quelle non più osservate vengono eliminate definitivamente. La rimozione di tabelle, colonne o relazioni richiede la conferma dell'esatto piano distruttivo; se il secondo scan produce una fotografia differente, l'applicazione richiede una nuova conferma.
  50. Un rename fisico è intenzionalmente delete più create e perde i metadati curati. Le colonne e relazioni dipendenti vengono eliminate in cascade insieme alla Catalog Table.
  51. L'introspezione vive nel modulo catalogo Fastify dietro un adapter. PostgreSQL diretto e tunnel SSH usano il catalogo pg_catalog; REST preferisce il contratto tipizzato POST /rpc/schema_snapshot e, quando quell'RPC non è esposto, usa come fallback compatibile una singola query read-only tramite POST /rpc/run_query. Entrambi i percorsi devono produrre la stessa fotografia v1 stretta descritta in docs/contracts/catalog-schema-snapshot.md.
  52. Test connessione e sincronizzazione sono serializzati per Workspace Database, hanno timeout e richiedono che la binding nella version corrente abbia un test reachable prima di qualsiasi Catalog Sync Run. La scansione asincrona ha un timeout separato, di default dieci minuti.
  53. Il tunnel SSH usa OpenSSH in modalità stdio -W, chiave privata e passphrase opzionale dal secret store, known_hosts obbligatorio, StrictHostKeyChecking=yes, agent e configurazione globale disabilitati. Non è ammesso TOFU. TLS PostgreSQL con CA e server name resta verificato anche attraverso il tunnel.
  54. In questo slice ssh_tunnel è una binding supportata da Database management per Test connection e Schema Sync. Il renderer e il runtime delle sessioni NL→SQL restano fuori scope e continuano a rifiutarla finché non verrà deciso il relativo cutover.
  55. I menu di azione a livello Workspace Database espongono separatamente Synchronize tables, Synchronize relationships e Synchronize all. Su una selezione di database lo scope scelto viene avviato per ogni database idoneo; non viene sostituito implicitamente con una sincronizzazione completa.
  56. Lo scope Columns è disponibile dalla grid Tables e limita la riconciliazione alle tabelle selezionate; la pagina Columns non espone azioni di sincronizzazione. La grid Tables espone Synchronize columns sulle tabelle selezionate.

Correzione del modello mentale corrente

schema/annotations.yaml non contiene l'intero schema del database.

  • physical.yaml è un artefatto derivato dall'introspezione. Contiene database, schema, timestamp, tabelle, colonne, tipi, nullability, default, primary key, commenti sorgente, esempi, foreign key fisiche e indici.
  • annotations.yaml contiene metadati curati: descrizioni e concetti delle tabelle; descrizioni, sinonimi, concetti, evidence, note e override eligible delle colonne; foreign key logiche.
  • Il rendering M-Schema fonde questi due input. Le annotations prevalgono sui commenti sorgente e le relazioni logiche vengono unite alle foreign key fisiche.

La sostituzione del solo file annotations non elimina automaticamente l'introspezione fisica. Il nuovo catalogo dovrà conservare una distinzione esplicita fra fatti osservati nel database e contenuto semantico modificabile.

Architettura ThothII rilevante

Autorità e revisionamento attuali

Il repository dei workspace contiene:

thoth-workspaces.yaml
<workspace-id>/workspace.yaml
<workspace-id>/schema/annotations.yaml
<workspace-id>/evidence/**

Il backend legge descriptor e annotations allo stesso commit Git. Durante l'attivazione valida il blob, lo copia atomicamente nello snapshot immutabile della revisione e registra commit, blob ID e digest. Le nuove sessioni vengono legate a quella revisione; resume e SQL salvato riaprono lo stesso snapshot.

Punti principali:

  • backend/src/workspaces/schema.ts: descriptor v3 e singolo dwh.database/dwh.schema;
  • backend/src/workspaces/git-repository.ts: lettura sicura del blob annotations al commit;
  • backend/src/workspaces/registry.ts: validazione e attivazione atomica;
  • backend/src/workspaces/annotations-sync.ts: materializzazione revision-qualified;
  • backend/src/workspaces/runtime-config-lease.ts: binding dello snapshot al runtime;
  • harness/tht/mschema/models.py: contratti PhysicalSchema e Annotations;
  • harness/tht/mschema/render.py: fusione fisico/semantico;
  • harness/tht/cli/vector_cmd.py: indicizzazione schema in Qdrant.

Consumatori da preservare al cutover futuro

Le annotations incidono oggi su:

  • override eligible prima del campionamento LSH;
  • suggerimento, controllo e accettazione delle foreign key logiche;
  • descrizioni, concetti e sinonimi dei record schema in Qdrant;
  • retrieval delle tabelle e colonne candidate;
  • rendering M-Schema usato dal gate F4 e dalla generazione SQL;
  • digest della revisione accettata durante il preprocessing.

Il futuro cutover non potrà limitarsi a rimuovere il file: dovrà fornire al core lo stesso contenuto effettivo, con un'identità coerente e test di equivalenza. Poiché non occorre preservare le sessioni di test esistenti, non serve progettare compatibilità con i vecchi manifest, ma resta necessario evitare letture parziali o semanticamente incoerenti.

Inventario ThothAI

Modelli legacy

I modelli sono definiti in Thoth/ThothAI/backend/thoth_core/models.py.

SqlDb

Campi di connessione osservati:

  • name;
  • db_host, db_port;
  • db_type;
  • db_name, schema;
  • user_name, password;
  • db_mode;
  • configurazione SSH e Informix opzionale.

Il modello contiene anche scope, JSON dello scope, ERD, direttive, campi GDPR, collegamento a VectorDb e numerosi campi di stato/task/log per lavori AI asincroni.

I tipi legacy dichiarati sono Informix, MariaDB, MySQL, Oracle, PostgreSQL, SQL Server e SQLite. Questo elenco non costituisce automaticamente un requisito per ThothII: il core corrente supporta PostgreSQL e l'estensione ad altri dialetti dovrà essere decisa separatamente.

SqlTable

  • name;
  • description;
  • generated_comment;
  • foreign key obbligatoria a SqlDb, con cancellazione cascade.

SqlColumn

  • original_column_name e alias column_name;
  • data_format normalizzato;
  • column_description;
  • generated_comment;
  • value_description;
  • stringhe denormalizzate pk_field e fk_field;
  • foreign key obbligatoria a SqlTable, con cancellazione cascade.

Relationship

Contiene quattro foreign key obbligatorie:

  • source_table e source_column;
  • target_table e target_column.

Il form admin verifica che le tabelle appartengano allo stesso database e che ogni colonna appartenga alla tabella selezionata. Il database non impone però gli stessi check.

Workspace

ThothAI usa Workspace.sql_db come foreign key nullable verso SqlDb: un workspace seleziona un solo DB, mentre lo stesso DB può essere riusato da più workspace. ThothII adotterà invece una relazione uno-a-uno: workspace_id deve essere unico nel catalogo.

Lacune dei constraint legacy

Non risultano constraint database-level per:

  • unicità del nome database nel workspace;
  • unicità (database, table name);
  • unicità (table, column name);
  • unicità degli estremi di una relationship;
  • appartenenza degli estremi della relationship allo stesso database;
  • corrispondenza fra colonna e tabella dichiarata.

ThothII deve applicare queste invarianti sia nel database interno sia nel servizio applicativo. La sola validazione del form non è sufficiente perché API, import e job la possono aggirare.

Django Admin e UX da replicare concettualmente

ThothAI espone il CRUD tramite il Django Admin standard, registrato da backend/thoth_core/admin.py e pubblicato su /admin/.

Capacità utili:

  • lista database con ricerca per nome, host, tipo, database e schema;
  • fieldset separati per identità, connessione, autenticazione, SSH e stato;
  • lista tabelle filtrabile per database;
  • lista colonne filtrabile in cascata per database e tabella;
  • lista relazioni con estremi leggibili e filtri per database e tabelle;
  • form relazione con dropdown dipendenti database → tabella → colonna;
  • validazione degli estremi prima del salvataggio;
  • azioni separate per test connessione, introspezione, import/export e generazione AI;
  • azioni bulk sulle righe selezionate.

ThothII deve replicare i contratti di interazione e validazione, non il rendering server-side o i template Django.

Introspezione legacy

Thoth/ThothAI/backend/thoth_core/dbmanagement.py usa thoth-dbmanager per:

  1. costruire l'adapter del dialetto;
  2. acquisire tabelle;
  3. acquisire e normalizzare colonne e tipi;
  4. acquisire relazioni;
  5. creare le eventuali colonne mancanti necessarie alle relazioni;
  6. aggiornare i campi PK/FK denormalizzati.

Il comportamento è principalmente additivo: usa get_or_create o controlli exists, aggiorna alcuni commenti, ma non riconcilia in modo completo rename, rimozioni o drift. Non va copiato così com'è. Il processo ThothII implementato distingue scansione, differenze osservate e applicazione della nuova snapshot.

Generazione AI legacy

ThothAI dispone di azioni e workflow per:

  • commenti delle tabelle;
  • commenti delle colonne;
  • scope del database;
  • ERD Mermaid;
  • documentazione del database;
  • analisi GDPR.

Per il requisito attuale sono direttamente rilevanti descrizioni di tabelle e colonne, scope e metadati semantici. ERD, documentazione aggregata e GDPR sono estensioni future, non prerequisiti del CRUD iniziale.

La separazione description/generated_comment del legacy non offre versioning o approvazione robusti. Nei passi successivi andrà deciso se l'output AI è una proposta revisionabile o diventa immediatamente il valore editabile corrente.

Import ed export legacy

ThothAI offre:

  • CSV di database, tabelle, colonne e relazioni;
  • export di struttura per workspace;
  • import mediante import_db_structure;
  • script SQL dei commenti per più dialetti;
  • aggiornamento delle descrizioni colonna da CSV.

Il futuro import PSD dovrà leggere il contratto YAML corrente e convertirlo su chiavi naturali, non riutilizzare gli ID numerici Django. Deve essere idempotente e produrre un report di elementi creati, aggiornati, ignorati o non risolti.

Comandi osservati in ThothAI

Backend locale

Eseguiti da Thoth/ThothAI/backend:

uv sync
uv run python manage.py migrate
uv run python manage.py createsuperuser
uv run python manage.py runserver 8200
uv run pytest

Import catalogo legacy:

uv run python manage.py import_db_structure --source local
uv run python manage.py load_defaults --only-level 4 --source local

Test mirati rilevanti:

uv run pytest tests/test_relational_database_operations.py -v
uv run pytest tests/test_ssh_tunnel_configuration.py -v

Stack Docker legacy

ThothAI dichiara postgres:16-alpine nel profilo internal-db, con volume persistente e healthcheck pg_isready.

docker compose --profile internal-db up --build

Il wrapper legacy abilita lo stesso profilo quando POSTGRES_INTERNAL=true:

POSTGRES_INTERNAL=true ./docker-up.sh

Questi comandi documentano il riferimento osservato; non sono comandi di installazione per ThothII.

Cosa copiare in ThothII

Parità necessaria

  • gerarchia Workspace Database → Table → Column;
  • relazione strutturale fra colonne sorgente e destinazione;
  • navigazione e filtri dipendenti workspace/database/tabella;
  • test di connessione separato dal salvataggio;
  • introspezione esplicita e ripetibile;
  • descrizioni generate dall'AI ma modificabili dall'utente;
  • validazione cross-entity delle relazioni;
  • azioni di import/export senza segreti;
  • stato leggibile dei job lunghi;
  • PostgreSQL interno persistente con migrazioni esplicite;
  • test di CRUD, cardinalità, cascade/restrict, isolamento per workspace e idempotenza.

Parità semantica con annotations.yaml

Il modello futuro deve poter rappresentare almeno:

  • descrizione, concetti e note per tabella;
  • descrizione, sinonimi, concetti, evidence, note ed eligible per colonna;
  • foreign key logiche;
  • distinzione fra commento fisico osservato e descrizione curata;
  • provenienza del contenuto importato o generato.

L'eventuale esclusione di uno di questi campi deve essere una decisione esplicita perché cambia rendering, retrieval, LSH o SQL generation.

Vincoli minimi da progettare

  • workspace_id obbligatorio e unico sul Workspace Database, con esistenza validata contro il catalogo YAML dal servizio applicativo;
  • nome tabella unico nel database e schema appropriato;
  • nome colonna unico nella tabella;
  • relationship unica secondo il modello, anche per chiavi composite;
  • estremi della relationship nello stesso Workspace Database;
  • appartenenza certa della colonna alla tabella;
  • mutazioni aggregate transazionali;
  • gestione esplicita di concorrenza fra CRUD e introspezione.

Cosa non copiare

  • Django, Django Admin, Django ORM, DRF, template admin e frontend Next;
  • modello Workspace legacy e condivisione dello stesso DB fra più workspace;
  • password o passphrase come normali campi testuali;
  • password incluse in CSV o export completi;
  • token SSO inseriti nella query string;
  • migrazioni generate automaticamente all'avvio;
  • validazioni presenti soltanto nel form;
  • pk_field e fk_field testuali come fonte di verità;
  • duplicazione di tabella e colonna negli estremi senza constraint coerenti;
  • introspezione additiva che non segnala rename, delete o drift;
  • azioni admin che possono mostrare successo dopo output AI non valido;
  • dipendenza del workflow core dalla disponibilità della UI o del PostgreSQL amministrativo.

Aspetti di sicurezza da non ereditare

L'export legacy della struttura include username e password in chiaro. Il modello conserva inoltre password, passphrase SSH e altri segreti in CharField; non è stata trovata cifratura applicativa, nonostante un testo admin affermi il contrario.

ThothII distingue i metadati di connessione dai riferimenti al secret store cifrato. In ogni caso:

  • nessun endpoint o export deve restituire segreti;
  • log ed errori devono sanificare DSN e credenziali;
  • le credenziali di migrazione non devono essere disponibili al runtime CRUD;
  • il catalogo non deve riusare credenziali del DWH, delle sessioni o di Qdrant;
  • test connessione e introspezione devono usare timeout e privilegi read-only.

La binding REST corrente richiede una verifica prima del cutover: il renderer emette ssl_ca_file, mentre il modello Python espone ssl_ca; il percorso della CA privata potrebbe quindi non essere consumato. PSD richiede TLS con CA privata in locale, perciò questo disallineamento deve essere corretto e coperto da un test end-to-end prima di affidare il profilo REST al catalogo.

Percorso incrementale

Step 1: accesso alla superficie vuota

Implementato in questo worktree:

  • pulsante Database management nella sidebar destra;
  • visibilità legata a workspace.manage;
  • superficie centrale React separata e vuota;
  • nessun router, endpoint, fetch o stato catalogo;
  • sessione e SSE conservati in background;
  • ritorno al core tramite creazione, apertura o resume di una sessione;
  • test frontend dedicati.

Comandi di verifica:

cd frontend
npx vitest run src/shell/AppShell.database-management.test.tsx
npx vitest run src/shell/AppShell.new-session.test.tsx \
  src/shell/AppShell.session-target.test.tsx \
  src/shell/AppShell.session-mgmt.test.tsx
npx tsc -b

Step 2: contratto di dominio e schema relazionale

Progettazione della vertical slice completata: Workspace Database, Database Binding, singolo schema, riferimenti al secret store, optimistic concurrency e capability per trasporto hanno contratti espliciti. Configurazione e contenuti semantici restano mutabili; la struttura fisica osservata è sincronizzata e non modificabile manualmente.

Step 3: PostgreSQL interno e migrazioni

PostgreSQL interno con volume e ruoli runtime/migrator separati. Il modulo catalogo usa Kysely sopra il driver pg; le migrazioni compilate vengono applicate soltanto dal comando catalog:migrate e mai allo startup Fastify. Health, readiness e diagnostica restano dedicate; l'indisponibilità del catalogo non cambia core /health e non interrompe una sessione.

Step 4: API CRUD

Contratti HTTP, autorizzazione, paginazione, filtri, errori, optimistic concurrency e transazioni. Gli endpoint dovranno vivere sotto un namespace catalogo e non riutilizzare le route sessione.

Step 5: UI CRUD

Workspace Database, Catalog Table, Catalog Column e Catalog Relationship sono implementati con React/Vite e il design system ThothII. La navigazione è gerarchica e locale al database (Overview | Tables), senza menu o filtri globali per tipo di entità. La grid delle tabelle non offre Add o cancellazione della singola configurazione; le selezioni espongono invece la pulizia esplicita dei metadati. Il dettaglio full-width mantiene immutabili i fatti fisici e consente di modificare separatamente Description e Generated Description. Colonne e relazioni seguono la stessa gerarchia: Columns appartiene al dettaglio della tabella, Relationships al database. I valori descrittivi null sono mostrati come celle e campi vuoti, senza fallback visivi o placeholder Not set che nascondano quale sorgente è effettivamente valorizzata.

Le griglie che dispongono di azioni massive usano checkbox e una toolbar contestuale con conteggio, menu Actions e cancellazione della selezione. La selezione identifica ID espliciti, può essere accumulata attraverso i filtri e viene azzerata dopo successo, nuova sincronizzazione o uscita dalla pagina; un'azione è all-or-nothing se un elemento non è idoneo. I menu a livello database espongono gli scope fisici come azioni distinte: Synchronize tables, Synchronize relationships e Synchronize all. La grid Tables espone invece Synchronize columns per le tabelle selezionate; la pagina Columns non espone sincronizzazione. Le selezioni database aggiungono Delete all tables e Delete all relationships; le selezioni tabelle aggiungono Delete all columns e Delete all relationships. Queste operazioni sono atomiche, richiedono conferma e non modificano database esterno, binding, configurazione o segreti. Test connection resta un'azione distinta; griglie senza azioni non mostrano controlli di selezione inerti.

Step 6: introspezione

Catalog Table, Catalog Column e Catalog Relationship sono implementate per PostgreSQL diretto, Thoth REST Connector e tunnel SSH. La scansione read-only è separata dalla transazione; una riconciliazione atomica crea, aggiorna i commenti sorgente ed elimina, dopo conferma, i fatti fisici assenti senza rendere modificabile manualmente la struttura osservata. Gli scope autorevoli sono Tables per database e Physical Relationships per database. Per Columns, tableIds vuoto include tutte le Catalog Table correnti, mentre una lista di ID limita lo scope al sottoinsieme esplicito; Synchronize all osserva tutti e tre gli scope in un unico snapshot e li riconcilia insieme. Tutti gli scope sono eseguiti come Catalog Sync Run durevoli in background, non attraverso implementazioni sincrone e asincrone separate. Un run che prevede cancellazioni conserva il diff, attende una conferma esplicita e verifica nuovamente lo snapshot prima dell'applicazione; se la sorgente è cambiata, invalida la conferma. Ogni applicazione è atomica e fail-closed: errori, timeout o capability non disponibili non producono aggiornamenti parziali.

PK e FK devono essere visibili sulle Catalog Column senza duplicare le stringhe denormalizzate di ThothAI. La posizione nella primary key è un fatto osservato della colonna; membership e conteggio FK sono proiezioni derivate dalle Catalog Relationship e dalle loro coppie ordinate, aggiornate nella stessa transazione di riconciliazione.

Ogni scope registra la versione della Database Binding osservata e l'istante dell'ultima sincronizzazione. Una modifica della binding conserva il catalogo precedente ma lo marca stale; solo un Synchronize all riuscito rende nuovamente corrente l'intero schema.

Step 7: generazione AI dei metadati

Generated Description è una proposta distinta e modificabile: un revisore può correggerla prima di consolidarla esplicitamente come Description. Lo slice AI dovrà decidere e implementare anche alias semantici, descrizioni dei valori, sinonimi e concetti per tabelle e colonne, oltre alla gestione esplicita di errori e output non validi. La generazione AI e l'azione di consolidamento non appartengono allo slice di introspezione dello schema.

Step 8: migrazione PSD

Import idempotente delle annotations PSD, riconciliazione contro la struttura introspezionata, report degli orfani e confronto semantico con il rendering corrente. Gli altri workspace non ricevono import legacy.

Step 9: sostituzione dell'input core

Rimuovere la dipendenza da annotations.yaml soltanto dopo avere un contratto equivalente, test di rendering/search/Qdrant e una policy di disponibilità. Le sessioni di test esistenti possono essere eliminate, ma le nuove sessioni non devono osservare aggiornamenti parziali. Questo cutover è esplicitamente rinviato fino al completamento del database dei metadati. Il primo gate successivo obbligatorio sarà valutare l'integrazione del Catalog Schema Snapshot con il workflow core e lo schema-linking corrente; il rinvio non autorizza a dimenticare o assorbire implicitamente il lavoro in altri slice.

Step 10: operazioni e accettazione

Backup/restore reale, diagnostica, metriche, permessi definitivi, hardening degli export e test di failure isolation fra catalogo e workflow. I Catalog Sync Run hanno un solo job attivo per Workspace Database, sono concorrenti fra database diversi e usano un lock persistente. Un pannello operativo non modale rimane visibile durante la navigazione del database, mostra fasi, contatori, tempo trascorso e log sanitizzato via SSE con polling di fallback, e offre Confirm, Cancel e Retry quando consentiti. Un restart marca interrupted i run rimasti attivi; il retry crea un nuovo run. Le modifiche ai metadati restano consentite durante la scansione e sono preservate dall'applicazione. Il worker gira inizialmente nello stesso servizio Fastify ma dietro un'interfaccia estraibile, con coda, lease e heartbeat persistiti nel catalog-db. I riepiloghi dei run non scadono; gli eventi dettagliati sono conservati per 30 giorni, mentre snapshot e diff completi vengono eliminati dopo la conclusione lasciando conteggi, decisioni e una sintesi sanitizzata dell'esito.

Verifiche del core da conservare per il cutover

Comandi attuali rilevanti:

tht --installation <absolute>/thothii-installation.yaml workspace preprocess dwh \
  --workspace <id> --json
tht --installation <absolute>/thothii-installation.yaml workspace schema suggest-fks \
  --workspace <id> --json
tht --installation <absolute>/thothii-installation.yaml workspace schema check \
  --workspace <id> --json
tht --installation <absolute>/thothii-installation.yaml workspace schema accept \
  --workspace <id> --run <run-id> --yes --json
tht --installation <absolute>/thothii-installation.yaml workspace index-schema \
  --workspace <id> --json

Suite che documentano il comportamento da preservare:

cd backend
npx vitest run test/workspaces-git-annotations.test.ts \
  test/registry-annotations.test.ts \
  test/annotations-sync.test.ts \
  test/workspace-runtime-config-lease.test.ts \
  test/workspace-preprocessing-service.test.ts
npx tsc --noEmit -p .

cd ../harness
.venv/bin/pytest -q \
  tests/test_annotations_root.py \
  tests/test_schema_fk_annotations.py \
  tests/test_mschema_render.py \
  tests/test_qdrant_cli_commands.py

Questi test non implicano che la futura implementazione debba continuare a usare file YAML. Definiscono gli effetti semantici e le guardie da mantenere o sostituire consapevolmente.

Decisioni rinviate

Le seguenti scelte non appartengono allo step 1:

  • lifecycle dei riferimenti ai segreti durante sostituzione e cancellazione;
  • criteri per aggiungere dialetti successivi a PostgreSQL;
  • criteri per un'eventuale estensione futura a più schemi per database;
  • lifecycle e gestione amministrativa delle future Logical Relationship;
  • alias semantici, descrizioni dei valori, sinonimi e concetti prodotti o assistiti dall'AI;
  • formato e momento del cutover dal file al database interno;
  • permission definitiva separata da workspace.manage.

Ognuna sarà affrontata nel relativo step, senza anticipare scelte tecnologiche nel presente documento.