# Utilisation de ksp-config-lib ## 1. Bootstrap et moteur documentaire Config doit interpréter ses propres arguments de bootstrap avant toute lecture de document : ```rust let args: std::vec::Vec = std::env::args_os().collect(); let bootstrap = match ksp_config_lib::ConfigBootstrapOptions::from_args(args.as_slice()) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let registry = match ksp_config_lib::ConfigFileRegistry::from_args(args.as_slice()) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let engine = ksp_config_lib::ConfigDocumentEngine::new(bootstrap, registry); ``` Les arguments compris par Config sont : ```text --cfgpath=/path/to/config --schemapath=/path/to/schemas --filemap=cfg.std.logging=my-logging.json ``` `cfgpath` et `schemapath` ne sont jamais lus depuis JSON, `.env` ou une variable KSP : cette règle évite un bootstrap récursif. ## 2. Charger et valider un document connu Les consumers utilisent un `file_id` logique : ```rust let file_id = match ksp_config_lib::ConfigFileId::new(ksp_config_lib::FILE_ID_STD_LOGGING) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let document = engine.load_validated_document(&file_id); ``` Le moteur résout le path physique via le registre, charge le schema associé, valide le schema lui-même, valide l'instance puis applique les invariants sémantiques KSP. ## 3. Environnement effectif `ConfigEnvironment::load()` capture les variables process KSP/KSPB et lit `./.env` : ```rust let environment = match ksp_config_lib::ConfigEnvironment::load() { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; ``` La priorité est : ```text process environment > .env > fallback > missing ``` Une chaîne vide explicitement présente est une valeur définie ; elle ne provoque pas l'utilisation du fallback. Exemples de placeholders : ```text ${KSP_LOGS_DIRECTORY} ${KSP_LOGS_DIRECTORY:-logs} ``` Pour conserver la sensibilité et la provenance, préférer les variantes détaillées : ```rust let resolved = environment.resolve_text_detailed("${KSP_SECRET_EXAMPLE}"); ``` `ResolvedConfigText` / `ResolvedConfigJson` séparent valeur réelle et valeur sûre. Une représentation `Debug` ne doit pas révéler le réel d'un secret. ## 4. Construire Logging depuis Config Le chemin normal consiste à charger le profil Logging, résoudre l'environnement puis construire directement le contrat Logging public : ```rust let resolved = match engine.load_resolved_logging_config(std::option::Option::None, &environment) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let settings = resolved.into_settings(); let initialized = ksp_logging_lib::initialize(&settings); let mut logging_guard = match initialized { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; ``` L'application/service possède `logging_guard`. Config ne conserve pas de singleton Logging. Un `logs_directory` relatif est ancré sur le current working directory du processus. Un path absolu est conservé. Une valeur explicite invalide produit une erreur effective : elle ne retombe pas silencieusement sur le fallback du placeholder. Les `files[].path` restent relatifs sous le root Logging, y compris après interpolation. ## 5. Profils et composites Pour un document standard profilé : ```rust let profile = engine.load_resolved_profile(&file_id, std::option::Option::None); ``` `None` utilise le `default_profile`; `Some("profile_id")` impose un profil explicite. Un composite référence les documents par `file_id`, jamais par filename. `load_resolved_composite(...)` conserve chaque `ResolvedConfigProfile` composant et sa provenance plutôt que d'aplatir plusieurs domaines dans une map ambiguë. ## 6. Management de `std.logging.json` Une application de management construit la façade à partir d'un moteur : ```rust let management = ksp_config_lib::ConfigManagement::new(engine); let document = match management.load_logging_document() { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; ``` Le type `LoggingConfigDocument` et ses sous-structures exposent des setters/mutators typés. Après modification, la sauvegarde : ```rust let saved = management.save_logging_document(&document); ``` valide le candidat complet avant toute substitution du fichier. Un candidat invalide ne remplace pas la source existante. `read_source(file_id)` reste disponible pour une UI de réparation : il peut lire le texte brut d'un document enregistré même lorsque son JSON ou son schema est invalide. Il n'ouvre pas un path arbitraire. ## 7. Management de `.env` Les rapports ordinaires sont sûrs : ```rust let report = management.environment_report(); ``` Ils distinguent notamment valeur souhaitée `.env`, valeur effective, source et shadowing process sans exposer un secret réel. L'accès au réel est volontairement explicite : ```rust let effective = management.reveal_effective_environment_value("KSP_SECRET_EXAMPLE"); let persisted = management.reveal_dotenv_value("KSP_SECRET_EXAMPLE"); ``` Une application doit contrôler l'autorisation de l'utilisateur avant ces appels et ne jamais journaliser les valeurs retournées. Les mutations persistantes utilisent : ```rust let changed = management.set_dotenv_value("KSP_LOGS_DIRECTORY", "logs"); let removed = management.remove_dotenv_value("KSP_LOGS_DIRECTORY"); ``` Elles n'altèrent jamais l'environnement hérité du processus. Une valeur process peut donc masquer une modification `.env`; `ConfigEnvironmentChangeReport` distingue `source_changed`, `effective_changed`, `shadowed_by_process_environment` et `reload_required`. Sur Unix, un nouveau `.env` est créé avec des permissions privées `0600`; les permissions existantes sont préservées lors des remplacements atomiques. ## 8. `.env.example` `/.env.example` est l'inventaire versionné. `/.env` reste local et ignoré. Toute nouvelle variable runtime concrète `KSP_*` / `KSPB_*` introduite dans le code ou les documents Config doit être ajoutée à `.env.example` avec un commentaire expliquant son usage. Les audits `ksp-config-lib/tests/ownership.rs` font échouer `cargo test` lorsqu'une clé concrète est oubliée. ## 9. Frontière Tauri Une application Tauri doit appeler les APIs ci-dessus via ses commandes/DTO applicatifs. Elle ne lit ni JSON ni `.env` directement et ne résout jamais elle-même les placeholders. Les valeurs `Secret` ne doivent pas être incluses par défaut dans les DTO publics. Une action UI explicitement autorisée peut appeler une méthode `reveal_*` et transporter le résultat par un DTO spécifique, sans log ni diagnostic contenant la valeur réelle.