@lssm-tech/integration.growth-persistence
Server-only persistence for GrowthOS referral and affiliate state. It provides a serialized in-memory adapter for tests, a structural PgLite/Postgres adapter, and matching Drizzle table exports with tenant, entity, external conversion, link-code, reward-rule/beneficiary, webhook-event, and idempotency constraints.
Every mutation runs inside a transaction. Ledger entries and webhook receipts are immutable, payout items remain separately addressable, and duplicate conversions or rewards are rejected. Provider credentials and raw acquisition tokens are not persisted.
The optional ./marketing subpath provides SqlMarketingExecutionStore,
SqlEditorialStore and SqlMediaGenerationStore using the same pinned-transaction SQL client. Each exposes an additive migrate() for host-owned migrations in the private marketing_execution schema. Revision updates append history atomically. Budget reservations serialize by brand scope, unknown dispatches retain liability, and definitive failures release their reservation. Media history stores provider job IDs and durable artifact references, never temporary download URLs.
SqlMarketingProposalStore persists goal-plan requests and immutable result history. It permits one generating-to-result transition per request, protects the original goal/brand binding, and isolates records by tenant, workspace and brand.
SqlMarketingConversionStore persists conversion revisions and append-only receipt history in the private marketing_execution schema. Call migrate() before mounting the conversion service. Accepted history is immutable, corrections are ordered, and CAS claims prevent concurrent workers from dispatching the same revision twice.
SqlMarketingObservationStore preserves immutable snapshots partitioned by campaign, platform, account and tenant/workspace/brand. Late polls cannot replace newer snapshots; conflicting same-timestamp writes fail. SqlMarketingObservationEvidenceStore retains sanitized provider responses for replay and rejects credential-bearing artifacts. Run both stores' migrate() methods before mounting the observation service.
Social scheduling adapters (SqlSocialScheduleStore, SqlSocialIntentStore,
SqlSocialRecoveryLeases) implement library-owned contracts with SQL history, CAS, server-clock lease expiry and monotonically fenced recovery. Call their migrate() methods before starting workers. Canonical intent creation verifies the publication-key binding and rejects changed payloads; recovery claims require the matching live lease. Grant verification, policy evaluation, provider bindings and audit delivery remain host-owned requirements. The adapters never supply an allowing authority.
SqlXPublicationStore persists immutable reviewed thread plans, per-part CAS claims and append-only history. It verifies canonical root identity, scoped native request digests, predecessor IDs and confirmation author/media/reply facts. SqlSocialIntentStore supports fenced continuation of reconciled parent intents without changing their publication keys.
SqlXUploadStore persists immutable asset/chunk manifests and sequential native upload claims with transactional history. Migrate before starting upload workers. It rejects plan changes, altered native identity, reset uncertain steps and terminal-state rewrites. Source media bytes and credentials remain outside the store.
SqlLinkedInMediaJobStore persists scoped image/video plans, exact dispatch claims, part receipts and immutable history. Private upload capabilities are stored separately through LinkedInSecretSessionVault; the SQL payload contains only versioned references. Migrate before running the bounded native upload worker.
SqlPlanningApprovalStore persists private planning quotes, immutable issued receipts, revocation and revision history. Its consume method implements the canonical nonce store with atomic SQL uniqueness. Run migrate first and retain nonce rows through their expiry. Receipt records are private authority evidence, never analytics or public assets.
SqlMarketingOptimizationEvidenceStore records immutable assessed experiment documents, recomputes assessments before writes, and returns canonical SHA-256 artifact references. Use record for the marketing promotion wrapper's recordEvidence callback. Reads require explicit marketing scope and verify stored content against the artifact digest. Host authorization remains mandatory before storage access.
SqlMarketingOptimizationLifecycleStore implements the shared lifecycle store with an explicit marketing scope/program binding. Candidates are immutable; receipt appends serialize per candidate and validate canonical replay before committing. Duplicate receipts must match exactly; changed identities, digest chains and sequence gaps fail. It reconstructs current state from durable history. Effect adapters must separately honor the lifecycle idempotency key and expected state/sequence before external actions.
SqlContentRightsStore serializes rights grants and registered uses per tenant/workspace and appends immutable snapshots. Revocation and withdrawal queue creation share one transaction. Supply it to ContentRightsService; provider removal and confirmation evidence remain separate execution responsibilities.
Rights invariants are also enforced at the storage boundary: revoked grants cannot be reactivated, registered-use identities cannot change, confirmed withdrawals cannot be rewritten, and revocation cannot commit while existing uses lack withdrawal obligations. A failed invariant rolls back the entire scope transaction.
Terminal withdrawal jobs must commit with matching registered-use state and evidence. An unavailable automated attempt may later be resolved by separately evidenced manual confirmation; a confirmed job cannot leave its use pending.
SqlContentWithdrawalQueue supplies durable pending-use discovery and batch-result tracking. Migrate the rights store first, then the queue. Discovery selects pending uses within its authorized scope and processes never-attempted/least-recently-attempted items first, so unresolved removals do not starve later revocations. Terminal result records must agree with authoritative use state. Bind loadPending/recordResults to the installation withdrawal worker's callbacks.
SqlEditorialStore.listRecovery reads scoped publishing/unknown claims ordered by update time and ID. Reconciled terminal records disappear from discovery; publication is never resubmitted by this read.
SqlEditorialGitStore provides additive scoped Git dispatch persistence with revision CAS. Compiler artifacts cannot change after dispatch, and confirmed commit identity cannot be rewritten. Run its migration before enabling a Git publisher.
Run the updated SqlEditorialGitStore.migrate() before enabling preparation-failure handling. Additive claim-lock and failure tables serialize failure versus dispatch, retain immutable receipts and fence failed claims. Preserve one canonical writer while upgrading. Confirmed preparation failure permits the editorial article to be revised under a new publication claim.
SqlEditorialStore.listPage supports bounded keyset discovery with a C-collation ID index and parameterized filters. Run migrate to install the additive listing index. The runtime authorizes rows and emits summaries without Markdown.
SqlEditorialStore.listHistory reads existing append-only editorial_history records with exact scope, revision bounds and pagination. It does not modify or reconstruct prior revisions.
Media generation persistence rejects removal or replacement of existing artifact references. Each imported output may add a running-state history revision before final success.
Media persistence enforces immutable expected output counts and requires succeeded jobs to contain exactly that many durable artifact references when the count is known.