# Guide PostgreSQL et contrats de stockage ## Objectif `ks-store` porte la frontière de stockage généraliste. PostgreSQL reste le backend opérationnel actif, mais il est encapsulé derrière la façade publique backend-agnostique `Store`. ## Connexion Les consommateurs ne construisent plus `PostgresStore`, `PostgresStoreOptions` ni un pool SQLx. Ils transmettent le backend sélectionné et ses options résolues à `StoreOpenOptions`; `ks-store` valide et interprète ensuite les paramètres PostgreSQL. ```rust let options = match ks_store::StoreOpenOptions::new( true, "postgres", serde_json::json!({ "url": database_url, "max_connections": 10, "connect_timeout_ms": 10_000, "auto_initialize_schema": true }), ) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let store = match ks_store::Store::open(options).await { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; ``` Le descripteur public éventuellement affiché provient du résumé runtime et est déjà masqué par `ks-store`. Le DSN brut et les options backend ne doivent jamais être propagés dans les DTO, erreurs applicatives ou logs normaux. ## Domaines - N1 raw/acquisition : transactions canoniques, observations de transactions et observations génériques de comptes ; - N2 Core : transactions, clés, top-level, CPI, logs, variations de balances, return data et états de comptes ; - N3/transverse : ledger, observations décodées, couverture et `k_sol_mat_outputs` ; - replay/diagnostic : sélections et résumés bornés au-dessus de ces contrats. ## Baseline `0.5.3-pre.003` `pre.003` reconstruit directement le schéma sous `k_sol_*`. Les bases Devnet/Mainnet/test historiques sont considérées reconstructibles ; aucune migration in-place depuis `kb_sol_*` n'est fournie. Le comportement attendu à l'ouverture est : 1. base vide + auto-init : création du baseline complet ; 2. base `k_sol_*` déjà conforme : vérification/idempotence ; 3. base contenant encore des objets `kb_sol_*` : refus non destructif et demande de reconstruction explicite ; 4. `DROP`/`TRUNCATE` : opérations de maintenance distinctes, jamais déclenchées implicitement par `Store::open()`. Le baseline candidat au gel comprend 16 tables N1-N3. ## Ressources SQL Les ressources actives sont sous : ```text ks-store/migrations/postgres/ schema/ tables/ constraints/ indexes/ maintenance/ truncate/ drop/ ``` Chaque fichier contient une instruction SQL. Le code PostgreSQL privé utilise `include_str!` et l'orchestrateur global exécute le schéma dans une transaction unique avec advisory lock. Il n'existe plus trois initialiseurs raw/Core/decode indépendants : **l'initialisation du schéma est globale**. Le corpus `pre.003` contient actuellement : - 16 créations de tables ; - 129 ressources de contraintes ; - 59 créations d'index explicites ; - 16 ressources `TRUNCATE` ; - 16 ressources `DROP` ; - quatre index supplémentaires justifiés par le replay/invalidation `pre.004` ; - soit **240 ressources SQL**. PostgreSQL attend désormais **79 index** au total dans son diagnostic : 63 index explicites plus les 16 index de clé primaire créés par PostgreSQL. Les index non uniques restent des optimisations physiques et ne font pas partie du gel logique N1-N3. ## Repositories `pre.004` La tranche `pre.004` conserve les 16 tables et ferme les comportements suivants : - replay logique commun top-level/CPI avec scope explicite et pagination keyset ; - lifecycle symétrique top-level/CPI ; - invalidation N2 Core -> N3 lors d’un remplacement de signature ; - invalidation decode -> matérialisation pour l’identité decoder exacte ; - normalisation versionnée `k_sol_obs_account_observations` -> `k_sol_core_account_states` ; - limites interactives à 500 et batches de processing à 1 000 ; - traces fonctionnelles `TRACE ks-store` avec durée/lignes/outcome, sans bind values. Les quatre nouveaux index couvrent l’ordre de replay CPI et les recherches d’invalidation/descendants dans coverage/materialization. Leur utilité finale doit encore être confirmée par des plans PostgreSQL réels avant le gel ; les index non uniques restent une optimisation physique. ## Statut du schéma La façade n'utilise plus `_sqlx_migrations` comme preuve du baseline actuel. Le statut est dérivé du contrat réellement observé : - aucune ressource connue : non initialisé ; - toutes les ressources attendues : contrat courant ; - présence partielle : drift/partial. Le résumé d'initialisation expose des compteurs de modèles, tables et index sans publier leurs noms physiques. ## Compatibilité des identités de processeurs Depuis `0.5.1-pre.003`, les identités techniques produites par `ks-lib` utilisent `ks-lib-decoder.*`, `ks-lib-executor.*` et `ks-lib-materializer.*`. Comme les bases `0.5.2` doivent être reconstruites pour le nouveau baseline `0.5.3`, les anciennes identités `kb-lib.*` ne sont pas migrées automatiquement dans ce chantier. ## Core readiness `pre.003` ajoute les éléments génériques nécessaires au futur redécodage : - `block_time` sur raw/Core transaction ; - `stack_height` sur top-level/CPI ; - parent CPI immédiat reconstructible ; - `k_sol_core_return_data` ; - `k_sol_obs_account_observations` ; - `k_sol_core_account_states` ; - provenance de schéma optionnelle sur les observations décodées. Ces contrats sont indépendants d'Anchor/IDL. Aucun parser Anchor ni table `anchor_*` n'appartient à `0.5.3`. ## Repositories Les traits publics et la façade `Store` décrivent des opérations fonctionnelles indépendantes du moteur. PostgreSQL implémente ces contrats à l'intérieur de `ks-store`; aucune crate consommatrice ne reçoit `PgPool`, un type SQLx ou une requête concrète. Le schéma des observations/états de comptes est introduit avant gel en `pre.003`; son ingestion/replay fonctionnel est raccordé dans la tranche repositories/replay suivante. ## Diagnostics La surface publique expose : - health snapshot ; - schema/migration snapshot générique ; - backend descriptor masqué ; - résumé de configuration sanitisé ; - résumé d'initialisation/vérification par modèle logique ; - diagnostics de ressources sans nom physique d'objet. Les noms de tables, index, contraintes et le SQL restent des détails backend-internes. Les traces PostgreSQL utilisent l'unique `target: crate::TRACING_TARGET` (`ks-store`) avec les champs structurés `backend="postgres"`, `domain="ks-store.pg"` et un `action` précis. ## Invariants - aucune donnée canonique ne doit être dupliquée sans justification ; - les écritures rejouables doivent être idempotentes ; - la progression de campagne doit rester cohérente avec les lignes effectivement traitées ; - les requêtes dynamiques n'acceptent que des identifiants validés ; - les détails PostgreSQL utiles au diagnostic restent backend-internes ; - les erreurs traversant la façade publique ne doivent jamais divulguer DSN, password ou options sensibles ; - un nouveau décodeur doit pouvoir exploiter N1/N2/N3 sans remodelage normal de ces niveaux. ## Références - `docs/architecture/STORAGE_ARCHITECTURE.md` ; - `ks-store/USAGE.md` ; - `ks-store/README.md`.