Vai al contenuto

Navigation Registry — Phase 1

Scopo

Phase 1 introduce un registry di navigazione in memoria, read-only e in shadow mode. Il menu FAB/legacy resta la sola fonte di verità operativa. Il registry osserva e normalizza ciò che è già registrato senza alimentare la sidebar, modificare appbuilder.menu o cambiare autorizzazioni.

Architettura

FAB / legacy Menu
        ↓
app.navigation.adapters.fab_legacy.snapshot_from_fab_menu
        ↓
NavigationRegistry (in-memory)
        ↓
snapshot JSON + compare_snapshots

Il nuovo codice non è registrato nell'application factory e non introduce route HTTP, pagina amministrativa, migration o CLI con effetti esterni. Un consumer diagnostico può importare snapshot_from_fab_menu(appbuilder), serializzare registry.to_json() e confrontare due snapshot con compare_snapshots.

Cosa fa

  • legge la struttura già esposta da appbuilder.menu.get_list();
  • rappresenta categorie e voci con NavigationItem;
  • raccoglie label, modulo, parent/categoria, endpoint tecnico, view, icona, ordine, permission metadata e origine;
  • assegna un ID stabile derivato da modulo, view, endpoint, categoria e parent;
  • conserva la condizione di rendering come metadata (visibility.conditional) senza eseguirla;
  • produce una lista JSON deterministica;
  • confronta snapshot rilevando elementi mancanti/inaspettati, ID duplicati, endpoint duplicati, categorie incoerenti, differenze di ordine e record non normalizzabili.

Cosa non fa

Non modifica FAB, registrazioni add_view/add_link/add_separator, ordine del menu, template, sidebar, navbar, endpoint, API, permission, ruoli, ACL, tenant filtering o database. Il campo permission è metadata osservazionale: non filtra, non autorizza, non nega e non mostra/nasconde elementi. Non esiste un capability engine in Phase 1.

Modello dati

NavigationItem contiene:

  • id: digest stabile della composizione tecnica;
  • label, category, parent, icon, order;
  • module, view, endpoint;
  • permission: tuple di permission FAB eventualmente esposte dalla view;
  • source: attualmente fab_legacy;
  • legacy: sempre true per questo adapter;
  • tenant_aware: nullable, perché l'adapter non deduce ACL;
  • visibility: metadata non esecutivo, per ora solo presenza di una condizione FAB.

Quando FAB non espone una view o un endpoint, il campo resta vuoto. Non sono stati introdotti hack per ricostruire URL con url_for: l'adapter legge l'href dichiarato e l'endpoint tecnico della view, così resta utilizzabile fuori da una request context.

Adapter FAB/legacy

app/navigation/adapters/fab_legacy.py usa introspezione duck-typed e get_list(). Non chiama Menu.get_data(), perché quella funzione applica già il filtraggio SecurityManager e richiede contesto applicativo; non esegue callback cond. Questa scelta mantiene lo snapshot descrittivo e non altera il comportamento operativo.

Snapshot e confronto

NavigationRegistry.snapshot() restituisce dizionari JSON-serializzabili in ordine di registrazione. to_json() usa output UTF-8 e chiavi ordinate. compare_snapshots(legacy, registry) non lancia eccezioni per differenze: restituisce liste diagnostiche con le categorie missing_items, unexpected_items, duplicate_ids, duplicate_endpoint_registrations, inconsistent_categories, order_differences e unnormalizable_items.

Limiti conosciuti

  • il registry osserva il menu FAB registrato, non tutte le route non presenti nel menu;
  • l'href è quello dichiarato dalla registrazione, non una URL risolta per l'utente corrente;
  • non interpreta ACL, tenant, Cliente.users, is_platform_admin o permission inheritance;
  • tenant_aware rimane nullable;
  • label tradotte e callback condizionali non vengono valutate;
  • un ID duplicato è riportato dal confronto, non corretto automaticamente;
  • non è ancora disponibile un comando CLI o una pagina web: l'accesso è una utility Python interna, sufficiente per test e diagnostica senza ampliare la superficie operativa.

Debito tecnico residuo

Restano da mappare endpoint/API non registrati nel menu, profili tenant e ACL per modulo, policy basate su label, duplicati storici FAB e differenze DEV/PROD. Questi temi appartengono a fasi successive e non sono stati modificati.

Percorso verso Phase 2

Prima di una fase successiva occorrono snapshot DEV/PROD congelati, una matrice endpoint/ruolo/tenant/cliente e una decisione sul mapping capability-to-FAB. Solo dopo si potrà valutare un adapter più completo o una modalità shadow collegata alla diagnostica applicativa. Il registry non deve diventare fonte operativa finché il confronto non è stabile e i test negativi di autorizzazione non sono disponibili.