# Architecture de fondation Knowledge ## Décision structurante Knowledge est un **workspace modulaire multi-app**. Il possède trois applications Actix Web déployables séparément pour PGR, HOWTOs et snippets, et des bibliothèques communes pour les responsabilités réellement partagées. Cette décision ne crée pas une architecture de microservices distribués : les trois launchers restent des couches de composition minces, peuvent utiliser le même PostgreSQL et partagent les mêmes contrats de domaine, Git, stockage et synchronisation lorsque leur ownership est commun. Le principe directeur reste : > Git est le backend du contenu ; une forge est une capacité optionnelle. ## Workspace Rust matérialisé La stable `0.0.1` a matérialisé les premières frontières et le runtime Web : ```text knowledge-domain-lib famille/source de contenu knowledge-git-api GitRepository provider-neutral knowledge-sync-api RepositoryEventSource et signal de réconciliation knowledge-web-lib composition Actix/Maud et assets Vite knowledge-pgr-server launcher PGR knowledge-howtos-server launcher HOWTOs knowledge-snippets-server launcher snippets ``` `0.0.2` ajoute deux owners réels sans changer la topologie multi-app : ```text knowledge-git-lib backend Git générique : mirror/refresh/resolve/snapshot knowledge-app-lib cas d'usage partagé de synchronisation Changed/Unchanged ``` Les deux crates `-api` sont justifiées par des implémentations réellement remplaçables ou multiples. Elles restent sans runtime, sans logging propre et sans dépendance à Actix, Gitea ou PostgreSQL. `0.0.4-alpha.2` matérialise `knowledge-store-postgres-lib` comme owner concret du pool, des migrations et de l'état PostgreSQL partagé. La crate masque `tokio-postgres`, Deadpool et Refinery derrière sa façade publique et aucun `knowledge-store-api` symétrique n'est introduit sans besoin de substitution démontré. Les tests unitaires Rust sont désormais placés hors de `src/` sous `unit_tests/`, conformément à la convention locale Knowledge sélectionnée sur l'option permise par PGR. Le workspace est une application déployable à train de release unique. Knowledge choisit néanmoins de conserver `Cargo.lock` comme état généré local et ignoré par Git ; les manifests Cargo portent le contrat versionné des dépendances. Les artefacts Cargo sont dirigés hors du dépôt vers `../builds/sasedev-knowledge/target/`. ## Vue de responsabilités ```text pgr.sasedev.com howtos.sasedev.com snippets.sasedev.com | | | knowledge-pgr-server knowledge-howtos-server knowledge-snippets-server \________________________|________________________/ | v application use cases | +----------------------+-----------------------+ | | | v v v content/domain contracts GitRepository RepositoryEventSource | | | | v v | Git local/remotes explicit/poll/hook/webhook | +---------------------> GitForge (optionnel) | Gitea/autre forge | +---------------------> PostgreSQL partagé | état/index/relations/jobs | +---------------------> projections/cache locales lecture/recherche/rendu ``` La dépendance pointe vers les contrats métier. Les détails Actix, processus Git, API Gitea ou SQL ne remontent pas dans le domaine. `GitRepository` ne porte dans la stable `0.0.1` que les opérations génériques alors nécessaires : rafraîchir la vue locale d'une source et résoudre une référence opaque vers une révision Git autoritaire. `0.0.2` n'étend ce contrat que lorsqu'un besoin de snapshot réellement implémenté le démontre. Le contrat ne suppose ni API de forge, ni type de remote particulier, ni format SHA figé. `RepositoryEventSource` ne produit qu'un `RepositorySyncSignal` associé à un `source_id`. La cause reste volontairement grossière (`Explicit`, `Periodic`, `ExternalSignal`) afin que hook Git, webhook de forge ou watcher ne deviennent pas des concepts autoritaires du domaine. ## 1. Applications publiques Les trois façades publiques sont des unités de déploiement distinctes : ```text knowledge-pgr-server -> famille PGR knowledge-howtos-server -> famille HOWTO knowledge-snippets-server -> famille snippet ``` Chaque serveur : - compose les mêmes bibliothèques communes lorsque la responsabilité est réellement partagée ; - possède sa configuration de source(s) Git et de publication ; - peut être déployé et dimensionné indépendamment ; - ne porte pas de logique métier dupliquée dans `main.rs` ; - peut utiliser le même PostgreSQL logique que les deux autres applications. La topologie d'administration reste `DEFER`. Une future application d'administration séparée n'est créée que si son boundary de déploiement devient réellement utile. ## 2. Application et domaine Le domaine porte les concepts durables : famille de contenu, source de contenu, révision, proposition, validation, publication, type documentaire et références entre contenus. La couche application orchestre les cas d'usage tels que synchroniser une source, indexer une révision, ouvrir/revoir une proposition et publier une révision autorisée. Les modèles HTTP, SQL et payloads Gitea ne sont pas des modèles domaine par défaut. Le domaine ne suppose pas qu'une famille possède exactement un repository. Il manipule des identités de source configurables afin de permettre plusieurs repositories PGR/HOWTO/snippet à l'avenir sans refonte du modèle. ## 3. Git générique Le contrat `GitRepository` reste provider-neutral. `0.0.2-alpha.1` sélectionne comme première implémentation un **processus `git` contrôlé** et `0.0.2-alpha.2` matérialise son premier owner runtime : ```text knowledge-git-lib ``` Cette sélection est une décision locale Knowledge, pas un couplage du contrat au CLI Git. Une autre implémentation pourra remplacer le backend ultérieurement si des preuves de maintenance, performance ou portabilité le justifient. ### Configuration physique `knowledge-domain-lib` continue de posséder `SourceId` et `ContentSource`. Les URLs, chemins locaux, exécutable Git et répertoires de travail ne remontent pas dans le domaine. `knowledge-git-lib` possède la configuration physique : ```text source_id -> local path ou remote Git générique source_id -> référence cible configurée backend -> racine d'état Git contrôlée ``` La composition runtime pourra charger ces valeurs depuis la configuration de déploiement. La persistance logique future dans PostgreSQL reste différée. ### Matérialisation locale Les données générées résident hors du dépôt applicatif et hors des dépôts éditoriaux : ```text / empty-global.gitconfig hooks-disabled/ repositories/ .git/ snapshots/ / / write-worktrees/ / candidate/ ``` Le backend reçoit explicitement `` ; il n'utilise aucun défaut implicite sous le workspace. Une variable de déploiement telle que `KNOWLEDGE_GIT_STATE_ROOT` pourra alimenter la composition, mais la librairie reçoit un chemin et ne lit pas elle-même l'environnement. `source-key` est une clé sûre dérivée par l'implémentation Git. Depuis `0.0.2-alpha.2`, elle encode de manière déterministe les octets UTF-8 du `SourceId` sous une forme hexadécimale préfixée ; un `SourceId` ou une URL remote ne sont jamais interpolés directement comme chemin de filesystem. Pendant `0.0.2`, une racine d'état appartient exclusivement à une instance backend/processus. Le partage simultané d'une même racine entre plusieurs processus reste `DEFER` jusqu'à matérialisation d'un verrouillage inter-processus. ### Mirror et refresh Une source locale ou remote converge vers un mirror Git contrôlé. `alpha.2` implémente l'initialisation et l'inspection bare minimale ; `alpha.3` ajoute l'enregistrement explicite des sources physiques, le refresh réel, la résolution et le snapshot derrière `GitRepository`. L'initialisation utilise conceptuellement : ```text git clone --mirror [--no-local pour une source locale] -- ``` Pour une source locale, `--no-local` évite de créer une dépendance par hardlinks/optimisation locale sur le repository éditorial. Le refresh réutilise la configuration du remote du mirror et exécute `remote update --prune`. L'opération est idempotente, initialise le mirror s'il n'existe pas encore et ne dépend d'aucune API de forge. ### Résolution et snapshot Une référence cible n'est jamais considérée comme identité autoritaire avant résolution. Le backend exige qu'elle se résolve vers un commit réel, selon la sémantique : ```text git --git-dir= rev-parse --verify --end-of-options ^{commit} ``` La valeur obtenue devient `GitRevision`. Le backend valide que l'identité produite est une représentation hexadécimale non vide avant de l'utiliser comme composant de chemin, sans figer une longueur SHA particulière. Le snapshot de lecture est ensuite créé comme worktree détaché adressé par cette révision. `GitSnapshot` expose uniquement la révision autoritaire et le chemin local de lecture. Un snapshot déjà présent n'est réutilisé qu'après vérification de son `HEAD` et d'un état propre ; une divergence produit une erreur récupérable plutôt qu'un nettoyage destructif silencieux. Les hooks Git sont désactivés pour les opérations de checkout/worktree appartenant au backend. Les commandes sont exécutées directement sans shell, avec prompts interactifs désactivés et sans journaliser de credential. ### Écriture Git engagée en `0.0.3` `0.0.3` ajoute une frontière d'écriture distincte du `GitRepository` de lecture. Le backend conserve le processus `git` contrôlé et matérialise un worktree d'écriture isolé sous la racine d'état, sans modifier les snapshots de lecture. Le chemin cible est : ```text base GitRevision explicite -> worktree d'écriture contrôlé -> mutations de fichiers confinées -> commit avec identité explicite -> révision candidate -> push vers refs/heads/... gardé par l'état distant attendu -> succès ou conflit explicite ``` Une divergence ne déclenche ni rebase, ni merge, ni force-push non gardé. Ces décisions appartiennent à un futur workflow de proposition/publication. Les capacités forge-specific restent séparées. La baseline conserve au moins trois sources indépendantes (`pgr`, `howtos`, `snippets`) mais le mapping reste configurable et extensible ; aucun `match` codé en dur n'impose exactement trois repositories. ## 4. Forge optionnelle Le contrat conceptuel `GitForge` porte uniquement les capacités qui ne sont pas des opérations Git fondamentales : ```text pull/merge requests issues permissions forge releases forge webhooks et métadonnées spécifiques ``` L'absence d'un adapter forge ne doit pas empêcher la synchronisation d'un dépôt local/générique, la lecture publique ou le workflow interne de proposition. Gitea est le premier candidat d'intégration mais n'est pas figé comme dépendance du domaine. ## 5. Événements et synchronisation Le contrat `RepositoryEventSource` produit un **signal de synchronisation**, pas une vérité de contenu. Sources conceptuelles : ```text sync explicite polling hook Git local/serveur webhook de forge watcher filesystem éventuel ``` Toutes les sources doivent converger vers le même cas d'usage : ```text signal(source_id) -> refresh du mirror si nécessaire -> résolution de la révision cible Git -> comparaison avec previous_revision -> snapshot/worktree de cette révision si changement -> futurs parsing + validation + projection ``` Un webhook peut être perdu ou dupliqué. Le commit Git résolu reste l'identité autoritaire. ### Ownership de `0.0.2` La synchronisation partagée est une responsabilité de couche application, distincte du backend Git et des producteurs de signaux. `0.0.2-alpha.5` confirme cette responsabilité et matérialise `knowledge-app-lib` comme owner du cas d'usage provider-neutral ; les launchers n'ont pas à dupliquer cette orchestration. Le cas d'usage de synchronisation existant continue de recevoir `previous_revision` de l'appelant et retourne explicitement la révision observée ainsi qu'un résultat `Changed` ou `Unchanged`. `0.0.4-alpha.2` matérialise seulement le store et le schéma ; le raccord de cette persistance au cas d'usage reste réservé à `alpha.4`, sans modifier la frontière Git. La cause `Periodic` reste supportée par `knowledge-sync-api`, mais `0.0.2-alpha.1` ne désigne pas encore de scheduler concret. Un scheduler n'est matérialisé que si son lifecycle/runtime est démontré ; lorsqu'il existe, il appelle exactement le même cas d'usage que la voie explicite. La synchronisation peut rester composée par chacun des trois serveurs au début. Un worker réseau séparé n'est créé que si un owner/lifecycle distinct devient nécessaire. ## 6. Propositions et revues Le workflow exact reste à formaliser avant implémentation, mais le contrat minimal conserve : ```text auteur famille et source cible révision Git de base patch ou contenu proposé statut historique de revue résultat de validation révision/branche résultante si acceptée ``` Une proposition ne modifie jamais directement la révision publiée. Si la base n'est plus courante, le workflow doit pouvoir signaler un conflit/rebase plutôt que forcer un écrasement. Une pull request de forge MAY refléter ou accélérer ce workflow ; elle n'en est pas le modèle autoritaire obligatoire. ## 7. Parsing et validation des contenus Le contrat conceptuel `ContentRepository` expose du contenu normalisé au métier sans révéler le provider Git ou forge. Le format final des HOWTOs/snippets reste `DEFER`. Le parseur devra néanmoins pouvoir produire au minimum : ```text identité logique famille de contenu source Git révision source métadonnées normalisées corps rendu/parsé références sortantes résultat de validation ``` Les validations normatives PGR restent propres au corpus PGR. Knowledge ne doit pas inventer une règle PGR pour simplifier son parseur. ## 8. PostgreSQL partagé, index, recherche et cache La baseline retient **une base PostgreSQL logique partagée** par les trois applications. Ce choix est justifié par l'état transversal : identités, sessions, propositions, synchronisation, relations entre familles, index et recherche. Il évite trois bases divergentes pour des concepts qui appartiennent à la même plateforme. ### Fondation matérialisée pour `0.0.4` `0.0.4-alpha.1` sélectionne le toolkit ; `0.0.4-alpha.2` matérialise `knowledge-store-postgres-lib` avec `tokio-postgres 0.7.18`, `deadpool-postgres 0.14.2` et Refinery `0.9.2`. La façade publique reste limitée à `PostgresStoreConfig`, `PostgresStore` et `PostgresStoreError`. Les types du driver, du pool et du migrator ne remontent ni dans le domaine ni dans les contrats applicatifs, et aucun `knowledge-store-api` symétrique n'est introduit sans seconde implémentation démontrée. La configuration est injectée par la composition : la crate reçoit une URL PostgreSQL et une taille maximale de pool. Elle ne lit pas directement les variables d'environnement du processus, n'expose pas l'URL par son API publique et ne journalise jamais l'URL ou les credentials. Une configuration invalide, une acquisition de pool ou une migration impossible produit une erreur récupérable ; aucun fallback fichier/mémoire ne masque l'indisponibilité PostgreSQL. La première implémentation utilise `tokio_postgres::NoTls`; un backend TLS ne sera ajouté que lorsqu'une cible de déploiement le justifiera. Le premier schéma utile est volontairement borné : ```text knowledge_sources source_id TEXT PRIMARY KEY family TEXT NOT NULL CHECK (pgr/howto/snippet/project_local) git_reference TEXT NOT NULL knowledge_source_sync_state source_id TEXT PRIMARY KEY REFERENCES knowledge_sources(source_id) ON DELETE CASCADE last_synchronized_revision TEXT NOT NULL ``` `git_reference` est la référence Git logique à suivre ; la localisation physique locale/remote et les credentials restent hors de cette table et sous les frontières de configuration appropriées. La dernière révision synchronisée est un état applicatif, pas une nouvelle autorité de contenu : elle peut être reconstruite/réconciliée à partir de Git et une valeur obsolète provoque au pire une resynchronisation. La migration `V1__initial_sources.sql` est embarquée au build et appliquée uniquement via `PostgresStore::apply_migrations`; Refinery conserve son historique dans PostgreSQL. Le test d'intégration réel reste `#[ignore]` pour ne pas transformer tout `cargo test` en dépendance externe implicite. La gate PostgreSQL vérifie explicitement `KNOWLEDGE_POSTGRES_TEST_URL`, crée un schéma unique, borne le `search_path` de la connexion du store, exécute la migration, vérifie `knowledge_sources`, `knowledge_source_sync_state` et `refinery_schema_history`, puis supprime le schéma. L'absence du service requis rend la gate `BLOCKED`. PostgreSQL MAY contenir ultérieurement des documents/index/métadonnées dérivés et assurer une première capacité de recherche. Le corps publié et ses métadonnées éditoriales autoritaires restent dans Git. `0.0.4` ne matérialise pas encore le parsing/projection final prévu par l'horizon `0.0.5`. Les enregistrements dérivés doivent porter au minimum l'identité de famille/source et la révision Git afin de savoir exactement quel contenu ils représentent. Une séparation physique de bases ou de schémas par application reste possible ultérieurement si une contrainte de sécurité, disponibilité, charge ou ownership la justifie. Elle n'est pas la baseline de fondation. ## 9. Rendu et publication Chaque application publique sélectionne et publie uniquement les familles/sources qui lui sont autorisées. Pour PGR : - le canal stable provient d'un tag stable vérifié par le workflow PGR ; - un canal `dev` MAY exister mais doit être visuellement et sémantiquement distinct. Pour HOWTOs/snippets : - la cadence MAY être continue et plus légère ; - le workflow SemVer/delta/history PGR n'est pas imposé artificiellement. Actix Web et Maud sont des choix de composition/rendu locaux. Vite gère les assets/interactions frontend lorsqu'il est matérialisé. La baseline `alpha.4` retient un package de laboratoire partagé `Web/knowledge-template-lab/` pour les assets et templates statiques de référence communs. Cette décision évite trois toolchains identiques ; une divergence réelle pourra introduire ultérieurement des entrées ou packages supplémentaires. ### Pipeline Web de référence et rendu runtime Le frontend Web n’est pas une SPA concurrente du SSR Maud. Il possède deux responsabilités distinctes : ```text Vite + TypeScript + Sass + Bootstrap -> assets construits et templates statiques de référence -> typecheck/build/preview/smoke indépendants du backend Actix Web + Maud -> markup runtime des trois applications -> consommation des mêmes contrats d’assets ``` Les templates statiques de référence permettent de travailler rapidement sur le HTML, le responsive, les classes Bootstrap, les comportements TypeScript et les styles Sass sans démarrer les serveurs Rust. Ils sont ensuite adaptés en composants/templates Maud pour le rendu runtime. Cette adaptation ne doit pas créer deux produits UI indépendants : la tranche Web devra définir les invariants vérifiables qui empêchent la dérive entre référence statique et rendu Maud. Le build production Vite doit exposer un manifest permettant au backend de convertir une clé d’entrée stable en URL d’asset hashé. Le corpus `actix-auth-app` montre un pattern utile : manifest Vite activé, entrées TypeScript/Sass explicites, loader Rust et sélection dev-server versus manifest en fonction du mode. Knowledge retient le **contrat d’intégration**, pas l’implémentation historique telle quelle. En particulier, Knowledge ne doit pas hériter mécaniquement : - d’un origin Vite `localhost:5173` codé en dur ; - d’un préfixe `/res` universel ; - d’un `panic!` lorsque le manifest est absent ou invalide ; - d’une arborescence d’assets spécifique au corpus ; - de dépendances TypeScript `@types/*` non justifiées par les packages réellement consommés. `0.0.1-alpha.4` possède le frontend indépendant et la production du manifest. La clé stable `src/main.ts` constitue l'entrée d'asset commune de départ ; son entrée de manifest doit référencer les sorties JavaScript et CSS générées. `0.0.1-alpha.5` matérialise `knowledge-web-lib` comme owner partagé de l'intégration Actix/Maud. La crate choisit entre un dev server configuré par `KNOWLEDGE_VITE_DEV_ORIGIN` et un manifest configuré par `KNOWLEDGE_VITE_MANIFEST_PATH`. En production elle dérive le répertoire `assets/` depuis le manifest et le sert sous le préfixe `/assets`, tandis que `KNOWLEDGE_ASSET_BASE_PATH` garde le préfixe d'URL configurable. Les erreurs de configuration/manifest restent récupérables et remontent avant le démarrage du listener. Les trois packages `knowledge-pgr-server`, `knowledge-howtos-server` et `knowledge-snippets-server` sont des launchers minces : chacun sélectionne `ServerSite` et le nom de sa variable de bind, puis délègue au runtime commun. Ils ne possèdent aucune logique de rendu ou de manifest dupliquée. ## Réconciliation `0.0.1-beta.1` La fondation matérialisée est cohérente avec les objectifs `0.0.1` : - trois launchers séparés, sans duplication de runtime ; - Git encore contractuel et provider-neutral, sans adapter de forge ; - synchronisation encore contractuelle, sans worker artificiel ; - frontend de référence indépendant et rendu runtime Maud effectivement relié au manifest Vite ; - aucune persistance PostgreSQL, auth complète, UI admin complète, forge spécifique ou format final HOWTO/snippet introduit par anticipation. `0.0.2-alpha.1` a conservé cette réconciliation comme baseline et la stable `0.0.2` a fermé le chemin Git générique de lecture et la synchronisation réelle. ## Réconciliation `0.0.2-beta.1` La mission Git/synchronisation est réconciliée avec l'implémentation réellement obtenue : - neuf packages Cargo, sans crate placeholder ; - `knowledge-git-api` provider-neutral et `knowledge-git-lib` comme implémentation process Git contrôlée ; - sources locales/remotes convergeant vers un mirror contrôlé puis vers une révision commit et un snapshot validé ; - `knowledge-app-lib` comme unique owner du cas d'usage refresh / resolve / compare / snapshot ; - dernière révision fournie par l'appelant, sans stockage caché ; - causes de synchronisation non autoritaires, `Periodic` sans scheduler imposé ; - règles Knowledge autonomes après l'adoption ponctuelle PGR `v0.1.3` ; - aucun adapter forge, PostgreSQL, auth/admin complète, écriture Git ou format final HOWTO/snippet introduit par anticipation. Les besoins de rétention de snapshots, submodules/LFS, partage multi-processus de la racine Git et scheduler concret restent différés jusqu'à preuve d'un besoin réel. Aucune prochaine release n'est numérotée par cette réconciliation. ## Ouverture `0.0.3` — écriture Git contrôlée Après publication vérifiée de `v0.0.2`, la prochaine mission explicitement engagée est l'écriture Git générique contrôlée. Elle réutilise le backend process existant, introduit un contrat d'écriture distinct de la lecture et garde la forge optionnelle. `0.0.3` borne la mise à jour distante à des branches `refs/heads/...` et exige un état distant attendu. Un push n'est accepté que lorsque cette attente reste vraie ; sinon le résultat est un conflit récupérable. Le backend ne résout pas ce conflit par rebase/merge automatique. `alpha.2` matérialise cette frontière dans `knowledge-git-api` sans implémentation de backend : `GitMutationPath` confine lexicalement les mutations à des chemins relatifs normalisés hors `.git`, `GitFileMutation` représente écriture ou suppression, `GitCommitIdentity` impose une identité explicite, `GitBranch` borne la cible à une référence de branche complète valide, et `GitRemoteState` représente soit l'absence attendue soit une révision distante attendue. `GitWriteRequest`, `GitPushRequest` et `GitPushOutcome` portent respectivement la création de candidate, la comparaison-et-échange distante et son résultat. Le trait `GitRepositoryWriter` reste séparé de `GitRepository` afin qu'un consommateur ou fake lecture seule n'acquière aucune obligation d'écriture. `alpha.3` implémente la moitié locale de ce contrat dans `knowledge-git-lib`. Le backend crée un worktree détaché temporaire sous `write-worktrees//candidate`, applique uniquement les chemins demandés et refuse tout composant filesystem qui est un symlink. Le staging est contrôlé contre l'ensemble exact des mutations avant commit. L'identité auteur/committer est injectée explicitement ; la configuration Git système et globale est neutralisée, les hooks sont redirigés vers `hooks-disabled`, et le commit désactive également hook/signature à l'appel. Après commit, le backend vérifie `HEAD` et `HEAD^1`, exige que le parent soit exactement la `GitRevision` de base puis conserve l'objet candidat sous `refs/knowledge/candidates/`. Le worktree possédé est retiré après succès ; après une erreur survenue dans un worktree créé par l'opération, le backend tente une suppression forcée de cet état temporaire. Un worktree préexistant n'est jamais supprimé silencieusement et produit une erreur récupérable. Le push distant gardé reste réservé à `alpha.4`. `alpha.3` ne met à jour aucune branche remote et n'implémente ni rebase ni merge. PostgreSQL, workflow complet de proposition, auth/admin, parsing final et adapter Gitea restent des missions distinctes. ## Ouverture `0.0.4` — persistance partagée La stable `v0.0.3` ayant fermé le chemin Git générique, `0.0.4` matérialise la première persistance partagée nécessaire aux prochains cas d'usage sans déplacer l'autorité éditoriale. La trajectoire retenue est : ```text alpha.1 étude, ownership, schéma, migrations et tests alpha.2 crate PostgreSQL + pool + première migration alpha.3 persistance source logique + état de synchronisation alpha.4 raccord applicatif de la révision précédente persistée beta réconciliation + horizon rc/rel stabilisation et publication ``` Le raccord applicatif futur doit conserver la primitive `synchronize_repository` provider-neutral : la persistance fournit la révision précédente et reçoit la révision observée, mais ne devient ni un backend Git ni une condition pour interpréter l'identité du commit. ## 10. Administration L'administration Web est une interface vers les mêmes cas d'usage que l'édition locale Git, pas une deuxième source de vérité. Chaque application doit pouvoir protéger sa propre surface d'administration métier : ```text knowledge-pgr-server -> administration PGR knowledge-howtos-server -> administration HOWTOs knowledge-snippets-server -> administration snippets ``` Les chemins HTTP exacts restent `DEFER`. Les exemples `/admin`, `/adminapi`, `/login` ou autres observés dans les corpus historiques ne sont pas adoptés comme convention Knowledge. Une quatrième application d'administration MAY être créée ultérieurement si une vraie responsabilité transversale apparaît. Elle pourra agréger comptes, sources, jobs, propositions ou autres vues communes, mais MUST NOT remplacer les contrôles d'autorisation propres aux trois applications. Une UI complète reste hors scope `0.0.1`. ## 11. Authentification et autorisation Le domaine doit distinguer identité, authentification, rôle/capacité et action autorisée. L'identité et les sessions peuvent être transversales via PostgreSQL partagé ; l'autorisation métier reste vérifiée côté serveur dans chaque application. Le fournisseur d'identité, les URLs de login, le modèle détaillé de rôles/capabilities, OAuth2/OIDC et MFA restent différés. Les permissions forge ne sont pas supposées équivalentes aux permissions applicatives. Le partage d'une base PostgreSQL facilite une identité et des autorisations transversales aux trois façades sans imposer trois silos de comptes. ## 12. Frontières PGR / HOWTO / snippet / project-local Les quatre familles gardent une sémantique propre : | Famille | Rôle | Force | |---------------|--------------------------------------------------|--------------------------| | PGR | règle/contrat de gouvernance | normative dans son scope | | HOWTO | procédure, diagnostic, explication, anti-pattern | guidance | | snippet | exemple court, commande, configuration, fragment | contextualisée | | project-local | décision concrètement instanciée | locale au projet | Les métadonnées peuvent relier ces familles sans promotion automatique de force normative. Une pratique répétée dans HOWTO/snippet peut devenir un candidat d'étude PGR ; elle n'est normative qu'après le workflow PGR correspondant. ## 13. Git versus PostgreSQL ### Autoritaire dans Git - corps du contenu publié ; - métadonnées éditoriales versionnées avec ce contenu ; - historique de révisions Git ; - refs/tags/branches autorisées par la politique de chaque source. ### État applicatif PostgreSQL partagé - utilisateurs/sessions ; - propositions et revue ; - commentaires/audit applicatif ; - configuration logique persistante des sources lorsque PostgreSQL sera matérialisé ; - mapping source/famille/application ; - dernière révision synchronisée/indexée par source lorsque la persistance sera matérialisée ; - index et recherche dérivés ; - relations calculées entre familles ; - jobs de synchronisation/publication ; - cache/projections reconstructibles. ### Interdit comme raccourci architectural Une modification du contenu publié ne doit pas exister uniquement dans PostgreSQL après acceptation. L'acceptation doit produire une révision Git avant qu'elle devienne contenu publié. ## Topologie de dépôts retenue ```text sasedev-knowledge application, workspace et gouvernance de la plateforme pgr source Git normative PGR existante howtos source Git procédurale séparée snippets source Git courte/contextualisée séparée ``` Les dépôts de contenu ne sont pas fusionnés dans PGR et ne sont pas requis comme submodules Git du dépôt applicatif. Leur localisation et leurs credentials sont de la configuration de déploiement. Pendant `0.0.2`, cette configuration de déploiement est adaptée en configuration physique possédée par `knowledge-git-lib`. La racine de mirrors/worktrees reste un état généré reconstructible et ne remplace pas le futur stockage logique PostgreSQL. ## Écriture Git gardée acquise en 0.0.3-alpha.4 Le backend Git complète désormais le cycle provider-neutral d'écriture sans adapter de forge : un candidat retenu localement peut être publié vers une branche `refs/heads/...` uniquement sous garde explicite de l'état distant attendu. Le chemin est : ```text candidat retenu sous refs/knowledge/candidates/ -> observation `git ls-remote --refs origin ` -> comparaison avec GitRemoteState attendu -> git push --force-with-lease=: -> Updated(candidate) ou Conflict { actual } ``` Pour `GitRemoteState::Absent`, la lease utilise une attente vide et autorise donc uniquement la création d'une branche encore absente. Pour `GitRemoteState::Revision(r)`, la mise à jour distante n'est acceptée que si la branche pointe encore exactement sur `r`. L'observation préalable fournit un conflit rapide ; `--force-with-lease` reste la garde autoritaire contre une course entre observation et push. Après un rejet de push, le backend observe à nouveau la branche afin de traduire une divergence concurrente en conflit récupérable. Cette capacité ne fait aucun rebase/merge automatique et ne publie aucune pull/merge request. Elle utilise uniquement le remote `origin` possédé par le mirror contrôlé et conserve la forge hors du contrat. ## Réconciliation `0.0.3-beta.1` et trajectoire produit Le chemin Git générique est maintenant complet pour la responsabilité de `0.0.3` : lecture/snapshot par `GitRepository`, création locale de candidat puis push gardé par `GitRepositoryWriter`, sans API de forge. Les deux contrats restent séparés et les conflits distants sont des résultats récupérables plutôt que des rebase/merge implicites. La prochaine dépendance structurante commune aux trois produits n'est plus l'écriture Git mais l'état applicatif persistant partagé. `0.0.4` est donc retenue comme prochaine mission pour matérialiser PostgreSQL, son premier schéma et ses migrations, la configuration logique des sources et l'état minimal de synchronisation/indexation. Le choix concret du driver/ORM, du pooling et de la stratégie de test PostgreSQL reste à décider dans l'étude de démarrage `0.0.4` ; il n'est pas anticipé par `0.0.3`. La trajectoire des façades Web est désormais explicitement séparée en étapes afin de ne pas confondre design, rendu et logique serveur : ```text PostgreSQL partagé -> modèles/projections PGR + HOWTO + snippet -> templates publics des trois sites dans le template lab -> templates d'administration des trois sites dans le template lab -> routes publiques Actix + adaptation Maud des templates publics -> auth/autorisation + routes admin Actix + adaptation Maud des templates admin -> gestion/proposition/revue/publication appuyée sur Git + PostgreSQL ``` Les pages de garde, listes, détails, navigation et états de recherche/filtrage visibles sont donc conçus d'abord comme templates Web de référence. Les dashboards, formulaires et états de proposition/revue suivent le même principe côté administration. Une phase ultérieure adapte le markup validé en composants Maud servis par les trois launchers Actix, plutôt que de développer simultanément deux interfaces indépendantes. Cette trajectoire concerne les trois sites : ```text pgr.sasedev.com consultation et gestion du référentiel PGR howtos.sasedev.com consultation et gestion des HOWTOs snippets.sasedev.com consultation et gestion des snippets ``` Git reste la vérité éditoriale publiée ; PostgreSQL porte l'état transversal et les projections reconstructibles. Un contenu accepté n'est publié qu'après production d'une révision Git autoritaire, puis la projection locale est réconciliée depuis cette révision.