182 lines
16 KiB
Markdown
182 lines
16 KiB
Markdown
<!-- file: crates/ksp-app-config-desk/README.md -->
|
||
<!-- version: 20 -->
|
||
|
||
# `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 :
|
||
|
||
```text
|
||
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 `splash` et `main`, orchestrées par `tw_splash.rs` et `tw_main.rs` ;
|
||
- le frontend Vanilla TypeScript + Vite sous `frontend/` ;
|
||
- SCSS, Bootstrap et Font Awesome ;
|
||
- SimpleBar + `resize-observer-polyfill` pour 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 `.env` et 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_profile` ni le document source ;
|
||
- `tauri-plugin-tracing` côté Rust et `@fltsci/tauri-plugin-tracing` côté frontend ;
|
||
- les ports dédiés `1430` pour Vite HTTP et `1431` pour le WebSocket de développement ;
|
||
- la destination frontend externe commune à Tauri et Vite;
|
||
- le bootstrap Config/Logging réel, un `AppState` durable et le premier contrat Tauri/TS-RS `get_app_snapshot`;
|
||
- le bridge de logging frontend KSP `frontend_log.ts`, routé par `emit_frontend_log` vers des targets statiques whitelistés de `ksp-logging-lib` ;
|
||
- le lifecycle configurable `splash -> main` avec navigation monofenêtre et instrumentation `debug`/`trace` des interactions frontend.
|
||
|
||
## Layout frontend
|
||
|
||
```text
|
||
frontend/
|
||
├── imgs/
|
||
├── sass/
|
||
│ ├── _app.scss
|
||
│ ├── _bootswatch.scss
|
||
│ ├── _fontawesome.scss
|
||
│ ├── _simplebar.scss
|
||
│ ├── _variables.scss
|
||
│ ├── main.scss
|
||
│ └── splash.scss
|
||
├── ts/
|
||
│ ├── environment.ts
|
||
│ ├── frontend_log.ts
|
||
│ ├── invoke.ts
|
||
│ ├── logging.ts
|
||
│ ├── main.ts
|
||
│ ├── profiles.ts
|
||
│ ├── secret_reveal.ts
|
||
│ └── splash.ts
|
||
├── main.html
|
||
└── splash.html
|
||
```
|
||
|
||
Les premiers bindings TS-RS sont générés par les tests `ts-rs` sous :
|
||
|
||
```text
|
||
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.
|
||
|
||
## Artefacts frontend
|
||
|
||
Les artefacts frontend construits ne sont pas versionnés. `tauri.conf.json` fixe :
|
||
|
||
```text
|
||
../../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 :
|
||
|
||
```text
|
||
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 lancé depuis la racine du workspace par Tauri avec la configuration explicite de l'application.
|
||
|
||
|
||
## 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 :
|
||
|
||
```text
|
||
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. Il ne réémet pas encore les événements Rust arbitraires vers la console WebKit : cette direction nécessitera une intégration contrôlée de `tauri_plugin_tracing::WebviewLayer` dans le subscriber possédé par `ksp-logging-lib`, sans second subscriber 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 -c ...` peut sinon lancer le binaire 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.
|
||
|
||
## 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 :
|
||
|
||
```text
|
||
KSP_DESK_SPLASH_MINIMUM_MS=1200
|
||
KSP_DESK_SPLASH_FADE_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`. Exemple d'un prefix effectif : `ksp-app-config-desk.20260816-182519.123Z-p4242.ksp-debug.log`. Le path Config reste inchangé ; l'identité appartient au runtime, pas au document source.
|
||
|
||
## 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.
|