20 KiB
ksp-app-config-desk
ksp-app-config-desk est l'application desktop spécialisée de management et de validation de la configuration KSP.
La crate est un package Tauri mixte :
package : ksp-app-config-desk
lib : ksp_app_config_desk_lib
bin : ksp-app-config-desk
Responsabilités
L'application reste une couche d'interface/composition. Les responsabilités de parsing, validation, profils, environnement, .env, secrets et persistence restent dans ksp-config-lib; le runtime Logging restera possédé par ksp-logging-lib.
Le gabarit desktop actif fournit maintenant :
- le verrou single-instance ;
- l'assemblage Tauri centralisé dans
src/tauri.rs; - les fenêtres
splashetmain, orchestrées partw_splash.rsettw_main.rs; - le frontend Vanilla TypeScript + Vite sous
frontend/; - SCSS, Bootstrap et Font Awesome ;
- SimpleBar +
resize-observer-polyfillpour le scrolling du shell ; - DataTables 3 + Select 4 pour l’inventaire interactif des documents Config ;
- le panneau Documents générique alimenté par le registre
ksp-config-lib, avec diagnostics backend et réparation validée ; - le panneau Profils générique pour
default_profile, sélection explicite, vues global/profil/effective sûre et provenance ; - le panneau Environnement alimenté uniquement par
ConfigManagement, avec rapport desired/effective sûr, source/shadowing, management atomique.envet reveal Secret privilégié/transitoire ; - le panneau Logging typé, alimenté par
ConfigManagement::load_logging_document()/save_logging_document(), avec brouillon éditable, profils, console, fichiers, filtres, targets et domains sans parsing JSON frontend ; - l’observabilité du runtime Logging actif : profil, source de sélection, génération, console, compteurs de drop, identité de lancement et prefixes fichiers effectifs ;
- l’application explicite d’un profil Logging persisté sans modifier
default_profileni le document source ; tauri-plugin-tracingcôté Rust et@fltsci/tauri-plugin-tracingcôté frontend ;- les ports dédiés
1430pour Vite HTTP et1431pour le WebSocket de développement ; - la destination frontend externe commune à Tauri et Vite;
- le bootstrap Config/Logging réel, un
AppStatedurable et le premier contrat Tauri/TS-RSget_app_snapshot; - le bridge de logging frontend KSP
frontend_log.ts, routé paremit_frontend_logvers des targets statiques whitelistés deksp-logging-lib; - le lifecycle configurable
splash -> mainavec navigation monofenêtre et instrumentationdebug/tracedes interactions frontend.
Layout frontend
frontend/
├── imgs/
├── sass/
│ ├── _app.scss
│ ├── _bootswatch.scss
│ ├── _fontawesome.scss
│ ├── _simplebar.scss
│ ├── _variables.scss
│ ├── main.scss
│ └── splash.scss
├── ts/
│ ├── documents.ts
│ ├── environment.ts
│ ├── frontend_log.ts
│ ├── invoke.ts
│ ├── logging.ts
│ ├── logging_test.ts
│ ├── main.ts
│ ├── profiles.ts
│ ├── secret_reveal.ts
│ ├── shell_registry.ts
│ └── splash.ts
├── main.html
└── splash.html
Les premiers bindings TS-RS sont générés par les tests ts-rs sous :
frontend/ts/bindings/ksp_app_config_desk/...
Les DTO Rust applicatifs restent la source de vérité et les bindings générés ne sont pas versionnés.
Robustesse desktop et extensibilité
pre.018 rend le fallback de bootstrap Logging testable avant installation du subscriber : la résolution produit d'abord un plan managed ou fallback, puis seulement l'initialisation runtime est tentée. Une source Logging invalide peut ainsi être couverte par test sans installer un subscriber global dans le processus de tests. Le fallback reste transitoire, console-only, niveau Info, sans file sink.
Le frontend possède désormais shell_registry.ts. Le registre décrit les vues du shell et les adapters d'éditeurs spécialisés par file_id. Le panneau Documents reste générique ; lorsqu'un document possède un adapter enregistré, Ouvrir l'éditeur spécialisé déclenche la navigation par événement de registre. cfg.std.logging -> Logging est le premier adapter. Ajouter un futur éditeur ne demande donc pas de réécrire le moteur Documents ni la logique générale d'activation des panneaux.
Deux audits d'intégration applicatifs complètent les audits Config/Logging existants : contrat Tauri/Vite/package scripts, centralisation des commandes Tauri, absence de tauri-plugin-log, interdiction des dialogues navigateur natifs et absence de stockage persistant pour le reveal Secret. Aucun script frontend standalone n’est lancé par l’opérateur : Tauri possède le cycle dev/build et déclenche les hooks npm de la crate. Le build Vite/TypeScript de production appartient au beforeBuildCommand du cargo tauri build crate-local, qui reste la dernière validation après tous les contrôles Rust et le parcours fonctionnel cargo tauri dev.
Artefacts frontend
Les artefacts frontend construits ne sont pas versionnés. tauri.conf.json fixe :
../../../builds/khadhroony-solana-project/ksp-app-config-desk/dist
vite.config.ts résout cette même destination depuis la racine de la crate, ce qui maintient dist hors du workspace source et l'aligne avec la stratégie .cargo/config.toml pour les artefacts Rust.
Ports desktop
ksp-app-config-desk utilise :
Vite HTTP : 1430
Vite WS : 1431
Le port HTTP est strict. Les futures applications desk utilisent les couples suivants 1432/1433, 1434/1435, etc.
Dépendances frontend
Les bibliothèques consommées par le bundle applicatif sont déclarées sous dependencies : @fltsci/tauri-plugin-tracing, @fortawesome/fontawesome-free, @tauri-apps/api, bootstrap, simplebar et resize-observer-polyfill.
Les outils de compilation/développement et déclarations de types appartiennent à devDependencies, notamment @tauri-apps/cli, @types/bootstrap, @types/node, sass-embedded, typescript et vite. Les commandes npm directes sont réservées à l'installation ou à la mise à jour de ces dépendances. Le cycle normal de développement et de build est crate-local : l'opérateur peut rester positionné à la racine du workspace, mais la commande exécute d'abord cd crates/ksp-app-config-desk puis cargo tauri dev/build. -c/--config n'est pas utilisé comme sélecteur de crate.
Logging frontend KSP
Le frontend utilise frontend/ts/frontend_log.ts. Les helpers frontendTrace, frontendDebug, frontendInfo, frontendWarn et frontendError, ainsi que le bridge console.*, invoquent la commande Tauri emit_frontend_log.
Le payload ne transporte pas de target tracing libre. Il utilise uniquement les identifiants logiques :
frontend -> ksp-app-config-desk.frontend
main -> ksp-app-config-desk.frontend.main
splash -> ksp-app-config-desk.frontend.splash
Rust valide le niveau et le targetId, choisit un callsite statique puis émet exclusivement via les macros de ksp-logging-lib. Le package applicatif n'importe pas directement tracing. Le pont actuel garantit donc le trajet WebView -> Rust tout en conservant l'affichage local des appels console.* dans la console WebKit. Le retour général Rust -> console WebKit est volontairement hors périmètre de 0.1.4 : une future intégration devra passer par une couche possédée par ksp-logging-lib, sans second subscriber, double émission ni boucle avec le bridge KSP. Le panneau Test Logging complète désormais ce bridge : il peut émettre des événements backend via ksp-logging-lib avec target KSP statique et domain contrôlé, ou réutiliser le bridge frontend existant avec son target/domain fixes.
Panneau Test Logging
pre.017 ajoute une surface de validation volontairement explicite. Le champ Message est le contenu qui sera réellement journalisé ; il ne doit donc jamais recevoir de Secret. Log backend appelle emit_logging_test, qui valide le niveau (trace/debug/info/warn/error/tous), choisit un target statique (ksp-app-config-desk ou ksp-app-config-desk.logging-test) et applique un domain absent, connu ou personnalisé borné avant d'émettre exclusivement avec les macros ksp-logging-lib. Le résultat retourne uniquement des métadonnées sûres : nombre d'événements, niveau demandé, target/domain effectifs et génération runtime.
Log via bridge frontend réutilise le bridge déjà installé. Son contrat reste volontairement fixe : target=ksp-app-config-desk.frontend.main, domain=frontend. Cela permet de comparer dans le même panneau le routing backend et le chemin WebView -> Rust -> ksp-logging-lib, avant et après modification/hot reload des filtres.
Bootstrap Config et Logging
Au démarrage, l'application construit ConfigBootstrapOptions, ConfigFileRegistry, ConfigDocumentEngine et ConfigManagement à partir des arguments complets du processus. En développement, le launcher normalise d'abord le current working directory Rust vers la racine du workspace : cargo tauri dev est volontairement lancé depuis la crate Tauri, ce qui ferait manquer les chemins Config relatifs config/, config/schemas/ et le .env racine. Cette normalisation ne lit ni ne parse aucun fichier Config elle-même ; l'ownership reste intégralement dans ksp-config-lib. Elle tente ensuite de résoudre le profil Logging par défaut avec un snapshot ConfigEnvironment frais.
Si le document Logging, sa résolution environnementale ou l'initialisation du runtime configuré échoue avant installation du subscriber, Config Desk installe un fallback transitoire en mémoire : console stderr, niveau Info, aucun fichier, aucun span lifecycle. Ce fallback n'est jamais persisté et son diagnostic frontend est limité à domain, code et message.
Le LoggingGuard est conservé dans AppState et sert désormais au hot reload transactionnel du runtime Logging après sauvegarde.
Runtime packagé
Le parcours release ne dépend pas du checkout source ni du répertoire depuis lequel le binaire est lancé. Les documents Config et schemas enregistrés sont embarqués comme resources Tauri. Avant AppState::initialize, tauri.rs résout le répertoire de resources puis délègue à ksp-config-lib::prepare_packaged_runtime. Config résout un répertoire de données utilisateur KSP writable via ProjectDirs, y seed les documents Config absents et y synchronise les schemas possédés par le package courant. Le process adopte ensuite ce répertoire writable comme current working directory.
Les documents Config déjà présents restent user-managed et ne sont jamais écrasés silencieusement lors d'une mise à jour. Les schemas sont resynchronisés à chaque lancement packagé. Le .env n'est jamais embarqué ni seedé ; les chemins relatifs logs/ et wallets/ restent ancrés dans ce runtime partagé sauf override Config. Config Desk et Wallet Desk utilisent le même identifiant de projet KSP afin de partager cette racine runtime sans dupliquer l'ownership des ressources.
Lifecycle des fenêtres
tw_splash.rs valide l'origine de splash_frontend_ready, ignore les readiness dupliquées et orchestre le passage à main. Les timings sont résolus par ksp-config-lib depuis :
KSP_DESK_SPLASH_MINIMUM_MS=1200
KSP_DESK_SPLASH_FADE_IN_MS=300
KSP_DESK_SPLASH_FADE_OUT_MS=300
Après la readiness frontend, Rust émet fade_in, attend la durée minimale, émet fade_out, attend la durée de fade puis tw_main.rs affiche/focalise main avant destruction du splash. Le backend journalise en debug les valeurs résolues, leur provenance (process, dotenv ou fallback), chaque attente réellement observée et la durée totale. Avec 12000/3000, la durée backend attendue entre readiness et activation de main est donc d'environ 15000 ms. Une valeur splash invalide ne bloque pas le manager : des timings de fallback sûrs restent en mémoire afin que la future surface .env puisse permettre la réparation.
Le shell principal expose les cinq routes de référence Vue d'ensemble, Documents, Profils, Environnement / .env et Logging. Le logo porte déjà l'identité KSP ; le texte du header suit donc la forme Config Desk — <vue active> au lieu de répéter KSP. Les quelques commandes principales restent des pills/tabs à droite ; un dropdown sera préféré lorsqu'une application possède trop de commandes pour conserver ce format lisible. La route Logging expose maintenant un brouillon typé éditable, sa persistence atomique et l’application runtime immédiate par hot reload.
Panneau Profils
La vue Profils inspecte les documents validés qui exposent le contrat standard default_profile / profiles. Elle ne revalide ni ne fusionne les valeurs dans le frontend : le backend utilise ConfigDocumentEngine::load_resolved_profile() puis ResolvedConfigProfile::resolve_effective_environment_detailed().
L'inspection expose le profil par défaut ou une sélection explicite, les vues source globals et profile, ainsi que l'effective après résolution environnementale. Cette dernière est toujours sérialisée depuis ResolvedConfigJson::safe_value() afin qu'une substitution Secret soit redacted. La provenance top-level distingue global / profile; la provenance environnement n'expose que JSON Pointer, nom de variable, source process/.env/fallback et sensibilité, jamais la valeur résolue.
Panneau Logging — édition typée et persistence
La vue Logging charge le document standard exclusivement avec ConfigManagement::load_logging_document(). Rust mappe ensuite les types publics LoggingConfigDocument, LoggingProfileConfig, LoggingConsoleConfig, LoggingFileConfig, LoggingOutputFilterConfig et LoggingTargetFilterConfig vers des DTO TS-RS dédiés. Le frontend ne parse donc ni le JSON source ni son schema.
Le panneau expose format_version, logs_directory, default_profile, tous les profils, la console, les fichiers persistants, les filtres locaux, les target overrides et les listes de targets/domains. Le frontend maintient un brouillon typé : create/clone/rename/delete de profils, 0/1/N file sinks et target filters restent locaux jusqu'à Sauvegarder et appliquer. Le backend reconstruit les types publics Config et appelle ConfigManagement::save_logging_document(), qui valide la totalité du candidat avant remplacement atomique. Après persistence, Config Desk recharge un ConfigEnvironment frais, résout le default_profile, puis appelle ksp_logging_lib::reinitialize() sur le LoggingGuard actif. Le hot reload est immédiat et logging_generation avance uniquement après succès. Si l'application runtime échoue, l'ancien runtime reste actif et la source précédente est restaurée. Recharger le document ne modifie que le brouillon/source persistée.
pre.016 distingue en plus le profil default persistant du profil runtime actif. La section Runtime actif expose le profil actuellement appliqué, selection_source (default_profile, explicit ou fallback), la génération, l'état console, les compteurs de lignes abandonnées et les file sinks réellement actifs. Un profil déjà persisté peut être appliqué explicitement sans modifier default_profile ni écrire le document ; cette action est désactivée tant que le brouillon contient des changements non sauvegardés.
Chaque lancement de Config Desk crée aussi une LoggingRuntimeIdentity stable : application_id + timestamp UTC de démarrage + PID. ksp-logging-lib utilise cette identité pour préfixer les noms des fichiers actifs et la conserve pendant tous les hot reloads du même processus. Deux lancements distincts ne partagent donc plus le même fichier persistant, même avec une rotation daily. Avec la configuration de release info/ksp-info.log, un prefix effectif peut être ksp-app-config-desk.20260816-182519.123Z-p4242.ksp-info.log. Le path Config reste inchangé ; l'identité appartient au runtime, pas au document source.
Baseline Logging de release
La configuration canonique livrée avec 0.1.4 revient à une baseline opératoire info conformément à KSP-APP-031 : console info, sink général info/ksp-info.log au niveau info, et overrides ksp-config-lib, ksp-logging-lib, ksp-app-config-desk à info. Le default_filter reste warn pour les autres targets KSP. Les niveaux debug/trace restent disponibles et peuvent être remontés temporairement depuis Config Desk lors d’un développement ou diagnostic, puis redescendus avant la release suivante.
Traçabilité frontend
Les actions utilisateur significatives et changements d'état sont journalisés en debug; les opérations plus fines (rendu/remplacement DOM, étapes IPC, animations et événements fréquents) en trace. Le wrapper invoke.ts trace début/fin des commandes sans journaliser leurs arguments, afin de ne pas créer ultérieurement de fuite de valeurs sensibles.
Police du splash
Le splash utilise DOS_Amazigh.ttf (font-family: Dos Amazigh) pour son titre, via le @font-face déclaré dans frontend/sass/splash.scss. Le répertoire frontend/fonts/ documente la provenance et l'empreinte de l'asset de référence. Le lifecycle du splash est désormais actif et utilise cette police pendant la transition vers la fenêtre principale.
Panneau Environnement / .env
La vue Environnement / .env expose la projection sûre de ConfigManagement::environment_report() puis une zone de management qui appelle exclusivement ConfigManagement::set_dotenv_value() et ConfigManagement::remove_dotenv_value(). Elle ne lit jamais directement le process environment ni le fichier .env. Pour chaque variable KSP/KSPB actuellement présente dans le process ou .env, le frontend reçoit uniquement : nom, namespace, sensibilité, valeur desired sûre, valeur effective sûre, source effective et indicateur de shadowing.
Les mutations acceptent un nom existant ou nouveau sous KSP_* / KSPB_*, présentent explicitement source_changed, effective_changed, shadowed_by_process_environment et reload_required, puis rechargent le rapport depuis Config. Une ligne du tableau ne précharge que le nom de variable : aucune ancienne valeur réelle n'est injectée dans le formulaire. Pour un namespace Secret, la nouvelle saisie est masquée. Les boutons Révéler effective et Révéler .env ouvrent un flux privilégié distinct : confirmation Bootstrap explicite, commande Tauri dédiée, appel exclusif aux méthodes ConfigManagement::reveal_*, puis affichage temporaire masqué par défaut. Le backend refuse ce flux pour les namespaces non-Secret.
La suppression demande une confirmation via un modal Bootstrap intégré au shell. Les dialogues navigateur natifs window.alert / window.confirm / window.prompt ne sont pas utilisés pour ce flux.
La valeur révélée n'est jamais stockée dans AppState, n'est jamais incluse dans un snapshot/diagnostic/log et est effacée du DOM à la fermeture du modal ou au changement de vue. Aucun localStorage/sessionStorage n'est utilisé.
Les valeurs KSP_SECRET_* / KSPB_SECRET_* restent redacted par ksp-config-lib dans le rapport. La priorité process > .env > fallback reste visible : une mutation .env shadowed peut changer le desired sans modifier l'effective. Les logs frontend/backend n'enregistrent jamais la valeur soumise, seulement le nom de variable, l'opération et les booléens du rapport de changement.