Ecto schema for a row in mailglass_suppressions.
Atom Sets (D-07, D-10, D-11)
:scope—:address | :domain | :address_stream. NO default; changesetvalidate_requiredenforces (MAIL-07 prevention).:stream—:transactional | :operational | :bulk(nullable; populated only whenscope = :address_stream).:reason—:hard_bounce | :complaint | :unsubscribe | :manual | :policy | :invalid_recipient.
Coupling invariants (D-07)
scope = :address_streamREQUIRESstream.scope IN (:address, :domain)REJECTSstream.
Enforced both at the changeset layer (validate_scope_stream_coupling/1)
and at the DB layer (mailglass_suppressions_stream_scope_check
CHECK constraint — Plan 02). Belt-and-suspenders: either layer alone
would suffice, but lint-time errors (changeset) are cheaper than
runtime errors (Postgres).
Address normalization
The column is CITEXT, so the DB compares case-insensitively.
Additionally, downcase_address/1 lowercases at cast time — defense
in depth, and makes "did I downcase?" questions moot for reads that
bypass citext (e.g. analytics exports).
Summary
Functions
Closed reason atom set.
Closed scope atom set.
Closed stream atom set.
Builds a changeset for a new %Entry{} from an attr map.
Types
@type t() :: %Mailglass.Suppression.Entry{ __meta__: term(), address: String.t() | nil, expires_at: DateTime.t() | nil, id: Ecto.UUID.t() | nil, inserted_at: DateTime.t() | nil, metadata: map(), reason: atom() | nil, scope: :address | :domain | :address_stream | nil, source: String.t() | nil, stream: :transactional | :operational | :bulk | nil, tenant_id: String.t() | nil }
Functions
@spec __reasons__() :: [atom()]
Closed reason atom set.
@spec __scopes__() :: [atom()]
Closed scope atom set.
@spec __streams__() :: [atom()]
Closed stream atom set.
@spec changeset(map()) :: Ecto.Changeset.t()
Builds a changeset for a new %Entry{} from an attr map.
Enforces three invariants at the Elixir layer:
:scopeis required with no default (MAIL-07 prevention — D-11).- Scope/stream coupling (D-07) via
validate_scope_stream_coupling/1. - Address normalization via
downcase_address/1— belt-and-suspenders with the underlyingCITEXTcolumn.