0.0.4-alpha.1

This commit is contained in:
2026-10-01 10:49:09 +02:00
parent b382397244
commit b55eb23dc0
12 changed files with 961 additions and 25 deletions

View File

@@ -0,0 +1,255 @@
<!-- file: docs/studies/008-V0_0_4_POSTGRES_FOUNDATION_STUDY.md -->
<!-- version: 1 -->
# Étude 0.0.4 — fondation PostgreSQL partagée
## Objet
Cette étude de `0.0.4-alpha.1` décide l'ownership et la première architecture PostgreSQL de SaseDev Knowledge avant toute implémentation de stockage.
Elle part exclusivement de la stable Knowledge `v0.0.3` publiée et vérifiée. Elle ne consulte ni n'adopte une nouvelle version de PGR.
## Baseline autoritaire vérifiée
La baseline reçue au démarrage est :
```text
tag v0.0.3
commit b3823972449150b72905930b806d4d15471cddce
archive sasedev-knowledge-v0.0.3.zip
SHA-256 82407dc2a83be878daa65692f975681428d0adc721ff249c3c9020e3a9d1f29d
report sasedev-knowledge-0.0.3-publish.001-report.md = PASS
```
La vérification de démarrage confirme :
- `VERSION = 0.0.3` et `[workspace.package].version = 0.0.3` dans l'archive ;
- neuf packages Cargo et aucune crate PostgreSQL déjà matérialisée ;
- douze deltas et douze histories `0.0.3`, appariés jusqu'à `rel.1.fix.1 = PASS` ;
- Git lecture/écriture contrôlée stable et provider-neutral ;
- `ROADMAP.md` engage déjà `0.0.4` comme fondation PostgreSQL partagée ;
- `prompts/004-V0_0_4_START_PROMPT.md` est présent dans la stable ;
- PGR `v0.1.3` reste uniquement une provenance historique de l'adoption fermée en `0.0.2`.
## Contraintes acquises
La fondation doit préserver simultanément :
```text
Git vérité du contenu publié
PostgreSQL état applicatif transversal et projections reconstructibles
knowledge-domain-lib aucun type SQL/Actix/Gitea
knowledge-git-api contrats Git provider-neutral
knowledge-git-lib configuration physique et opérations Git
knowledge-app-lib orchestration applicative
knowledge-web-lib composition Web partagée
```
La première implémentation PostgreSQL ne doit pas entraîner par symétrie une nouvelle crate `-api`, un service réseau, trois bases séparées, un ORM complet, un scheduler ou un modèle de contenu final.
## Sources techniques consultées
Consultation effectuée le `2026-09-30` sur les documentations publiées des crates comparées :
- SQLx `0.9.0` et ses features/MSRV : <https://docs.rs/crate/sqlx/0.9.0/source/Cargo.toml.orig> ;
- `PgPool` SQLx : <https://docs.rs/sqlx/0.9.0/sqlx/postgres/type.PgPool.html> ;
- migrations et `migrate!` SQLx : <https://docs.rs/sqlx/0.9.0/sqlx/migrate/index.html> et <https://docs.rs/sqlx/0.9.0/sqlx/macro.migrate.html> ;
- `tokio-postgres` `0.7.18` : <https://docs.rs/tokio-postgres/0.7.18/tokio_postgres/> ;
- `deadpool-postgres` `0.14.2` : <https://docs.rs/deadpool-postgres/0.14.2/deadpool_postgres/> ;
- Diesel `2.3.13` : <https://docs.rs/crate/diesel/2.3.13> ;
- `diesel-async` `0.9.2` : <https://docs.rs/crate/diesel-async/0.9.2> ;
- SeaORM `2.0.4` : <https://docs.rs/crate/sea-orm/2.0.4> ;
- Refinery `0.9.2` : <https://docs.rs/crate/refinery/0.9.2>.
## Comparaison des options Rust
État des versions consultées le `2026-09-30` : SQLx `0.9.0`, `tokio-postgres` `0.7.18`, `deadpool-postgres` `0.14.2`, Diesel `2.3.13`, `diesel-async` `0.9.2`, SeaORM `2.0.4` et Refinery `0.9.2`.
| Option | Atouts pour Knowledge | Coûts / inadéquations | Décision |
|----------------------------------------|---------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|----------|
| `tokio-postgres` + Deadpool + Refinery | driver PostgreSQL async natif, responsabilités séparées, SQL explicite, pool spécialisé et migrations SQL intégrées | trois briques à versionner et intégrer ; la façade Knowledge doit normaliser leurs erreurs | `SELECT` |
| SQLx `0.9` | async/Tokio, PostgreSQL natif, pool et migrations intégrés, SQL explicite | toolkit multi-SGBD plus large que le besoin ; MSRV `1.94`; ses macros de requêtes ne sont pas nécessaires ici | `REJECT` |
| Diesel + `diesel-async` | typage/DSL fort, écosystème migrations, pooling disponible | modèle ORM/query-builder plus large que le premier schéma et davantage de surface de génération/traits | `REJECT` |
| SeaORM | ORM async complet, migrations, relations et modèles riches | surdimensionné avant les modèles/projections `0.0.5`; risque de faire remonter l'ORM dans les contrats | `REJECT` |
La sélection privilégie des responsabilités explicitement bornées plutôt qu'un toolkit généraliste. Knowledge cible PostgreSQL comme choix de produit : l'abstraction multi-SGBD de SQLx n'apporte donc pas de valeur attendue pour cette fondation. Le coût de composition de trois briques reste acceptable parce que chacune possède une responsabilité unique et vérifiable.
## Décision de dépendance
La première implémentation utilisera `tokio-postgres` comme driver PostgreSQL asynchrone natif, `deadpool-postgres` comme pool et `refinery` comme owner technique des migrations SQL. Aucun ORM n'est sélectionné et aucune abstraction multi-SGBD n'est recherchée.
Les versions observées pendant l'étude sont `tokio-postgres 0.7.18`, `deadpool-postgres 0.14.2` et `refinery 0.9.2`. `tokio-postgres` et `deadpool-postgres` déclarent actuellement Rust 2024 avec un MSRV `1.85`; Refinery vise les Rust stable récents. `alpha.2` doit néanmoins revalider les versions stables compatibles au moment exact de leur ajout au manifest, conformément à la politique locale de dépendances, sans downgrade silencieux.
La séparation est volontaire :
```text
tokio-postgres protocole, connexion, requêtes et transactions PostgreSQL
deadpool-postgres cycle de vie et mutualisation des connexions
refinery découverte, historique et application des migrations SQL
```
La façade publique de `knowledge-store-postgres-lib` masque ces dépendances et normalise leurs erreurs dans le type d'erreur de la crate. Les types `tokio-postgres`, Deadpool ou Refinery ne doivent pas remonter dans `knowledge-domain-lib` ni dans les contrats applicatifs.
Un backend TLS n'est pas figé par `alpha.1`. Si la cible de déploiement PostgreSQL exige TLS, la tranche qui matérialise la connexion doit sélectionner explicitement l'intégration TLS minimale compatible avec `tokio-postgres` au lieu d'hériter d'un défaut implicite.
## Ownership
La responsabilité est suffisamment concrète pour justifier :
```text
knowledge-store-postgres-lib
```
Cette crate possédera :
- construction et lifecycle du pool `deadpool-postgres` ;
- migrations SQL de Knowledge ;
- mapping SQL des types nécessaires ;
- persistance de configuration logique de source ;
- persistance de l'état de synchronisation ;
- erreurs publiques récupérables de cette frontière.
Elle dépendra des types domaine/Git strictement nécessaires, jamais l'inverse.
Aucun `knowledge-store-api` n'est créé en `0.0.4-alpha.1`. Si une deuxième implémentation réelle ou un besoin de fake transverse rend plus tard une frontière passive utile, cette décision sera réévaluée à partir d'un usage concret.
## Connexion, pool et secrets
La crate de stockage ne lit pas l'environnement. La composition lui fournit une configuration contenant au minimum l'URL PostgreSQL et les paramètres de pool retenus.
L'URL peut contenir un secret et respecte donc les invariants suivants :
- aucune valeur réelle versionnée ;
- aucune URL complète dans les erreurs publiques ou logs ;
- aucune valeur par défaut de production codée en dur ;
- aucune tentative de fallback vers un fichier, SQLite ou un stockage mémoire si PostgreSQL est indisponible.
Le pool est partagé par l'instance applicative qui compose le store. Les trois produits peuvent pointer vers la même base logique sans que chaque launcher réimplémente sa propre couche SQL.
## Premier schéma utile
Le premier schéma est volontairement plus petit que l'état futur décrit dans l'architecture.
### `knowledge_sources`
```text
source_id TEXT PRIMARY KEY
family TEXT NOT NULL
git_reference TEXT NOT NULL
```
`source_id` correspond à `SourceId`. `family` représente `ContentFamily` avec une contrainte SQL sur les valeurs supportées. `git_reference` est la référence Git logique à résoudre, pas une URL remote ni un credential. Les valeurs `family` persistées sont `pgr`, `howto`, `snippet` et `project_local`; la migration doit les contraindre explicitement.
### `knowledge_source_sync_state`
```text
source_id TEXT PRIMARY KEY REFERENCES knowledge_sources(source_id) ON DELETE CASCADE
last_synchronized_revision TEXT NOT NULL
```
La révision stockée représente la dernière révision effectivement acceptée par le cas d'usage de synchronisation. Elle est un état applicatif de comparaison. Git reste capable de fournir l'identité autoritaire et une valeur PostgreSQL perdue ou obsolète conduit à une nouvelle réconciliation, pas à une perte du contenu publié.
Le schéma n'ajoute pas encore :
- corps ou métadonnées éditoriales de contenu ;
- révision indexée séparée avant l'implémentation réelle des projections ;
- utilisateurs/sessions ;
- propositions/revues ;
- jobs ;
- audit applicatif ;
- moteur de recherche.
## Migrations
Les migrations sont des fichiers SQL versionnés sous :
```text
crates/knowledge-store-postgres-lib/migrations/
```
La crate embarque le jeu de migrations au build et expose une opération explicite d'application. Le schéma n'est pas créé implicitement à chaque requête.
Les migrations sont forward-only pour cette fondation : une correction de schéma publiée utilise une nouvelle migration. Un rollback destructif automatique n'est pas requis pour fermer `0.0.4`.
## Stratégie de test PostgreSQL
Le test réel doit prouver PostgreSQL, pas une imitation en mémoire.
La stratégie retenue est :
```text
KNOWLEDGE_POSTGRES_TEST_URL
-> PostgreSQL local ou service CI explicitement fourni
-> création d'un schéma de test unique
-> search_path borné à ce schéma
-> application des migrations
-> tests CRUD / état de synchronisation
-> suppression du schéma
```
Cette stratégie évite d'imposer Docker dans la bibliothèque tout en autorisant un service container en CI. L'absence du service requis pendant une gate qui exige le test PostgreSQL est `BLOCKED`, pas `PASS`.
Les tests unitaires sans PostgreSQL restent utiles pour les validations de types/configuration qui n'ont pas besoin d'un serveur réel, mais ils ne remplacent pas l'intégration PostgreSQL de migration et persistance.
## Raccord au cas d'usage de synchronisation
Le cas d'usage existant `synchronize_repository` reçoit actuellement `previous_revision` de son appelant. `0.0.4` doit conserver cette primitive provider-neutral.
Le raccord prévu est une orchestration supplémentaire qui :
```text
charge last_synchronized_revision
-> appelle synchronize_repository
-> enregistre la révision observée après succès
```
Un contrat passif de persistance peut vivre dans `knowledge-app-lib` si `alpha.4` démontre qu'il est nécessaire pour tester cette orchestration sans coupler l'application au driver PostgreSQL. Cette possibilité ne justifie pas à elle seule une crate `knowledge-store-api`.
## Indisponibilité PostgreSQL
Les erreurs de connexion, acquisition de pool, migration ou requête sont récupérables et typées à la frontière store.
Il n'existe pas de mode où une écriture est annoncée persistée alors que PostgreSQL ne l'est pas. Une future façade publique pourra continuer à servir un contenu Git déjà matérialisé seulement si son cas d'usage n'exige pas le store ; cette politique appartient à la composition de la façade, pas à un fallback interne de la crate de stockage.
## Impact sur les trois applications
`0.0.4` ne crée pas trois implémentations ou trois schémas par façade. `knowledge-store-postgres-lib` est le propriétaire partagé et la base logique est commune.
Les launchers ne seront modifiés que lorsqu'un cas d'usage runtime exige réellement la connexion. La fondation peut donc être testée indépendamment avant d'ajouter une dépendance de démarrage PostgreSQL à `/` et `/healthz`.
## DEFER conservés
Restent explicitement hors scope de `0.0.4` :
- formats finaux et parsing PGR/HOWTO/snippet ;
- projections de contenu finales et révision indexée détaillée ;
- recherche avancée ;
- Gitea/forge et webhooks forge-only ;
- scheduler/jobs ;
- auth, sessions et rôles/capabilities ;
- propositions/revues/publication produit ;
- templates publics/admin et routes finales ;
- quatrième application admin ;
- partage multi-processus de la racine Git ;
- Git LFS/submodules et rétention avancée.
## Horizon
L'étude ne révèle aucune dépendance fausse dans la revue `0.0.3-beta.1`.
L'horizon reste donc :
```text
0.0.5 modèles de contenu et projections
0.0.6 templates publics
0.0.7 templates d'administration
0.0.8 lecture publique Actix Web / Maud
0.0.9 administration Actix Web / Maud et autorisation
0.0.10 gestion, proposition, revue et publication
```
## Conclusion
`0.0.4` peut progresser sans REPLAN : l'owner PostgreSQL est démontré, `tokio-postgres`, `deadpool-postgres` et `refinery` couvrent respectivement le driver, le pool et les migrations nécessaires, le premier schéma est borné et reconstructible par rapport à Git, et une stratégie de test PostgreSQL réelle est définie sans imposer un outil de provisioning unique.
`alpha.1` ne crée encore aucune crate, dépendance ou migration. Après son `PASS` opérateur, `alpha.2` peut matérialiser `knowledge-store-postgres-lib`, le trio `tokio-postgres` / `deadpool-postgres` / `refinery` et la première migration.