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: attualmentefab_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_admino permission inheritance; tenant_awarerimane 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.