backbone-mailing 0.6.0

Email marketing — mass-mail engine: audiences, subscriptions, hand-set mailing lifecycle, seeded A/B testing, per-recipient traces, cycle-44 bridge targets (Odoo mass_mailing port)
[package]
name = "backbone-mailing"
version = "0.6.0"
edition = "2021"
description = "Email marketing — mass-mail engine: audiences, subscriptions, hand-set mailing lifecycle, seeded A/B testing, per-recipient traces, cycle-44 bridge targets (Odoo mass_mailing port)"
license = "MIT OR Apache-2.0"
repository = "https://github.com/faridlab/backbone-mailing"
exclude = [".claude/", ".github/", "graphify-out/"]

[lib]
path = "src/lib.rs"

[dependencies]
# -----------------------------------------------------------------------------
# Backbone Framework crates
#
# Pulled directly from the public framework repository so this skeleton works
# anywhere on disk without path fix-up. For reproducible builds, pin to a
# specific tag or commit by replacing `branch = "main"` with `tag = "vX.Y.Z"`
# or `rev = "<commit-sha>"`. Cargo dedupes the git fetch — the repo is only
# cloned once even though four crates reference it.
# -----------------------------------------------------------------------------
backbone-core = { version = "3.0.0", features = ["postgres"] }
backbone-orm = { version = "3.0.0" }
backbone-auth = { version = "3.0.0" }
backbone-messaging = { version = "3.0.0" }
# The public trace-route family (pixel + click) is throttled at middleware
# (ADR-0019 action_link-class routes).
backbone-rate-limit = { version = "3.0.0" }

# Sibling modules consumed through their public service surfaces: mail owns
# the outgoing queue the send engine enqueues into (plus the email blacklist
# and the sms gateway the sms channel rides). Pinned to the public tag so a
# host consuming THIS module as a git dependency resolves ONE copy of mail
# (tag-equal with the app pin — the composition rule mailing>=v0.2.0 needs
# mail>=v0.2.5; this equals the host's current mail pin). Campaign/utm
# masters and the short-link click seam stay in backbone-engagement and are
# reached through one-way logical uuid refs — no code dep and no DB FK
# crosses a schema boundary.
backbone-mail = { version = "0.3.0" }

# Core async runtime and serialization
tokio = { version = "1.0", features = ["full"] }
async-trait = "0.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
uuid = { version = "1.0", features = ["v4", "serde"] }
chrono = { version = "0.4", features = ["serde"] }
# Money/quantities — near-universal in domain modules. Generated code for any `decimal`
# field imports rust_decimal, so ship it (and the matching sqlx feature) by default.
rust_decimal = { version = "1.36", features = ["serde"] }

# Database (PostgreSQL primary)
sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "postgres", "uuid", "chrono", "json", "migrate", "rust_decimal"] }

# HTTP framework (Axum)
axum = { version = "0.7", features = ["macros"] }
tower = "0.4"
tower-http = { version = "0.5", features = ["cors", "trace"] }

# Logging
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

# Validation
validator = { version = "0.16", features = ["derive"] }

# Deterministic A/B fragment membership (HMAC-SHA256 over the persisted
# sampling seed) and seed minting — the engine's only crypto surface.
hmac = "0.12"
sha2 = "0.10"
rand = "0.8"

# Error handling
anyhow = "1.0"
thiserror = "1.0"

# Configuration
config = "0.14"
serde_yaml = "0.9"

# Protocol Buffers (Generated from Schema-First YAML)
tonic = "0.12"
prost = "0.13"
prost-types = "0.13"

# OpenAPI schema derive. The generator emits `use utoipa::ToSchema;` in every
# entity and DTO behind the `openapi` feature, so the crate only builds with that
# feature on when the derive's crate is present: a feature that cannot compile is
# not a feature.
utoipa = { version = "5", features = ["chrono", "uuid"] }

[features]
default = []
events = []
auth = []
grpc = []
openapi = []
validation = []

[build-dependencies]
tonic-build = "0.12"

[dev-dependencies]
tempfile = "3.0"
tokio-test = "0.4"
mockall = "0.12"
pretty_assertions = "1.0"

# Integration testing framework — the generated tests/integration_tests.rs hits a live server
# via reqwest; guarded-route probes hit the router in-process via tower's ServiceExt::oneshot.
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }
jsonwebtoken = "9.3"

# Test-only: the send engine enqueues through backbone-mail's public services,
# which stage outbox bus events into messaging.outbox_events — a table the
# outbox crate owns and migrates itself (the test harness runs that migration).
backbone-outbox = { version = "3.0.0" }