apomesh-state-store-smartchat-postgres
The Postgres adapter behind
SmartChat’s SmartChatStore
port — the durable home for operator-chat conversations and their turns.
It is a sibling to
apomesh-state-store-postgres:
same crate-direct sqlx layout, same inline migration-runner pattern,
but a disjoint schema (SmartChat’s tables stay SmartChat’s, the
substrate’s stay the substrate’s). Reach for this crate when a
deployment needs SmartChat conversations to survive a daemon restart;
without a Postgres pool the daemon falls back to the in-memory adapter.
Position in the workspace
Section titled “Position in the workspace”- Layer: state stores — the durable adapter behind SmartChat’s
store port, not a substrate
StateStore. It implements theSmartChatStoretrait owned by apomesh-smartchat. - Depends on:
apomesh-smartchat (the
SmartChatStoretrait plus theConversation/Turndomain types) and apomesh-substrate (TenantId,TenantContextfor tenant-scoped queries). - Consumed by: apomesh-orchestrator-bin — the only consumer; it selects this adapter at boot when a Postgres pool is present.
What it owns
Section titled “What it owns”PostgresSmartChatStore— the durableSmartChatStoreimplementation. Every query is tenant-scoped (tenant_idin theWHEREclause), and a cross-tenant or missing row folds intoConversationNotFoundso the adapter never leaks cross-tenant existence.- Embedded, independently-tracked migrations — a
MIGRATIONSconst embeds eachmigrations/*.sqlviainclude_str!;run_migrationsapplies them transactionally and idempotently, tracked in a_smartchat_migrationstable kept separate from the substrate’s_apomesh_migrationsso the two schemas evolve on their own timelines. - Crate-direct
sqlx— the crate goes straight tosqlx-core/sqlx-postgres(no umbrellasqlxcrate) for the same reason the substrate’s Postgres adapter does: to avoid the umbrella’s transitivesqlx-sqlitecolliding with the substrate’srusqlite. - Shared-pool construction —
from_poolwraps an existingArc<PgPool>so the orchestrator can share one connection pool with the substrate’s state-store adapter and keep connection counts bounded.
Public surface
Section titled “Public surface”Verified against lib.rs:
PostgresSmartChatStore::connect(url, pool_size) -> Result<Self, PostgresSmartChatError>— open a fresh pool for the adapter.PostgresSmartChatStore::from_pool(Arc<PgPool>) -> Self— the production path: share the process-wide pool.run_migrations() -> Result<(), PostgresSmartChatError>— apply the embedded SQL; idempotent.pool() -> &Arc<PgPool>— borrow the underlying pool (test probing).- The
SmartChatStoretrait methods (create_conversation,get_conversation,list_conversations,rename_conversation,delete_conversation,append_turn,set_turn_outcome,list_turns) are implemented here; their contracts live on the apomesh-smartchat trait. PostgresSmartChatError— construction/migration errors (Connect,Migration); runtime query errors surface asSmartChatError::Store.
The daemon selects the durable adapter when a Postgres pool is available, falling back to the in-memory store otherwise:
use std::sync::Arc;use apomesh_smartchat::{InMemorySmartChatStore, SmartChatStore};use apomesh_state_store_smartchat_postgres::PostgresSmartChatStore;use sqlx_postgres::PgPool;
# async fn wire(pool: Option<Arc<PgPool>>) -> anyhow::Result<()> {let store: Arc<dyn SmartChatStore> = match pool { Some(pool) => { let store = PostgresSmartChatStore::from_pool(pool); store.run_migrations().await?; Arc::new(store) } None => Arc::new(InMemorySmartChatStore::new()),};# let _ = store;# Ok(())# }Related
Section titled “Related”- Reference:
apomesh-smartchat — the
SmartChatStoreport and domain types this adapter persists. - Reference: apomesh-state-store-postgres — the sibling substrate adapter it shares a pool and layout with.