Skip to main content

Crate syrup_rail_postgres

Crate syrup_rail_postgres 

Source
Expand description

PostgreSQL schema contract and transaction orchestration for Syrup Rail.

Production service construction must not expose or invoke a migrator; host applications materialize versioned install artifacts as immutable migrations.

§syrup-rail-postgres

syrup-rail-postgres provides Syrup Rail’s canonical provider-neutral ledger, SQLx operations, and high-level subscription billing service. Version 0.5 supports PostgreSQL 18 only and uses schema v4.

[dependencies]
syrup-rail = "0.5.0"
syrup-rail-postgres = "0.5.0"

New hosts install schema/v4/install.sql through their normal migration system. Existing schema-v3 hosts separately commit schema/v4/prepare_from_v3.sql and schema/v4/validate_from_v3.sql, run schema/v4/index_from_v3.sql outside a transaction, and finally commit schema/v4/upgrade_from_v3.sql while following the versioned cutover guide. Schemas v1, v2, and v3 are immutable. The detailed versioned guides explain the required lock, maintenance, and rehearsal boundaries.

After the host applies its migration and before it serves billing traffic, verify the runtime catalog:

syrup_rail_postgres::assert_runtime_schema_v4_compatible(pool).await?;

During REINDEX CONCURRENTLY, PostgreSQL exposes the command, phase, and target details only to the maintenance role and statistics-privileged roles. The runtime assertion tolerates _ccnew and _ccold shadows only when those visible progress details and the backend’s relation locks agree, then rechecks the evidence before committing. Run maintenance and startup validation as the same database role when startup must remain available during a reindex; a cross-role observer fails closed. Drop stale invalid shadows left by failed maintenance before serving billing traffic.

SubscriptionBillingService is the primary mutation facade. Hosts supply offer locking, gateway resolution, abuse admission, and a transaction coordinator that locks the authorized billing subject first and appends every typed BillingEvent to the host outbox on the same connection. The packaged host_integration example includes concrete service wiring and a versioned, redacted host-owned event-envelope mapping. It separates first-write metadata from the replay-stable value and demonstrates the complete atomic insert/conflict-read/raw-structural-comparison/typed-reconstruction path on the same transaction. Version 1 owns its nested enum labels instead of delegating them to core display methods. The example keeps subject identifiers and payload values out of Debug output; its card payload uses the core canonical brand vocabulary and never copies an unknown provider string into the host event.

The service requires a live gateway account by default. A host exercising a dedicated test environment can call with_required_gateway_account_mode(GatewayAccountMode::Test) to require an exact test account instead. That setting permits test-mode mutations but still rejects an observed live account before submission; bind it only to trusted deployment configuration. A single NMI account can therefore be used only for a carefully serialized staging/live cutover, but NMI mode lookup and sale are separate requests and a Merchant Portal user can change the same account-wide switch out of process. Use separate NMI test and production merchant accounts when test/live isolation matters. The service performs an early account-mode query before final admission and a mandatory second query immediately before provider submission. The second query narrows the race window and makes the safety check structural for supported low-level submitters; it cannot make two NMI requests atomic. Initial enrollments and prepared host-charge replays change from query → mutation to query → query → mutation, roughly 50% more provider requests for those flows. Renewals, recoveries, payment-method replacements, and fresh host charges already performed a final readiness query, so their request counts do not increase. A transient failure of the new final query occurs after durable admission, but the provider mutation endpoint was not contacted. Resumable enrollment, recovery, payment-method replacement, and host-charge attempts are therefore atomically restored to prepared state and can retry with the same command and idempotency key. Automatic renewal retains terminal not-submitted handling because its scheduler does not resume prepared attempts. Approved enrollments also persist the required mode on the subscription. Renewal dispatches expose it for host routing, and renewal, recovery, and payment-method replacement reservations reject a service configured for the other mode before creating new provider work. A mode-specific scheduler should use due_renewals_page_for_mode; the returned cursor records that mode and rejects cross-mode reuse. Its dedicated mode-leading index filters before the bounded SQL page limit. The unfiltered due_renewals_page remains available to a central router that owns both modes. Entitlement queries and guards default to live paid subscriptions; test workers select Test, while trusted administrative tooling can opt into both modes with across_gateway_account_modes. Current-subscription, portal, and history projections remain mode-neutral, so a host that mixes modes must enforce its own trusted production access partition around those reads.

Supported low-level provider submission functions consume an opaque ModeVerifiedGateway created by verify_gateway_account_mode; they do not accept a raw gateway. The value captures early readiness and the expected mode, then revalidates that mode when consumed. A successful test-mode capability still executes the real NMI API request, whose processing is controlled by NMI’s account-wide TEST mode. All matching reservation constructors require the trusted account mode explicitly rather than defaulting to live. When a transient final mode query restores a host charge for same-key retry, HostChargeTargetStore::ensure_submission_admitted is invoked again for that attempt. Hosts must make that callback repeat-safe and reserve one-shot paid/failed business effects for apply_transition. Terminal host-charge replay and prepared replay owned by the other deployment mode resolve by idempotency before HostChargeTargetStore::preflight_target. A same-mode prepared replay invokes the snapshot callback again so a changed target charge becomes an idempotency conflict before gateway I/O.

Errors returned by host transaction, event, charge-target, and operator-review callbacks remain opaque through ordinary formatting and the standard Error::source() chain. A host can deliberately recover its original callback error only by classifying the outer service error, destructuring an owned callback-error variant, and consuming that wrapper with into_source() in a protected diagnostic path.

GatewayReadiness can be returned after a token-free attempt was committed. At that boundary, transient unavailability leaves the attempt pending for the same-key retry, while determinate readiness failures first persist their exact terminal resolution. Replaying the same command and idempotency key returns or resumes the canonical attempt before host admission or gateway I/O; an error is not permission to substitute a new key.

§Reconciliation phase order

The host owns the reconciliation scheduler. For each account returned by reconciliation_gateway_accounts, run the local-only cleanup phases before calling claim_exact_reconciliation_attempts:

  1. fail_stale_unsubmitted_payment_method_replacements;
  2. fail_stale_unsubmitted_subscription_charges;
  3. fail_stale_unsubmitted_subscription_enrollments; and
  4. fail_stale_unsubmitted_host_charges when host charges are configured.

The host-charge phase also requires the host’s HostChargeTargetStore; it releases the host-owned target and fails the canonical attempt in one database transaction. Local cleanup never contacts the gateway. The cleanup functions are safe to repeat, and the bounded phases should run on every scheduled pass so locked work or a backlog is retried later. Exact provider queries are only for attempts whose submitted_at proves that submission began.

fail_stale_unsubmitted_host_charges returns failed and skipped counts. A StaleTarget, Unchanged, concurrent change, or contended-row outcome leaves the target and financial attempt state untouched, increments skipped, and does not prevent later candidates from progressing. Candidate selection uses the attempt’s updated_at as a durable scheduling claim, so previously skipped rows sort behind unclaimed work and become retryable after the claim interval. The host callback should record the target-specific incident for operator follow-up; the account scheduler can continue its remaining local and exact reconciliation phases.

An existing 0.2.0 host must add the subscription-charge phase, plus the host-charge phase when host charges are configured, to its reconciliation loop when upgrading to 0.3.0. Omitting them leaves abandoned local rows for foreground reads or later cleanup even though exact reconciliation correctly excludes never-submitted attempts. The existing enrollment phase also repairs never-submitted initial attempts that 0.2.0 may already have parked as review_required. The schema-v3 cutover separately preserves historical combined attempt names as canonical first-name values and adds lossless last-name persistence for new attempts.

Customer billing portal/history queries, stable due-renewal pagination, and other lower-level transaction-local operations remain available for hosts that need to compose them into a larger application transaction. The protected-write guard described below deliberately owns its top-level transaction instead. Authentication, authorization, migrations, job queues, and event transport remain host-owned.

Protected product writes use two ownership-enforced phases. Start an EntitlementWriteTransaction from the pool and use its connection for any preparatory host writes; that pending value has no commit operation. require_entitlement_for_update returns an AdmittedEntitlementWriteTransaction only when current paid or granted access is admitted and keeps the relevant locks held for the host mutation. Completed denials and SQL failures await rollback, while cancellation queues rollback of the owned transaction, including any earlier host writes. Perform and commit the host-owned protected mutation only through the admitted value, and finish any nested savepoint before consuming that value with commit or rollback.

This package is proprietary software distributed under the terms in the packaged LICENSE file.

Structs§

AdmittedEntitlementWriteTransaction
A top-level transaction that passed entitlement admission.
AdmittedHostCharge
AdmittedSubscriptionEnrollment
One committed final-admission result that authorizes exactly one immediate provider submission by consuming this value.
AdmittedSubscriptionPaymentMethodReplacement
One committed final-admission result authorizing exactly one immediate Customer Vault mutation.
AdmittedSubscriptionRecovery
One committed final-admission result authorizing exactly one immediate subscription-recovery submission.
AdmittedSubscriptionRenewal
One committed final-admission result authorizing exactly one immediate automatic recurring charge.
BillingEventWriteError
Value-redacted failure returned while appending a host outbox event.
BillingTransactionError
Value-redacted failure returned by the host transaction coordinator.
EntitlementWriteTransaction
A top-level PostgreSQL transaction awaiting entitlement admission.
ExternalReversalHostStoreError
Value-redacted failure returned by the host’s reversal target store.
GatewayLifecycleQuarantineAlert
GatewayLifecycleQuarantineResolutionRecord
GatewayLifecycleQuarantineReviewRecord
GatewayLifecycleReconciliationSummary
HostChargeLedgerAdmissionQuery
HostChargeSubmissionAdmission
HostChargeTargetError
Value-redacted failure returned by the host charge-target store.
HostChargeTargetReservation
ManualAttemptFailureHostStoreError
Value-redacted failure returned by the host’s manual-failure store.
ModeVerifiedGateway
Opaque readiness capability for a resolved gateway and required account mode.
ProcessorChargeClassificationSummary
StaleHostChargeCleanupSummary
Outcome of one bounded stale host-charge cleanup page.
SubscriptionBillingService
High-level provider-neutral billing facade for authorized host commands.
SubscriptionEnrollmentOfferContext
Stable identity and lifecycle context for locking an enrollment offer.

Enums§

BillingTransactionSubjectState
Durable availability of the host recipient locked for a billing event.
CompensatingProcessorChargeOutcome
EntitlementGuardError
EntitlementQueryError
ExactQueryObservation
ExternalReversalAttestationOutcome
ExternalReversalHostTransitionOutcome
GatewayAccountModeVerificationError
Why a resolved gateway could not be authorized for a provider submission.
GatewayLifecycleApplyOutcome
GatewayLifecycleQuarantineResolutionOutcome
GatewayLifecycleReconciliationError
GatewayMutationCooldownScope
Canonical cooldown level that stopped a gateway mutation before submission.
HostChargeAdmissionOutcome
HostChargeApplicationError
HostChargeLedgerAdmission
HostChargeLedgerAdmissionError
HostChargeLedgerAdmissionMode
HostChargePreflightOutcome
HostChargeProviderResult
HostChargeReservationDecision
HostChargeReservationOutcome
HostChargeStoreError
HostChargeSubmissionDecision
HostChargeSubmissionOutcome
ManualAttemptFailureHostTransitionOutcome
OperatorReviewError
PaymentAttemptStoreError
ProcessorChargeObservationOutcome
ProcessorChargeStoreError
RenewalStoreError
SchemaConformanceError
Why a host database does not satisfy a canonical schema contract.
SubscriptionBillingPortalQueryError
Error returned while loading a customer-facing billing portal projection.
SubscriptionBillingServiceError
Failure returned by the high-level subscription billing facade.
SubscriptionBillingServiceErrorDisposition
A stable, conservative operational category for a SubscriptionBillingServiceError.
SubscriptionCancellationError
SubscriptionDiscountOperationError
SubscriptionEnrollmentAdmissionOutcome
SubscriptionEnrollmentApplicationError
SubscriptionEnrollmentOfferStage
The lifecycle boundary at which enrollment terms are locked.
SubscriptionEnrollmentProviderResult
SubscriptionGrantMutationError
SubscriptionPaymentMethodReplacementAdmissionOutcome
SubscriptionPaymentMethodReplacementProviderResult
SubscriptionRecoveryAdmissionOutcome
SubscriptionRecoveryProviderResult
SubscriptionRenewalAdmissionOutcome
SubscriptionRenewalProviderResult

Constants§

SUPPORTED_POSTGRES_MAJOR_VERSION
The only PostgreSQL major version supported by this crate and schema contract.

Traits§

BillingTransaction
One host-owned transaction and its typed event projection capability.
BillingTransactionCoordinator
Host-prepared transaction whose subject authorization lock is acquired before any shared billing lock.
ExternalReversalHostStore
HostChargeTargetStore
Host-owned target extension composed into shared ledger transactions.
ManualAttemptFailureHostStore
SubscriptionOfferStore

Functions§

activate_gateway_configuration
Activates an exact gateway configuration without touching cooldown state.
admit_host_charge_submission
admit_host_charge_submission_in_transaction
admit_subscription_enrollment_submission
Owns and commits final enrollment admission before exposing a one-shot submission capability. A rolled-back transaction can never yield the capability consumed by submit_admitted_subscription_enrollment.
admit_subscription_enrollment_submission_in_transaction
Revalidates a prepared initial attempt and durably admits its one provider mutation.
admit_subscription_payment_method_replacement
Commits final payment-method replacement admission before exposing its one-shot Customer Vault capability.
admit_subscription_payment_method_replacement_in_transaction
Revalidates the exact subscription baseline and commits one-shot Customer Vault admission. Semantic drift terminalizes the prepared attempt.
admit_subscription_recovery_submission
Commits final recovery admission before exposing its one-shot capability.
admit_subscription_recovery_submission_in_transaction
Revalidates the exact locked snapshot and commits one-shot provider admission. Every semantic rejection terminalizes the prepared attempt.
admit_subscription_renewal_submission
Commits final automatic-renewal admission and captures the exact stored credential.
admit_subscription_renewal_submission_in_transaction
Revalidates one exact renewal snapshot and commits one-shot submission admission.
apply_exact_query_observation
Applies one authoritative negative exact-query observation.
apply_gateway_lifecycle_evidence
Applies one lifecycle observation.
apply_host_charge_gateway_outcome
apply_reconciled_host_charge_gateway_outcome
apply_reconciled_subscription_enrollment_gateway_outcome
Applies an already-observed provider outcome to an exact durable enrollment attempt.
apply_reconciled_subscription_payment_method_replacement_gateway_outcome
apply_reconciled_subscription_recovery_gateway_outcome
Re-enters the same recovery application authority from durable evidence and never resolves a live gateway or submits another mutation.
apply_reconciled_subscription_renewal_gateway_outcome
apply_staged_gateway_lifecycle_evidence
apply_subscription_enrollment_gateway_outcome
Applies one initial-enrollment gateway outcome to the durable billing ledger.
apply_subscription_payment_method_replacement_gateway_outcome
apply_subscription_recovery_gateway_outcome
Applies one recovery outcome through the canonical charge ledger and host billing transaction.
apply_subscription_renewal_gateway_outcome
assert_runtime_schema_v4_compatible
Asserts that a host database is compatible with the canonical schema-v4 contract before the host accepts billing work.
attempt_review_page
attest_external_reversal
billing_deletion_blockers
Reports the canonical financial rows that prevent host account deletion.
cancel_subscription_in_transaction
Cancels one exact scope/subscriber/plan subscription inside the caller’s transaction.
claim_exact_reconciliation_attempts
Claims one bounded, account-scoped batch for authoritative exact queries.
claim_gateway_lifecycle_quarantine_alert
claim_subscription_discount
claim_subscription_discount_in_transaction
classify_pending_processor_charges
Classifies one bounded batch of durable pending processor charges.
clear_subscription_discount
clear_subscription_discount_in_transaction
create_subscription_discount_code
create_subscription_discount_code_in_transaction
Creates an active durable code after validating its terms against the locked current offer. The returned value is the administrative record; use validate_subscription_discount_code_in_transaction to obtain a quote.
create_subscription_grant
Creates a grant inside the caller’s transaction.
disable_subscription_discount_code
disable_subscription_discount_code_in_transaction
Disables an administrative record even when its historical terms are no longer quoteable against the host’s current offer.
due_renewals
Returns the first deterministic, provider-neutral renewal dispatch page.
due_renewals_for_mode
Returns the first deterministic renewal page for one deployment mode.
due_renewals_page
Returns one deterministic page of renewal work due in a stable scan.
due_renewals_page_for_mode
Returns one deterministic page of renewal work for one deployment mode.
entitlement
Loads one exact scope/subscriber/plan entitlement from a single database snapshot.
fail_review_required_attempt
fail_stale_unsubmitted_host_charges
Fails one bounded account-scoped batch of stale local host charges.
fail_stale_unsubmitted_payment_method_replacements
Fails one bounded batch of stale payment-method replacements for an account.
fail_stale_unsubmitted_subscription_charges
Fails one bounded batch of stale local renewal and recovery attempts.
fail_stale_unsubmitted_subscription_enrollments
Expires every stale prepared enrollment for one account.
find_payment_attempt_by_id_in_transaction
Loads an attempt by its exact scope and durable identity without locking it.
gateway_lifecycle_quarantine_review_page
gateway_lifecycle_reconciliation_start
host_charge_ledger_admission
list_subscription_discount_codes
list_subscription_discount_codes_in_transaction
Lists durable administrative records without reinterpreting them against the current offer. Quote eligibility is intentionally owned by validate_subscription_discount_code_in_transaction.
lock_payment_attempt_by_idempotency_in_transaction
Locks the exact owner-scoped idempotency row for replay or mutation.
mark_subscription_discount_claim_applied_in_transaction
observe_processor_charge_in_transaction
preflight_host_charge_in_transaction
preflight_subscription_enrollment_in_transaction
Resolves subscriber-wide enrollment idempotency before host admission.
preflight_subscription_payment_method_replacement_in_transaction
Resolves payment-method replacement idempotency before host admission.
preflight_subscription_recovery_in_transaction
Resolves subscriber-wide recovery idempotency before host admission.
processor_charge_review_page
reconcile_gateway_transaction_reports
reconciliation_gateway_accounts
Returns every registered gateway account in deterministic locator order.
record_gateway_lifecycle_quarantines
register_gateway_account
Registers canonical gateway metadata on the caller’s connection.
renewal_attempt_state
Computes the one shared renewal/recovery period ledger state.
require_entitlement_for_update
Locks and revalidates one exact entitlement inside a top-level transaction.
reserve_host_charge_in_transaction
reserve_subscription_enrollment_in_transaction
Reserves or resumes one exact-plan initial enrollment inside the caller’s transaction.
reserve_subscription_payment_method_replacement_in_transaction
Locks the exact subscription baseline and reserves a token-free replacement attempt before Customer Vault I/O.
reserve_subscription_recovery_in_transaction
Locks the canonical subscription, derives the exact due-period request, and inserts a token-free recovery attempt in one transaction.
reserve_subscription_renewal_in_transaction
Locks one exact due subscription and inserts its automatic-renewal attempt.
resolve_gateway_lifecycle_quarantine
revoke_subscription_grant
Revokes an exact grant inside the caller’s transaction.
save_gateway_lifecycle_reconciliation_cursor
saved_subscription_discount_claim
saved_subscription_discount_claim_in_transaction
scrub_subscriber_billing_data
Removes the canonical mutable billing PII for one subscriber.
stage_gateway_lifecycle_evidence
store_compensating_processor_charge
submit_admitted_host_charge
submit_admitted_subscription_enrollment
Performs the one provider sale authorized by a committed final admission, then applies or durably parks its result.
submit_admitted_subscription_payment_method_replacement
Performs the one Customer Vault mutation authorized by committed admission.
submit_admitted_subscription_recovery
Performs the one provider sale authorized by committed recovery admission, then applies or durably parks its result without holding a database lock across provider I/O.
submit_admitted_subscription_renewal
Performs the one recurring sale authorized by committed renewal admission.
subscription_billing_portal
Loads a provider-neutral customer billing portal from one PostgreSQL snapshot.
subscription_payment_history_page
Returns one strict descending page of exact-plan subscription payment history.
transition_processor_charge_in_transaction
update_subscription_discount_code
update_subscription_discount_code_in_transaction
Updates a durable administrative record. Active records are validated against the locked current offer. Disabled records remain administrable without requiring their historical terms to be quoteable today.
validate_subscription_discount_code
validate_subscription_discount_code_in_transaction
verify_gateway_account_mode
Queries the real provider account and mints one readiness capability only when its observed mode exactly matches the trusted required mode. Consuming the capability for submission performs another account-mode query.