# Plan `0.1.4` — `ksp-app-config-desk` ## 1. Statut, base et objectif Ce plan ouvre `0.1.4` avec `0.1.4-pre.001`. Cette première tranche reste volontairement une tranche de **brainstorming, audit et planification** : elle ne crée pas encore la crate Tauri, n'ajoute aucune dépendance desktop et ne commence pas l'éditeur fonctionnel. Base fournie et auditée : ```text khadhroony-solana-project-v0.1.3.zip workspace.package.version = "0.1.3" deltas/0.1.3/rel.001.md présent ``` L'archive `khadhroony-solana-project-v0.1.3.zip` est l'archive source générée automatiquement par Gitea à partir du tag stable `v0.1.3`, selon le mode de livraison normal du projet. L'absence de métadonnées `.git` à l'intérieur de cette archive est donc attendue et ne constitue pas une réserve sur la provenance de la base : l'archive Gitea nommée d'après le tag est prise comme export matériel de la release stable validée. Ce même principe s'applique aux futures bases KSP fournies sous forme d'archives de tag Gitea. La mission de `0.1.4` est d'introduire la première application desktop spécialisée KSP : ```text ksp-app-config-desk ``` Elle doit valider réellement la surface stable de `ksp-config-lib` et le lifecycle de `ksp-logging-lib`, tout en restant une couche de composition/interface : ```text ksp-app-config-desk -> ksp-config-lib -> ksp-logging-lib -> ksp-core-lib via les contrats KSP nécessaires ``` L'application ne devient propriétaire ni du parsing Config, ni des schemas, ni des placeholders, ni de `.env`, ni de la classification des secrets, ni de la persistence Config, ni du runtime `tracing`. ## 2. Audit exact de la base stable `0.1.3` ### 2.1 Workspace Le workspace stable contient exactement les crates fonctionnelles suivantes : ```text crates/ksp-core-lib crates/ksp-logging-lib crates/ksp-config-lib ``` Les ressources requises par le prompt sont présentes : ```text config/std.logging.json config/schemas/std.logging.schema.json config/schemas/composite.schema.json config/examples/std.logging.example.json config/examples/composite.example.json .env.example ``` Le `Cargo.toml` racine déclare Rust 2024 et les lints KSP attendus. Les dépendances externes communes sont centralisées sous `[workspace.dependencies]`. ### 2.2 Surface Config réutilisable L'audit confirme notamment : - `ConfigBootstrapOptions` pour `--cfgpath` / `--schemapath` ; - `ConfigFileRegistry`, `ConfigFileId`, `ConfigFileDescriptor` et `--filemap` ; - `ConfigDocumentEngine` ; - validation JSON, JSON Schema et sémantique ; - globals, profils, `default_profile` et provenance ; - composites génériques par `file_id` ; - `ConfigEnvironment` avec priorité process > `.env` > fallback ; - placeholders `${NAME}` et `${NAME:-fallback}` ; - sensibilité `Public` / `Internal` / `Secret` ; - représentations réelle/sûre et provenance ; - `ResolvedLoggingConfig::into_settings()` ; - `ConfigManagement` ; - `ConfigManagement::read_source()` pour lire le source d'un document Config enregistré même lorsqu'il est invalide ; - `ConfigManagement::load_logging_document()` / `save_logging_document()` ; - `environment_report()` ; - `reveal_effective_environment_value()` / `reveal_dotenv_value()` ; - `set_dotenv_value()` / `remove_dotenv_value()`. ### 2.3 Lifecycle Logging déjà compatible avec le hot reload `ksp-logging-lib` possède déjà le contrat essentiel de `0.1.4` : ```text initialize(&LoggingSettings) -> LoggingGuard reinitialize(&mut LoggingGuard, &LoggingSettings) -> Result<()> ``` Le nouveau runtime est préparé avant le swap. Une erreur de validation/préparation ou de reload laisse donc le runtime valide précédent actif. `0.1.4` doit **exploiter et démontrer** cette propriété, pas la réimplémenter. ### 2.4 Deux lacunes publiques de Config révélées par l'usage desktop L'audit fait apparaître deux besoins réels qui n'étaient pas nécessaires pour `0.1.3`, mais deviennent bloquants pour un manager extensible. #### A. Inventaire du registre `ConfigFileRegistry` sait : ```text descriptor(file_id) resolve_path(...) ``` mais n'expose pas aujourd'hui de vue publique permettant d'énumérer les descripteurs enregistrés. Construire dans l'application une liste codée en dur de `FILE_ID_*` dupliquerait le registre et empêcherait l'extensibilité demandée. Une petite extension publique de `ksp-config-lib` devra donc fournir une vue en lecture seule/itérable des descripteurs, dans l'ordre déterministe du registre. #### B. Réparation d'un document invalide `ConfigManagement::read_source()` permet volontairement de lire un source invalide. En revanche : ```text load_logging_document() -> nécessite déjà un document valide save_logging_document(&LoggingConfigDocument) -> sauve un candidat typé déjà reconstructible ``` Il n'existe pas encore de frontière publique permettant à une application de soumettre le texte corrigé d'un document enregistré qui était invalide, sans écrire directement le fichier physique. La solution prévue est une API Config bornée, de forme conceptuelle : ```text save_source_candidate(file_id, source_text) ``` Le nom public final sera fixé dans la tranche d'implémentation, mais le contrat est décidé dès maintenant : 1. `file_id` doit être connu et de kind `Config` ; 2. le texte candidat est parsé par Config ; 3. le document est validé contre le schema enregistré ; 4. les invariants sémantiques Config sont exécutés ; 5. rien n'est écrit si une étape échoue ; 6. si tout est valide, Config sérialise/persiste atomiquement le document normalisé ; 7. l'application ne reçoit aucun droit d'écrire un chemin arbitraire. Cette API n'est **pas** un contournement permettant de persister un JSON invalide. Elle constitue précisément la frontière de réparation validée manquante. Ces deux extensions appartiennent à `ksp-config-lib`, avec tests publics/unitaires appropriés ; elles ne doivent pas être simulées dans l'application Tauri. ## 3. Audit des règles Tauri et du gabarit bot3 Référence auditée : ```text khadhroony-bot3_v0.5.3-pre.005-fix010.zip kb-app-demo-desktop ``` La référence est réutilisée par **principes**, pas copiée mécaniquement. ### 3.1 Éléments retenus - package Rust mixte `lib` + `bin` ; - binaire très mince ; - verrou single-instance avant l'entrée Tauri ; - `tauri.rs` centralisant `run` et les wrappers `#[tauri::command]` ; - logique métier/fenêtre hors des wrappers ; - fenêtre `splash` distincte de la fenêtre `main` ; - frontend Vanilla TypeScript + Vite ; - SCSS/SASS et Bootstrap ; - gabarit visuel initial de bot3 comme base à simplifier/affiner, sans recopier les écrans métier ; - même icône de base bot3 (`favicon.png` / `favicon.ico`) tant qu'aucune identité KSP plus spécifique n'est décidée ; - police locale du splash bot3 `DOS_Amazigh.ttf` (`Dos Amazigh`) reprise dans le répertoire `frontend/fonts/` lors de la tranche bootstrap/splash ; - Font Awesome pour l'iconographie ; - SimpleBar pour le scrolling applicatif cohérent et visuellement plus confortable que les scrollbars WebKitGTK par défaut ; - `resize-observer-polyfill` comme dépendance du gabarit pour les composants/layouts qui doivent réagir proprement aux redimensionnements ; - organisation Vite explicite avec frontend sous `frontend/` ; - génération TS-RS à la frontière applicative ; - `LoggingGuard` gardé durablement dans l'état backend. ### 3.2 Éléments à refondre ou ne pas reprendre Le modèle bot3 contient encore : ```text SPLASH_MINIMUM_MS = 12100 SPLASH_FADE_MS = 12000 SPLASH_CLOSE_WAIT_MS = 12100 ``` Ces timings codés en dur ne sont pas retenus. KSP introduira un réglage Config/.env résolu via `ksp-config-lib` au moment où le splash runtime sera implémenté. Le frontend bot3 déclare `@fltsci/tauri-plugin-tracing`, package frontend compagnon de `tauri-plugin-tracing`. L'audit du projet officiel confirme que l'installation recommandée du plugin associe bien la crate Rust et ce package NPM. KSP conserve donc ce couple lorsqu'il introduit le plugin. Bot3 n'utilise toutefois pas directement les helpers JS du package pour son routing applicatif : son `frontend_log.ts` appelle une commande Tauri dédiée avec un niveau, un target frontend explicite et le message. Ce principe est retenu et refondu dans KSP afin de conserver des targets KSP contrôlés et de faire passer l'émission finale par `ksp-logging-lib`. Le package officiel reste disponible pour les capacités réellement utiles du plugin, notamment l'intégration console lorsque celle-ci est compatible avec l'ownership Logging KSP. Les dépendances propres aux nombreuses démos bot3 ne sont pas toutes reprises par défaut. Sont écartées tant qu'un besoin immédiat n'est pas démontré : - ECharts ; - `@andypf/json-viewer` ; - `markdown-it` en l'absence de vue de présentation. SimpleBar et `resize-observer-polyfill` **restent au contraire dans le gabarit frontend KSP** : ils participent au confort et à la robustesse visuelle du shell, notamment pour éviter de dépendre uniquement du scrolling natif WebKitGTK et pour conserver des composants correctement redimensionnés. DataTables n'est pas imposé au tout premier squelette vide, mais il fait partie des composants attendus dès qu'un tableau HTML devient réellement interactif. Dès qu'un panneau requiert tri, filtrage, pagination locale, sélection, cases à cocher ou autres interactions tabulaires structurées, la tranche qui introduit ce besoin doit ajouter/configurer DataTables plutôt que réimplémenter ces fonctions à la main. Le couple bot3 `datatables.net-bs5` + `datatables.net-select-bs5` constitue la référence à réauditer au moment de son introduction. `init_rustls` n'est pas copié par réflexe. Aucun besoin TLS direct de Config Desk n'est identifié. Le helper ne sera introduit que si une dépendance réellement utilisée l'exige. Le helper bot3 d'ouverture/focus de fenêtre est réduit à une primitive commune adaptée au shell (`show/focus` de `main` après splash) ; aucun helper multi-fenêtres générique n'est ajouté sans deuxième usage. ### 3.3 Décision frontend Le frontend de référence pour `0.1.4` sera : ```text Vanilla TypeScript Vite SCSS via sass-embedded Bootstrap Font Awesome Free SimpleBar resize-observer-polyfill DataTables lorsque le premier tableau interactif le justifie ``` Aucun framework React/Vue/Svelte n'est nécessaire pour ce manager spécialisé. Cette décision réduit la surface et reste cohérente avec le modèle bot3 ainsi qu'avec le template Vanilla TypeScript officiellement supporté par Tauri 2. Le premier éditeur raw utilisera un contrôle texte natif correctement stylé ; aucun éditeur de code lourd n'est ajouté tant qu'un besoin fonctionnel ne l'impose pas. ### 3.4 Conventions frontend, artefacts et ports des applications desk Le layout frontend reprend la convention éprouvée de bot3 : les sources web sont contenues dans `frontend/`, les modules TypeScript dans `frontend/ts/`, les styles SCSS dans `frontend/sass/` et les bindings TS-RS générés sous `frontend/ts/bindings/`. Les DTO Rust restent propriétaires de leur contrat ; les fichiers TypeScript générés ne sont jamais édités manuellement et `bindings/` reste ignoré par Git. Les artefacts frontend construits doivent être séparés des sources. Pour `ksp-app-config-desk`, la destination contractuelle est fixée à : ```text ../../builds/khadhroony-solana-project/ksp-app-config-desk/dist ``` Cette valeur est utilisée par `build.frontendDist` dans `tauri.conf.json`. `vite.config.ts` utilise la même destination comme `build.outDir` depuis son introduction en `pre.005`. Elle remplace le `../dist`/`../../dist` historique du gabarit bot3. La gestion npm distingue le runtime frontend du tooling. Les bibliothèques consommées par le bundle appartiennent à `dependencies`; les outils de compilation/développement (`@tauri-apps/cli`, Vite, TypeScript, Sass) et les paquets `@types/*` appartiennent à `devDependencies`. npm est utilisé directement uniquement pour installer ou mettre à jour ces dépendances. Pour la première installation, l'opérateur se place dans `crates/ksp-app-config-desk`, exécute `npm i -D`, puis revient à la racine avec `cd ../../`. Le cycle normal de développement et de build passe ensuite par Tauri depuis la racine du workspace, avec configuration explicite de l'application : `cargo tauri dev -c crates/ksp-app-config-desk/tauri.conf.json` et `cargo tauri build -c crates/ksp-app-config-desk/tauri.conf.json`. Tauri déclenche lui-même `npm run dev` / `npm run build` au travers des hooks configurés. Aucun lockfile npm n'est versionné. Chaque application Tauri desk KSP reçoit un couple de ports Vite/HMR propre. La première application réserve : | Application | Port Vite HTTP | Port HMR | | --------------------- | -------------: | -------: | | `ksp-app-config-desk` | `1430` | `1431` | Les applications suivantes incrémentent le couple de deux ports (`1432/1433`, puis `1434/1435`, etc.). Vite doit utiliser un port strict afin qu'une collision soit signalée au lieu de provoquer un basculement silencieux vers un autre port. Cette allocation permet de faire fonctionner simultanément plusieurs applications desk en mode développement. ## 4. Audit des dépendances actuelles au 2026-08-16 Aucune dépendance n'est ajoutée par `pre.001`. Les versions suivantes ont été revérifiées depuis les registres/documentations officiels afin de fixer la génération candidate à réévaluer **au moment exact de l'ajout** : | Dépendance | Version actuelle auditée | Usage envisagé | | ------------------------------- | -----------------------: | -------------------------------------------- | | `tauri` | `2.11.5` | runtime desktop | | `tauri-build` | `2.6.3` | build Tauri | | `tauri-plugin-tracing` | `0.3.4` | intégration tracing à la frontière Tauri | | `ts-rs` | `12.0.1` | bindings DTO applicatifs | | `fs2` | `0.4.3` | verrou single-instance | | `@fltsci/tauri-plugin-tracing` | `0.3.4` | package frontend compagnon du plugin tracing | | `@tauri-apps/api` | `2.11.1` | frontend Tauri | | `@tauri-apps/cli` | `2.11.4` | dev/build desktop | | `@types/bootstrap` | `5.2.11` | typings Bootstrap | | `vite` | `8.2.1` | build frontend | | `typescript` | `7.0.2` | frontend TypeScript | | `sass-embedded` | `1.102.0` | compilation SCSS | | `bootstrap` | `5.3.8` | composants/layout | | `@fortawesome/fontawesome-free` | `7.3.1` | iconographie | Sources d'audit : - - - - - - - - - - - - - - - - - - - Vite 8 reste compatible avec la direction choisie, mais demande une version Node moderne. Le poste de build devra donc être vérifié contre le prérequis Vite au moment de la création du frontend. ### 4.1 Décision explicite `tauri-plugin-tracing` La version auditée `0.3.4` convient à l'ownership KSP sur un point essentiel : **elle n'installe pas de subscriber global par défaut**. Config Desk devra enregistrer le plugin avec un builder qui n'appelle jamais : ```text with_default_subscriber() ``` Le subscriber global reste exclusivement installé par `ksp-logging-lib::initialize()`. Un autre point a été vérifié dans le source `0.3.4` : la commande JS -> Rust `log` émet actuellement des événements `tracing` avec : ```text target: "" ``` Or `ksp-logging-lib` impose aux target filters configurables un prefix `ksp-` et son takeover runtime est centré sur `ksp-`. Décision `0.1.4` : - intégrer le **plugin Rust** à la frontière Tauri sans subscriber propre ; - intégrer son package frontend compagnon `@fltsci/tauri-plugin-tracing` dans le gabarit desktop au même moment ; - ne pas utiliser `with_default_subscriber()` ; - ne pas installer une seconde pile `tracing-subscriber` dans l'application ; - ne pas détendre la politique `ksp-*` de `ksp-logging-lib` uniquement pour faire passer le target vide de la commande JS standard du plugin ; - reprendre/refondre le pont `frontend_logging` de bot3 : helpers TypeScript -> commande Tauri dédiée -> service Rust -> façade `ksp-logging-lib` ; - normaliser/whitelister les targets frontend et de test côté Rust afin qu'un texte arbitraire reçu depuis la webview ne devienne jamais un target de callsite arbitraire ; - utiliser le package officiel pour les fonctions réellement utiles du plugin (`attachConsole` ou autre) uniquement lorsque leur comportement reste compatible avec le runtime KSP ; - le bridge KSP actuel couvre WebView -> Rust et conserve les appels JavaScript dans la console WebKit, mais ne couvre pas encore Rust -> WebKit ; avec le subscriber custom de KSP, `attachConsole()` requiert une `tauri_plugin_tracing::WebviewLayer` intégrée au subscriber possédé par `ksp-logging-lib` ; cette capacité sera ajoutée seulement via un adapter qui préserve cet ownership ; - ne pas utiliser directement `interceptConsole()` / `takeoverConsole()` comme unique pont JS -> Rust si cela produit des événements impossibles à router selon les targets KSP ou une boucle/double émission avec le bridge KSP ; - pour les événements de test Logging de `0.1.4`, utiliser la façade/macros de `ksp-logging-lib` avec un target KSP contrôlé et un `domain` structuré optionnel ; - revérifier ce point lors de l'introduction réelle des dépendances, car une nouvelle version du plugin pourrait étendre son contrat frontend. `tauri-plugin-log` est **explicitement exclu**. ## 5. Layout interne cible de `crates/ksp-app-config-desk` La crate sera ajoutée directement sous : ```text crates/ksp-app-config-desk ``` Layout cible : ```text crates/ksp-app-config-desk/ ├── Cargo.toml ├── README.md ├── USAGE.md ├── build.rs ├── package.json ├── tsconfig.json ├── vite.config.ts ├── tauri.conf.json ├── capabilities/ ├── icons/ ├── frontend/ │ ├── main.html │ ├── splash.html │ ├── ts/ │ │ ├── main.ts │ │ ├── splash.ts │ │ ├── invoke.ts │ │ ├── frontend_log.ts │ │ ├── state.ts │ │ └── bindings/ # généré, ignoré │ └── sass/ │ ├── main.scss │ ├── splash.scss │ └── _shared.scss ├── src/ │ ├── main.rs │ ├── lib.rs │ ├── tauri.rs │ ├── app_state.rs │ ├── bootstrap.rs │ ├── errors.rs │ ├── config_service.rs │ ├── environment_service.rs │ ├── logging_service.rs │ ├── secret_service.rs │ ├── splash.rs │ ├── tw_main.rs │ ├── tw_splash.rs │ ├── dto_common.rs │ ├── dto_documents.rs │ ├── dto_environment.rs │ ├── dto_logging.rs │ └── dto_secret.rs ├── unit_tests/ │ └── ... miroir des modules Rust testés └── tests/ └── ... API publique / intégration bornée ``` Le layout pourra être ajusté lors de la création réelle si Tauri 2 impose un fichier généré spécifique, mais les responsabilités ci-dessous sont fixées. ### 5.1 Contrat `lib` + `bin` Le package est mixte : ```text package : ksp-app-config-desk lib : ksp_app_config_desk_lib bin : ksp-app-config-desk ``` `main.rs` reste minimal : 1. construire/acquérir le verrou single-instance ; 2. collecter les arguments de processus nécessaires au bootstrap ; 3. appeler l'entrée `run(...)` de la bibliothèque ; 4. convertir explicitement le résultat en `ExitCode`. `main.rs` ne lit pas `KSP_*` / `KSPB_*` et ne parse pas lui-même Config. `lib.rs` est limité aux déclarations de modules et réexports réellement nécessaires. `tauri.rs` possède : - `run` ; - le `tauri::Builder` ; - l'enregistrement du plugin tracing ; - l'enregistrement du state ; - **toutes** les annotations `#[tauri::command]` ; - les wrappers très minces qui délèguent aux services/modules ; - les helpers Tauri réellement transverses de démarrage/fenêtres. La construction du runtime Tauri doit rester lisible et facilement désactivable par étape. `run` ne doit donc pas accumuler une longue chaîne de `.plugin(...).manage(...).setup(...).invoke_handler(...)`. La convention cible est une variable builder construite/réassignée progressivement, éventuellement via des helpers courts : ```text let mut builder = tauri::Builder::default(); builder = configure_tracing(builder, ...); builder = configure_state(builder, ...); builder = configure_plugins(builder, ...); builder = configure_setup(builder, ...); builder = configure_commands(builder, ...); ``` Le code Rust final respectera évidemment les signatures réelles de Tauri et les règles KSP de retours explicites. L'objectif architectural est qu'un plugin, un bloc de setup ou un groupe de commandes puisse être commenté/désactivé temporairement sans devoir démanteler ou reformater une chaîne de builder monolithique. Aucune annotation `#[tauri::command]` n'est dispersée dans `config_service.rs`, `logging_service.rs`, `tw_*`, etc. ### 5.2 Convention `tw_*` `tw_*` est retenu pour les modules liés à une fenêtre Tauri : ```text tw_main.rs tw_splash.rs ``` Les opérations métier ne sont pas placées dans ces modules. Le shell fonctionnel reste essentiellement monofenêtre ; `tw_main` orchestre la fenêtre, pas la logique Config. ## 6. Modèle d'état applicatif et ownership de `LoggingGuard` L'état backend cible est conceptuellement : ```text AppState ├── ConfigManagement └── Mutex ├── LoggingGuard ├── active_profile_id └── generation/revision runtime ``` Principes : - `ConfigManagement` reste la façade de management ; - son `ConfigDocumentEngine` porte bootstrap + registry ; - `ConfigEnvironment::load()` produit un snapshot frais lorsqu'une résolution runtime doit refléter le process/`.env` courant ; - `LoggingGuard` vit aussi longtemps que l'application ; - guard + métadonnées du profil actif sont protégés ensemble pour éviter un état incohérent après reload ; - l'identifiant de profil actif n'est modifié qu'après succès de `reinitialize()` ; - un échec conserve guard, profil actif et génération précédents. ### 6.1 Bootstrap Logging initial Ordre cible : ```text argv -> ConfigBootstrapOptions / ConfigFileRegistry via ksp-config-lib -> ConfigDocumentEngine -> ConfigEnvironment::load() -> load_resolved_logging_config(None, env) -> ResolvedLoggingConfig::into_settings() -> ksp_logging_lib::initialize(...) -> LoggingGuard -> AppState -> tauri::Builder ``` `None` utilise le `default_profile` du document Logging. Une sélection explicite ultérieure est faite depuis l'UI. Si le document Logging est invalide au démarrage, l'application doit quand même pouvoir devenir un outil de réparation. Il faudra donc prévoir un **fallback de bootstrap applicatif sûr** qui ne duplique pas la configuration Logging : par exemple démarrer avec un settings KSP minimal construit par l'application uniquement pour rendre le manager utilisable, tout en affichant clairement le diagnostic Config. Le contrat exact de ce fallback sera implémenté/testé dans la tranche bootstrap ; il ne doit jamais remplacer silencieusement la configuration utilisateur ni être persisté automatiquement. Ce fallback est un point de vigilance : sans lui, l'exigence « afficher le source brut invalide afin de permettre sa réparation » serait impossible lorsque `std.logging.json` lui-même empêche le démarrage. ## 7. Shell et écrans/panneaux minimums Décision : **une fenêtre principale de management**, plus le splash de démarrage. Les fonctions sont des panneaux/routes internes, pas une collection de fenêtres séparées. Navigation minimum : ```text Vue d'ensemble Documents Profils Environnement / .env Logging ``` ### 7.1 Vue d'ensemble Affiche uniquement des informations sûres : - racines bootstrap Config ; - nombre de documents Config enregistrés ; - état valide/invalide des documents inspectés ; - profil Logging runtime actif ; - génération/revision de reload ; - présence de shadowing environnement ; - dernier résultat de mutation/test `.env` ; - dernier résultat de test Logging interactif. ### 7.2 Documents Fonctions : - lister les documents de kind `Config` issus du registre Config ; - afficher `file_id`, filename mappé, schema associé et path résolu ; - charger/valider un document via Config ; - classifier l'erreur ; - en cas d'invalidité, afficher le source brut fourni par `ConfigManagement::read_source()` ; - permettre l'édition du texte puis soumettre le candidat à l'API Config de réparation validée ; - recharger le document après succès. L'UI n'utilise ni `JSON.parse` comme validateur de vérité, ni un schema frontend dupliqué pour décider si la sauvegarde est valide. Un parsing frontend éventuel ne sert qu'à l'ergonomie ; l'autorité est le résultat backend Config. ### 7.3 Profils Le premier document spécialisé est Logging. L'UI doit montrer : - `default_profile` ; - profils disponibles ; - profil explicitement sélectionné pour inspection ; - source de sélection (`default_profile` ou explicite) ; - globals ; - contenu du profil ; - effective après résolution environnement ; - provenance utile sans valeur Secret réelle. L'inspection générique par `file_id` reste prévue dans le shell, mais `0.1.4` ne crée pas d'éditeur générique de tout schema inconnu. ### 7.4 Environnement / `.env` Ce panneau est une **surface fonctionnelle de validation de `ksp-config-lib`**, pas un simple écran de diagnostic. Il doit permettre de vérifier le comportement réel de `ConfigEnvironment` et `ConfigManagement` sans lecture/écriture directe de `.env` depuis l'application. Il comporte deux zones complémentaires. #### 7.4.1 Rapport desired/effective La table est alimentée uniquement par `ConfigManagement::environment_report()` et expose les variables KSP/KSPB présentes dans le process ou `.env` : - nom ; - namespace KSP/KSPB ; - sensibilité `Public` / `Internal` / `Secret` ; - `desired_safe_value` persistée dans `.env` ; - `effective_safe_value` ; - source effective `process` / `.env` ; - indicateur `shadowed_by_process_environment` ; - actions management adaptées à la ligne ; - action privilégiée « Révéler » séparée pour les valeurs réelles. Aucune valeur réelle Secret n'est nécessaire pour construire cette table. #### 7.4.2 Management/test `.env` Une zone d'édition dédiée permet de tester réellement les frontières déjà fournies par Config : ```text Variable : variable existante | nouveau nom KSP_*/KSPB_* Valeur : champ d'édition, masqué lorsqu'il s'agit d'un Secret Actions : Créer/Modifier | Supprimer | Recharger le rapport Résultat : source_changed | effective_changed | shadowed | reload_required ``` Règles : - création/modification uniquement via `ConfigManagement::set_dotenv_value()` ; - suppression uniquement via `ConfigManagement::remove_dotenv_value()` ; - le backend Config reste seul responsable de la validation du nom, de l'encodage `.env`, de la persistence atomique et du rechargement de ses snapshots ; - l'application ne lit pas le fichier `.env` brut et ne reconstruit pas son format ; - après chaque mutation, le rapport est rechargé depuis Config afin de montrer l'état réellement persisté/effectif ; - le résultat `ConfigEnvironmentChangeReport` est présenté explicitement à l'opérateur ; - une valeur process héritée n'est jamais modifiée par l'application. Après une mutation `.env`, l'UI doit donc pouvoir afficher sans ambiguïté : ```text source_changed = true|false effective_changed = true|false shadowed_by_process = true|false reload_required = true|false ``` Le scénario de shadowing est un test fonctionnel obligatoire. Si par exemple le process fournit une variable et `.env` contient une autre valeur pour le même nom, une modification de `.env` doit changer la valeur desired mais laisser la valeur effective issue du process inchangée. L'UI doit expliquer que la priorité reste : ```text process > .env > fallback de placeholder ``` et qu'un processus enfant ne peut pas modifier l'environnement déjà hérité de son parent. Le scénario reproductible de validation pourra lancer l'application avec `KSP_LOGS_DIRECTORY=` dans l'environnement du process, puis modifier la même variable dans `.env` depuis le panneau et vérifier que la valeur effective reste celle du process. Le panneau sert aussi à valider le lien entre `.env` et la résolution des documents Config. La base stable fournit déjà un cas reproductible : ```text config/std.logging.json logs_directory = "${KSP_LOGS_DIRECTORY:-logs}" ``` Une modification de `KSP_LOGS_DIRECTORY` via le panneau doit pouvoir être suivie d'une nouvelle résolution Config/Logging et rendre observable la nouvelle valeur effective/provenance, **sans que le frontend résolve lui-même le placeholder**. Si une variable process masque `KSP_LOGS_DIRECTORY`, le test doit au contraire démontrer que la modification `.env` n'affecte pas la résolution effective tant que le process reste prioritaire. Pour une variable `Secret`, l'ancienne valeur réelle n'est pas préchargée automatiquement dans le formulaire. Une nouvelle valeur peut être saisie explicitement pour remplacement ; la consultation de l'ancienne valeur passe exclusivement par le flux reveal privilégié décrit plus loin. ### 7.5 Logging Éditeur spécialisé et typé couvrant au minimum : - `default_profile` ; - création d'un profil ; - duplication d'un profil ; - renommage ; - suppression avec garde sur `default_profile` ; - filtre par défaut ; - span events ; - console enabled/output/ANSI/format/filter ; - plusieurs fichiers ; - `output_id` ; - path ; - rotation ; - format ; - filtres level/targets/domains ; - target filters ; - sauvegarde ; - sélection d'un profil à appliquer ; - hot reload ; - émission d'événements de test contrôlés depuis l'UI. Les opérations frontend produisent des DTO applicatifs ; le service Rust reconstruit/utilise les types publics `LoggingConfigDocument` et sous-contrats de `ksp-config-lib`. Le frontend ne fabrique pas directement le JSON persistant comme source d'autorité. ### 7.6 Test Logging interactif Le panneau Logging comporte une zone de test manuelle destinée à prouver le routing réel du runtime actif après sauvegarde/reload. Contrôles minimums : ```text Message : texte libre explicitement destiné au log de test Niveau : trace | debug | info | warn | error | tous Target : select de targets KSP contrôlés Domain : aucun | domaine connu | personnalisé Bouton : Log ``` Le message n'est jamais prérempli depuis Config, un diagnostic, un reveal Secret ou un état contenant une valeur réelle. L'UI indique explicitement que le contenu sera journalisé et ne doit contenir aucune donnée sensible. Le mode `tous` émet le même message de test aux cinq niveaux avec un identifiant de test commun afin de visualiser immédiatement les seuils de filtrage. Le target n'est pas un texte Rust arbitraire. Le frontend transmet un `target_id` appartenant à une liste exposée par l'application, par exemple : ```text config_desk frontend logging_test config_test tauri ``` Le service Rust mappe ces identifiants vers des callsites/targets KSP fixes tels que : ```text ksp-app-config-desk ksp-app-config-desk.frontend ksp-app-config-desk.test.logging ksp-app-config-desk.test.config ksp-app-config-desk.tauri ``` Le `domain`, au contraire, reste un champ structuré distinct du target. Le select peut proposer les domaines utilisés par la configuration Logging chargée, des domaines de test prédéfinis et une option personnalisée. Une valeur personnalisée reste un champ d'événement et ne modifie pas le target propriétaire. Le bouton `Log` appelle une commande Tauri dédiée. L'émission backend utilise uniquement `ksp-logging-lib`; aucune commande applicative n'appelle directement `tracing` pour posséder le routing. Le résultat retourné à l'UI contient au minimum l'identifiant du test, les niveaux émis, le target sélectionné, le domaine sélectionné et la génération du runtime actif, mais ne recopie pas inutilement le message. En parallèle, le `frontend_log.ts` commun reprend/refond le mécanisme bot3 pour les logs techniques du frontend et le bridge console. Il passe par une commande `emit_frontend_log` séparée et des targets frontend whitelistés. Les deux chemins peuvent partager le même service d'émission Rust sans confondre leurs DTO et leurs responsabilités. Le shell applique également une instrumentation frontend systématique : clics et transitions d’état significatives en `debug`; rendu, remplacement de sections, événements fréquents et étapes techniques en `trace`. Les wrappers IPC journalisent le début et la fin des chargements sans recopier les arguments ou payloads susceptibles de devenir sensibles. Cette convention devient le modèle des futures applications desk KSP. ## 8. Matrice commandes Tauri / services / APIs KSP Les noms ci-dessous sont les noms fonctionnels cibles ; ils pourront être normalisés avant implémentation, mais leurs responsabilités sont fixées. | Commande Tauri | Service interne | API KSP principale | Secret réel ? | | ------------------------------ | ------------------------------------ | --------------------------------------------------------------------------- | -------------------------------------------: | | `get_app_snapshot` | `config_service` + `logging_service` | registry/management + runtime state | non | | `list_config_documents` | `config_service` | future vue publique du `ConfigFileRegistry` | non | | `inspect_config_document` | `config_service` | `load_validated_document` + `read_source` si erreur | non | | `save_config_source_candidate` | `config_service` | future API Config de réparation validée | non | | `inspect_profile` | `config_service` | `load_resolved_profile` + résolution détaillée | non | | `get_environment_report` | `environment_service` | `ConfigManagement::environment_report` | non | | `set_dotenv_value` | `environment_service` | `ConfigManagement::set_dotenv_value` + rapport frais | entrée potentiellement Secret, jamais loggée | | `remove_dotenv_value` | `environment_service` | `ConfigManagement::remove_dotenv_value` + rapport frais | non | | `reveal_environment_value` | `secret_service` | `reveal_effective_environment_value` ou `reveal_dotenv_value` | **oui** | | `get_logging_editor` | `logging_service` | `load_logging_document` | non | | `save_logging_document` | `logging_service` | `save_logging_document` | non par design Logging | | `apply_logging_profile` | `logging_service` | `ConfigEnvironment::load` + `load_resolved_logging_config` + `reinitialize` | valeurs resolved possibles, jamais DTO/log | | `emit_frontend_log` | `frontend_logging_service` | façade `ksp-logging-lib` | non, message technique frontend seulement | | `emit_logging_test` | `logging_service` | façade/macros `ksp-logging-lib` | non, message explicitement saisi pour test | | `splash_frontend_ready` | `splash` | lifecycle Tauri + settings splash déjà résolus | non | Tous les wrappers dans `tauri.rs` : - retournent explicitement `Ok`/`Err` ; - n'utilisent ni `?`, ni `unwrap`, ni `expect`, ni `panic` ; - ne contiennent pas la logique métier ; - convertissent les erreurs vers un DTO sûr sans sérialiser aveuglément `Error::context()`. ## 9. Matrice DTO ordinaires / DTO secrets ### 9.1 DTO ordinaires Familles prévues : ```text AppSnapshotDto ConfigDocumentDescriptorDto ConfigDocumentInspectionDto ConfigDiagnosticDto ProfileInspectionDto EnvironmentVariableReportDto DotenvMutationRequestDto EnvironmentMutationResultDto LoggingDocumentDto LoggingProfileDto LoggingConsoleDto LoggingFileDto LoggingFilterDto LoggingRuntimeDto FrontendLogPayloadDto LoggingTargetOptionDto LoggingTestRequestDto LoggingTestResultDto ``` Règles : - valeurs environnement = safe/redacted uniquement ; - aucun champ « real_value » générique ; - aucune copie brute d'un contexte d'erreur pouvant contenir une donnée sensible ; - `ConfigDiagnosticDto` contient au minimum domaine/code/message/catégorie + métadonnées sûres connues de la requête (`file_id`, éventuellement path Config), jamais une source externe arbitraire ; - bindings TS-RS dans la crate applicative. ### 9.2 Classification des diagnostics L'application classe par **ErrorCode stable**, pas par parsing du texte : ```text Json Schema Semantic Effective Environment BootstrapOrMapping PersistenceOrManagement RuntimeLogging Tauri ``` Exemples : - `json_syntax_invalid` -> `Json` ; - `schema_invalid` / `schema_validation_failed` -> `Schema` ; - `document_semantic_invalid` -> `Semantic` ; - `effective_config_invalid` -> `Effective` ; - erreurs de placeholder/variable -> `Environment`. ### 9.3 DTO secret privilégié Le reveal utilise une commande et des DTO **séparés** : ```text SecretRevealRequestDto SecretRevealResponseDto ``` Le response DTO : - est sérialisable vers Tauri ; - n'est pas incorporé dans un snapshot global ; - n'est pas mis en cache dans `AppState` ; - n'est pas cloné/Debug par convenance ; - n'est jamais inclus dans un diagnostic/log. Le frontend : - n'appelle reveal qu'après action explicite sur une variable nommée ; - affiche un modal de confirmation mentionnant la variable et la source demandée ; - affiche le secret dans un contrôle transitoire masqué par défaut ; - retire la valeur du state frontend à la fermeture/changement de panneau ; - n'utilise ni localStorage, ni sessionStorage, ni persistance automatique pour cette valeur. ## 10. Modèle d'autorisation pour les secrets en `0.1.4` Le threat model de la première version est la **prévention de divulgation accidentelle** dans les DTO généraux, logs, diagnostics, snapshots et état UI persistant. L'application est locale et hérite de l'authentification de la session desktop qui l'exécute. `0.1.4` n'introduit pas de mot de passe KSP maison, de biométrie, de keychain ni de secrets manager distant. L'autorisation applicative retenue est donc : 1. le reveal n'existe que dans une commande Tauri distincte ; 2. la requête porte exactement le nom de variable et la source (`effective` ou `.env`) ; 3. le frontend impose une confirmation utilisateur explicite juste avant l'appel ; 4. le backend revérifie que le nom appartient bien aux namespaces KSP/KSPB et applique sa policy de reveal ; 5. seule la méthode `reveal_*` Config est appelée ; 6. la réponse n'est jamais conservée dans l'état backend ; 7. aucun log, bridge frontend ou test Logging ne reçoit automatiquement la valeur. Cette barrière n'est pas présentée comme une ré-authentification forte contre une webview déjà compromise. Une auth OS forte éventuelle est hors scope de `0.1.4` et devra être conçue séparément si le threat model futur l'exige. ## 11. Hot reload Logging : flux et preuve observable ### 11.1 Sauvegarde et application restent deux opérations Flux : ```text éditer -> sauver document via Config -> choisir profil à appliquer -> construire ConfigEnvironment frais -> load_resolved_logging_config(Some(profile), env) -> into_settings() -> reinitialize(guard, settings) -> succès : mise à jour metadata runtime -> échec : runtime précédent inchangé ``` La sauvegarde ne doit pas déclencher implicitement un reload. Cela permet d'éditer plusieurs profils sans changer le runtime et rend les erreurs/rollback compréhensibles. ### 11.2 Événement de test interactif et séquence multi-niveaux `emit_logging_test` reçoit uniquement les valeurs explicitement saisies/sélectionnées dans le panneau de test : ```text message action level = trace | debug | info | warn | error | all target_id domain optionnel ``` Le backend valide `target_id`, choisit un callsite KSP fixe, puis émet via `ksp-logging-lib`. Le `domain` est ajouté comme champ structuré lorsqu'il est présent. Chaque action reçoit un identifiant unique non sensible. En mode `all`, le backend émet la même intention de test aux cinq niveaux afin de tester le seuil de chacun des sinks. Exemple de campagne manuelle : ```text message = "routing-test-42" target = ksp-app-config-desk.test.logging domain = logging.hot-reload level = all ``` La démonstration peut ainsi vérifier qu'après reload : - un sink apparaît/disparaît ; - un format change ; - un niveau/routing change ; - un target est accepté/refusé par un output ; - un domain est accepté/refusé par un output ; - la console reçoit ou non l'événement ; - un fichier distinct reçoit l'événement correspondant. Le bridge technique `frontend_log.ts` est testé séparément avec au moins un événement frontend identifiable afin de prouver que les logs de la webview rejoignent le même runtime KSP sans seconde pile de logging. ### 11.3 Profil invalide Test obligatoire : ```text runtime A valide actif -> tentative apply B invalide -> erreur -> événement de test suivant toujours routé selon A ``` La réussite de ce scénario ferme le critère « une erreur de nouvelle configuration ne détruit pas le runtime Logging déjà valide ». ## 12. Matrice fonctionnelle de clôture Logging La release ne peut pas être clôturée sans preuve des cas suivants : | Cas | Action UI | Résultat attendu | | --- | ----------------------------- | ------------------------------------------------------------------------------ | | L1 | créer un second profil | profil ajouté via types Config et sauvegardable | | L2 | modifier le profil existant | mutation persistée via `save_logging_document()` | | L3 | profil mono-fichier | console optionnelle + exactement un sink fichier valide | | L4 | profil multi-fichiers | au moins deux sinks fichier distincts + sortie logiciel/console | | L5 | sauvegarder sans appliquer | source change, runtime reste inchangé | | L6 | sélectionner/appliquer profil | `load_resolved_logging_config` + `reinitialize` réussissent | | L7 | message + niveau avant/après | changement de routing/format/sink observable sans redémarrage | | L8 | changer target de test | routing target observable selon la configuration active | | L9 | changer domain de test | routing domain observable selon la configuration active | | L10 | mode `tous` | seuils trace/debug/info/warn/error vérifiables en une campagne | | L11 | log frontend via bridge | événement frontend identifiable rejoint le runtime KSP | | L12 | appliquer config invalide | erreur visible, runtime précédent reste fonctionnel et le bouton Log le prouve | | L13 | redémarrer l'app | profil/default persisté retrouvé selon le document sauvegardé | | L14 | modifier default profile | nouveau `default_profile` validé/persisté par Config | | L15 | redémarrer plusieurs fois | chaque lancement écrit dans un fichier applicatif distinct horodaté | | L16 | clôturer la release | target applicatif ramené à `info` ou `warn` dans le profil de référence | La démonstration de clôture conservera deux profils de test reproductibles, sans dépendre de données secrètes. ## 13. Splashscreen commun ### 13.1 Décision de `0.1.4` `0.1.4` établit la **référence canonique** du lifecycle splash KSP, mais ne crée pas prématurément une nouvelle crate `ksp-tauri-lib` avec un seul consumer. Le splash sera isolé proprement : ```text backend : splash.rs + tw_splash.rs frontend: splash.ts + splash.scss + splash.html ``` Les helpers ne sont pas recopiés entre fenêtres. Lorsque la deuxième application Tauri KSP sera introduite, elle devra réutiliser/extracter cette capacité commune au lieu de copier le code. Si un deuxième consumer apparaît avant la clôture de `0.1.4`, l'extraction en crate/module partagé pourra être avancée par delta explicite. ### 13.2 Configuration Aucune durée sensible à l'environnement n'est codée en dur par application. Le besoin runtime devra au minimum distinguer ce qui est réellement nécessaire, par exemple : ```text minimum display duration fade duration close delay si techniquement distinct ``` `pre.008` fige les deux clés communes nécessaires au lifecycle de référence : ```text KSP_DESK_SPLASH_MINIMUM_MS=1200 KSP_DESK_SPLASH_FADE_MS=300 ``` Elles sont résolues uniquement via `ConfigEnvironment` avec priorité process > `.env` > fallback. `KSP_DESK_SPLASH_MINIMUM_MS` est bornée à 60 000 ms et `KSP_DESK_SPLASH_FADE_MS` à 10 000 ms. Une valeur invalide ne doit pas rendre Config Desk inutilisable : l’application conserve les timings de fallback en mémoire, journalise seulement domaine/code de l’erreur et laisse la future surface `.env` permettre la réparation. Le frontend ne reçoit que la durée d’animation réellement nécessaire dans les ordres du splash; la durée minimale reste backend. La référence temporelle est la readiness frontend : Rust émet `fade_in`, attend `minimum`, émet `fade_out`, attend `fade`, puis affiche/focalise `main` et détruit `splash`. Aucun close delay distinct n’est nécessaire. Avec `minimum=12000` et `fade=3000`, le lifecycle backend attendu est donc proche de `15000 ms`, et non des trois délais indépendants historiques de bot3. `tw_splash` journalise en `debug` la provenance des valeurs, les attentes configurées et réellement observées ainsi que la durée totale. Les variables sont ajoutées à `.env.example` dans `pre.008`. ### 13.3 Racine runtime en développement Avec le workflow workspace `cargo tauri dev -c crates/ksp-app-config-desk/tauri.conf.json`, Tauri peut lancer le binaire Rust avec la crate applicative comme current working directory. Les defaults Config `config/`, `config/schemas/` et `.env` sont cependant des chemins de projet enracinés à la racine du workspace. En build debug, le launcher replace donc le CWD sur `env!("CARGO_MANIFEST_DIR")/../..` **avant** le bootstrap Config. Il ne lit aucune ressource KSP lui-même ; `ksp-config-lib` continue à gérer paths, `.env`, precedence et validation. Un runtime distribué ne doit pas dépendre de cette racine source et sera cadré séparément. ### 13.4 Header et navigation Le logo de Config Desk porte déjà l’identité graphique KSP. Le header ne répète donc pas `KSP` en texte : il suit `Config Desk — `. Les cinq commandes principales restent des tabs/pills alignées à droite tant que leur nombre reste compact ; les futures applications qui dépassent cette surface utiliseront un dropdown. Les clics/changements de tabs sont tracés (`trace` pour le clic/état technique, `debug` pour l’activation utilisateur significative). ## 14. Présentation et Markdown Décision explicite : **aucune vue de présentation dans `0.1.4`**. L'application est un manager monofenêtre avec navigation fonctionnelle. En conséquence : ```text PRESENTATION.md : absent markdown-it : absent ``` `README.md` reste la documentation du package et n'est jamais chargé dans une webview. Si une future version ajoute réellement une vue de présentation, elle ouvrira alors le besoin `PRESENTATION.md` + `markdown-it` et appliquera la règle d'absence de liens navigables dans le contenu affiché. ## 15. Extensibilité des futurs `file_id` / schemas / éditeurs L'extensibilité est structurée en trois niveaux. ### 15.1 Shell générique Le shell sait : - demander à Config quels documents sont enregistrés ; - afficher leurs descripteurs ; - demander validation/diagnostic/source ; - afficher les diagnostics sans connaître le schema métier. Il ne code pas la liste `cfg.std.logging` comme unique vérité du système. ### 15.2 Adapter d'éditeur spécialisé Logging est le premier adapter spécialisé : ```text file_id = cfg.std.logging editor = LoggingEditor ``` Le frontend possède une table/registry applicative simple d'éditeurs disponibles, basée sur `file_id`. Un futur document pourra ajouter : ```text file_id -> panel/editor spécialisé ``` sans modifier le moteur générique de liste/diagnostic/source. ### 15.3 Config reste propriétaire Même avec un éditeur spécialisé : ```text DTO UI -> service app -> type public ksp-config-lib -> validation/persistence ksp-config-lib ``` Aucun nouvel éditeur ne reçoit une API de filesystem directe ni ne transporte son propre validateur autoritatif. ### 15.4 Implémentation `pre.018` Le shell applicatif matérialise désormais cette architecture dans `frontend/ts/shell_registry.ts` : les vues sont décrites dans un registre unique et les adapters spécialisés sont déclarés séparément par `file_id`. Le panneau Documents interroge ce registre pour afficher ou non **Ouvrir l'éditeur spécialisé** ; il ne contient aucune branche métier Logging. Le premier mapping est `cfg.std.logging -> logging`. Le bootstrap Logging sépare également la **résolution du plan de démarrage** de l'**installation du subscriber**. Une source invalide peut ainsi être testée comme plan fallback sans initialiser le subscriber global du binaire de tests. La validation frontend de `pre.018` utilise `npm run check` pour **`tsc --noEmit` uniquement**. Le build Vite de production n'est pas lancé séparément : `cargo tauri build` déclenche déjà `npm run build` via `beforeBuildCommand`. Pour KSP, le build Tauri est réservé à la **dernière validation**, après `fmt/check/clippy`, les tests, le type-check frontend et le parcours fonctionnel `tauri dev`. ## 16. Stratégie de tests ### 16.1 `ksp-config-lib` Pour les deux extensions révélées par l'audit : - unit tests hors `src`, structure miroir ; - tests de registre : ordre, kind, schema, override conservé ; - tests de réparation : JSON invalide refusé, schema invalide refusé, sémantique invalide refusée, source valide atomiquement persistée, path arbitraire impossible ; - test public d'usage depuis `tests/` si le contrat public le justifie. ### 16.2 Rust applicatif Tests ciblés : - conversion sûre `ksp_core_lib::Error` -> diagnostic DTO ; - aucune valeur de contexte sensible recopiée ; - mapping DTO Logging -> contrats Config ; - mapping rapports Environment -> DTO safe ; - mutations `.env` via services uniquement, sans accès filesystem applicatif ; - propagation de `source_changed` / `effective_changed` / `shadowed` / `reload_required` ; - AppState : metadata runtime ne change qu'après reload réussi ; - policy reveal ; - test Logging : validation niveau/target_id/domain, mapping vers callsites KSP fixes et mode multi-niveaux ; - frontend logging : normalisation des targets whitelistés et dispatch par niveau ; - splash settings : bornes et lifecycle ; - single-instance helper lorsque testable sans flakiness. Pendant le développement : ```text cargo test -p ksp-config-lib cargo test -p ksp-app-config-desk ``` selon la tranche. ### 16.3 Frontend Le frontend reste suffisamment mince pour ne pas nécessiter dès le départ un framework de test lourd. Les validations minimum prévues : - `tsc` strict ; - build Vite ; - tests de fonctions pures TypeScript uniquement si une logique non triviale apparaît ; - parcours manuel reproductible du panneau `.env` (create/update/delete/reload/shadowing) ; - parcours manuel reproductible des panneaux et de la matrice Logging. Si des fonctions UI critiques deviennent suffisamment complexes, un runner de tests sera ajouté seulement au moment du besoin réel. ### 16.4 Tauri / intégration Les commandes sont testées principalement via leurs services Rust sans lancer une webview. Les points nécessitant Tauri réel sont validés par : - build Tauri ; - lancement `tauri dev` ; - splash -> main ; - single-instance ; - commandes invoke ; - mutations `.env` observables via rapport frais, sans accès fichier direct ; - démonstration du shadowing process > `.env` ; - démonstration d'une nouvelle résolution de `${KSP_LOGS_DIRECTORY:-logs}` après mutation `.env` non shadowée ; - hot reload Logging observable ; - absence de crash après échec de reload. ### 16.5 Frontières globales Après toute modification Rust : ```text cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets ``` Les tests ciblés par package sont privilégiés pendant les tranches. `cargo test --workspace` est obligatoire : - à l'ouverture globale si nécessaire pour confirmer la base ; - à la fermeture finale de `0.1.4` ; - lors d'une tranche transversale qui le justifie explicitement. Les `cargo tree` pertinents seront exécutés après ajout/modification des dépendances Tauri/Config/Logging et à la clôture. Côté frontend, les commandes de build/test retenues seront ajoutées au `package.json` et exécutées dans les tranches concernées. ## 17. Hors scope confirmé `0.1.4` n'ouvre pas : - Wallet ; - Store/PostgreSQL ; - RPC/WS/provider ; - Program/decoder/executor ; - workers/jobs/pipelines ; - trading/ML ; - nouveaux documents Config pour composants inexistants ; - watcher filesystem générique ; - service distribué de configuration ; - secrets manager distant ; - chiffrement maison de `.env` ; - auth biométrique/keychain ; - application de contrôle globale KSP ; - système générique de plugins UI dynamiques chargés à runtime ; - éditeur de JSON Schema ; - viewer de logs complet dans l'UI ; - nouvelle crate partagée Tauri sans deuxième consumer concret. ## 18. Prévision souple des prereleases Chaque prerelease vise **environ 15–20 minutes de travail effectif**. Cette prévision est volontairement souple : une tranche peut être scindée si elle dépasse nettement ce budget, fusionnée avec la suivante si elle se révèle triviale, ou réordonnée si une dépendance technique est découverte. Le numéro exact de la dernière prerelease n'est donc pas contractuel. Découpage candidat : ```text pre.001 audit + brainstorming + plan détaillé pre.002 Config — inventaire public du registre - API read-only des descripteurs - ordre déterministe - tests unitaires/publics - README/USAGE/TODO Config si nécessaire pre.003 Config — réparation source candidate - API bornée par file_id - parse/schema/sémantique avant persistence - atomicité/no-write-on-error - tests + docs ciblés pre.004 squelette Rust Tauri - membre workspace - Cargo lib+bin/build.rs - main.rs/lib.rs/tauri.rs minimaux - builder Tauri configuré par étapes courtes/réassignées, sans chaîne monolithique - tauri.conf/capabilities/icône - frontendDist externe contractuel - réservation 1430/1431 et convention des couples de ports desk - layout frontend/ts/bindings + frontend/sass fixé sans dépendances npm prématurées - single-instance pre.005 squelette frontend/gabarit - package.json + Vite/TypeScript - npm utilisé pour la gestion des dépendances, cycle dev/build lancé par Tauri - build.outDir identique au frontendDist externe - port Vite 1430 strict + HMR 1431 - SCSS/Bootstrap/Font Awesome - SimpleBar + resize-observer-polyfill comme socle du gabarit - @fltsci/tauri-plugin-tracing avec plugin Rust - main/splash HTML+TS minimaux - build frontend de base pre.006 bootstrap backend + AppState - argv -> Config bootstrap/registry/management - initialisation Logging - fallback sûr si std.logging invalide - LoggingGuard durable - erreurs/DTO communs + premier get_app_snapshot TS-RS - inventaire/provenance de la police DOS_Amazigh du splash bot3 pre.007 frontend logging commun - frontend_log.ts repris/refondu depuis bot3 - emit_frontend_log centralisé dans tauri.rs - targets frontend whitelistés - émission via ksp-logging-lib - intégration console plugin compatible seulement pre.008 shell main + splash de référence - tw_splash + tw_main - lifecycle splash configurable - KSP_DESK_SPLASH_MINIMUM_MS / KSP_DESK_SPLASH_FADE_MS + .env.example - normalisation du CWD debug vers la racine workspace avant bootstrap Config - navigation monofenêtre + header `Config Desk — ` - helpers show/focus/destroy - instrumentation debug/trace des interactions, tabs et timings splash pre.009 Documents + diagnostics [réalisé] - inventaire générique par registre - catégories JSON/schema/sémantique/effective - source brut invalide - réparation via Config - DataTables 3 + Select 4 pour tri/filtre/pagination/sélection pre.010 Profils + provenance [réalisé] - default_profile - sélection explicite - global/profile/effective - provenance sûre pre.011 Environnement — rapports [réalisé] - desired/effective/source/shadow - sensibilité + safe values - table issue uniquement de Config - DataTables si tri/filtre/sélection/checkboxes sont requis à ce stade - refresh/reload du rapport pre.012 Environnement — management/test .env [réalisé] - create/update via set_dotenv_value - remove via remove_dotenv_value - confirmation destructive via modal Bootstrap, sans dialogue natif window.confirm - résultats source/effective/shadow/reload - démonstration process > .env - démonstration placeholder KSP_LOGS_DIRECTORY pre.013 Secrets privilégiés [réalisé] - DTO séparés - confirmation explicite - reveal transitoire - édition Secret sans préchargement réel - audits non-divulgation pre.014 Logging editor — lecture/DTO [réalisé] - document/profils/console/files/filters - targets/domains - mapping types Config -> DTO pre.015 Logging editor — mutations/persistence [réalisé] - create/clone/rename/delete profils - default_profile - mono-fichier/multi-fichiers - save_logging_document - Sauvegarder et appliquer = persistence + hot reload immédiat du profil default - Recharger le document = resynchronisation du brouillon uniquement - rollback source + ancien runtime conservé si l’application échoue pre.016 Logging runtime — compléments [réalisé] - fichiers applicatifs uniques par lancement avec timestamp de démarrage - sélection explicite du profil à appliquer indépendamment du default_profile - observabilité metadata/génération du runtime - consolidation des scénarios de rollback/runtime pre.017 panneau Test Logging [réalisé] - champ message - niveau trace/debug/info/warn/error/tous - select target KSP contrôlé - domain absent/connu/personnalisé - bouton Log -> commande Tauri - preuve routing avant/après hot reload - preuve bridge frontend pre.018 robustesse/extensibilité/tests desktop [en cours] - invalid source au démarrage - audits secrets/Config ownership/tracing - tests frontend/Tauri/build - ajout futur file_id/editor sans refonte shell pre.019 clôture - fmt/check/clippy - tests ciblés + cargo test --workspace - cargo tree pertinents - build frontend/Tauri - matrice fonctionnelle complète - README.md + USAGE.md finalisés - aucun PRESENTATION.md - TODO fermés/reportés - documentation/changelog/prompt suivant - préparation rel.001 ``` Ce découpage est une **prévision**, pas une obligation de produire exactement dix-neuf prereleases. Lorsqu'une tranche atteint son objectif en moins de temps, elle peut absorber le début logique de la suivante ; lorsqu'elle dépasse 20 minutes de façon significative, elle doit préférentiellement être scindée plutôt que compressée. Un défaut déjà livré est corrigé par un `fix` conformément au workflow KSP. ## 19. Dépendances et ordre d'introduction Aucune dépendance n'est ajoutée par `pre.001`. Ordre candidat : ### Rust desktop ```text tauri tauri-build tauri-plugin-tracing fs2 ts-rs ``` `serde` / `serde_json` existent déjà dans le workspace et seront réutilisés si nécessaires aux DTO. Les dépendances Rust desktop destinées à être réutilisables par les futures applications (`tauri`, `tauri-build`, `tauri-plugin-tracing`, `fs2`, `ts-rs`) seront versionnées au `Cargo.toml` racine sous `[workspace.dependencies]` puis consommées avec `.workspace = true` ; aucune version externe partagée ne sera dupliquée dans la crate applicative. `tokio` n'est pas automatiquement promu à `full`. Les features nécessaires au splash seront choisies au besoin réel. Aucun `rustls` direct n'est ajouté par symétrie avec bot3. ### Frontend `dependencies` : ```text @fltsci/tauri-plugin-tracing @fortawesome/fontawesome-free @tauri-apps/api bootstrap simplebar resize-observer-polyfill ``` `devDependencies` : ```text @tauri-apps/cli @types/bootstrap @types/node sass-embedded typescript vite ``` DataTables est ajouté à la première tranche qui introduit un tableau nécessitant tri/filtrage/sélection/checkboxes, avec le couple bot3 `datatables.net-bs5` + `datatables.net-select-bs5` comme référence à réauditer avant ajout. Il n'est pas ajouté au squelette vide uniquement par symétrie. `@types/node` est requis par la configuration Vite TypeScript actuelle. Les autres paquets `@types/*` sont ajoutés uniquement lorsqu'une dépendance réellement utilisée en a besoin. ECharts, `@andypf/json-viewer` et les autres packages métier/démo bot3 restent exclus tant qu'une tranche n'en démontre pas l'usage immédiat. La politique KSP sans lockfile versionné reste inchangée. ## 20. Critères de validation de la release `0.1.4` peut être considérée fonctionnellement complète seulement si tous les critères suivants sont vrais : ### Architecture - la crate est directement sous `crates/` ; - lib+bin séparés, `main.rs` mince, `lib.rs` déclaratif ; - `run` configure le `tauri::Builder` par étapes courtes/réassignées ou helpers ciblés, sans longue chaîne monolithique ; - toutes les commandes Tauri sont dans `tauri.rs` ; - services/modules métier hors wrappers ; - aucune lecture/écriture directe des fichiers Config/`.env` ; - aucune lecture `std::env::var*` pour KSP/KSPB hors Config ; - aucun `tauri-plugin-log` ; - aucun subscriber tracing parallèle ; - plugin tracing intégré sans `with_default_subscriber()` ; - package frontend compagnon `@fltsci/tauri-plugin-tracing` intégré avec le gabarit ; - bridge `frontend_log.ts` KSP présent, targets frontend contrôlés, aucune seconde pile `log` ; - Logging runtime possédé par `ksp-logging-lib`. ### Documents/profils - documents enregistrés listés depuis Config ; - source invalide inspectable et réparable sans filesystem direct ; - erreurs JSON/schema/sémantiques/effective distinguées ; - `default_profile` et profils inspectables ; - source/global/profile/effective montrés lorsque pertinent. ### Environnement / `.env` / secrets - panneau `.env` fonctionnel, pas seulement un affichage de diagnostics ; - rapports desired/effective/source/shadow issus de Config ; - création et modification `.env` via `set_dotenv_value()` ; - suppression `.env` via `remove_dotenv_value()` ; - résultat de mutation `source_changed` / `effective_changed` / `shadowed` / `reload_required` rendu observable ; - rapport rechargé depuis Config après mutation ; - priorité process > `.env` démontrée avec un cas de shadowing ; - impossibilité de modifier le process parent expliquée ; - résolution `${KSP_LOGS_DIRECTORY:-logs}` redémontrée après une mutation `.env` non shadowée, sans résolution frontend ; - safe values par défaut ; - reveal séparé et explicite ; - une valeur Secret existante n'est pas préchargée automatiquement dans l'éditeur ; - aucune valeur Secret réelle dans logs/diagnostics/snapshot/state persistant. ### Logging - plusieurs profils créables/modifiables ; - profil mono-fichier démontré ; - profil multi-fichiers + console démontré ; - sauvegarde fonctionnelle ; - profil sélectionnable/appliquable ; - hot reload observable sans redémarrage ; - panneau de test `message + niveau + target + domain + Log` fonctionnel ; - mode multi-niveaux permettant de tester les seuils ; - bridge frontend réellement observable dans le runtime KSP ; - échec reload laisse ancien runtime actif et le panneau de test le démontre. ### Extensibilité - shell Documents non codé uniquement autour de Logging ; - registre Config reste source de vérité des `file_id` ; - Logging est un éditeur spécialisé branché sur un shell générique ; - ajout futur d'un `file_id` ne demande pas de réécrire bootstrap/diagnostics/persistence. ## 21. Documentation finale attendue À la clôture : ```text crates/ksp-app-config-desk/README.md crates/ksp-app-config-desk/USAGE.md ``` `README.md` décrit le rôle, l'architecture, les dépendances et les frontières de sécurité. `USAGE.md` décrit : - lancement/arguments bootstrap ; - splash ; - fenêtre principale ; - panneau Documents ; - panneau Profils ; - panneau Environnement / `.env` ; - création/modification/suppression `.env`, reload et shadowing ; - reveal secrets ; - panneau Logging ; - sauvegarde/application ; - test Logging interactif/hot reload ; - bridge frontend Logging ; - diagnostics usuels. Il n'y aura pas de `PRESENTATION.md` dans `0.1.4` tant qu'aucune vue de présentation n'existe. ## 22. Questions ouvertes volontairement reportées à leur tranche Aucune question n'empêche d'ouvrir le développement après validation du présent plan. Les choix suivants seront figés au moment où l'implémentation fournit les contraintes réelles : 1. nom public exact des deux petites extensions Config (`descriptors`/inventaire et sauvegarde de source candidate) ; 2. nom exact et nombre minimal de variables splash Config/.env ; 3. features Cargo minimales de Tauri/Tokio nécessaires au shell/splash ; 4. détails du fallback Logging minimal utilisé uniquement lorsque la Config Logging ne peut pas être résolue au démarrage ; 5. implémentation exacte du retour Rust -> console WebKit : `attachConsole()` est retenu comme capacité candidate, mais seulement après intégration d'une `tauri_plugin_tracing::WebviewLayer` dans le subscriber possédé par `ksp-logging-lib`; `interceptConsole()`/`takeoverConsole()` ne doivent pas doubler le bridge JS -> Rust KSP ni réintroduire des targets non conformes. Ces points doivent être résolus par code/tests dans les prereleases prévues, pas par contournement applicatif.