Ecto schema for the accrue_customers table.
The Customer is the fully-realized polymorphic schema linking a host
app's billable record (User, Organization, Team, etc.) to a processor
customer (e.g. Stripe cus_xxx).
Polymorphic ownership
owner_type and owner_id are explicit string columns (D2-01, D2-02),
lossless across UUID, bigint, ULID, or any future PK format. The composite
unique index (owner_type, owner_id, processor) enforces one customer per
billable per processor.
Metadata
The metadata field follows the exact Stripe metadata contract (D2-07):
flat %{String.t() => String.t()}, max 50 keys, keys max 40 chars,
values max 500 chars, no nested maps. See Accrue.Billing.Metadata.
Optimistic locking
All writes use Ecto.Changeset.optimistic_lock/2 on lock_version
to prevent torn writes when a user update and webhook reconcile race
on the same customer (D2-09).
Phase 3 additions
default_payment_method_id— FK to accrue_payment_methods withON DELETE SET NULL. Set viaset_default_payment_method/2(Plan 06), which asserts attachment before updating.last_stripe_event_ts/last_stripe_event_id— webhook watermark
Summary
Functions
Builds a changeset for creating or updating a Customer.
Types
@type t() :: %Accrue.Billing.Customer{ __meta__: term(), charges: term(), data: term(), default_payment_method: term(), default_payment_method_id: term(), email: term(), id: term(), inserted_at: term(), invoices: term(), last_stripe_event_id: term(), last_stripe_event_ts: term(), lock_version: term(), metadata: term(), name: term(), owner_id: term(), owner_type: term(), payment_methods: term(), preferred_locale: term(), preferred_timezone: term(), processor: term(), processor_id: term(), subscriptions: term(), updated_at: term() }
Functions
@spec changeset( %Accrue.Billing.Customer{ __meta__: term(), charges: term(), data: term(), default_payment_method: term(), default_payment_method_id: term(), email: term(), id: term(), inserted_at: term(), invoices: term(), last_stripe_event_id: term(), last_stripe_event_ts: term(), lock_version: term(), metadata: term(), name: term(), owner_id: term(), owner_type: term(), payment_methods: term(), preferred_locale: term(), preferred_timezone: term(), processor: term(), processor_id: term(), subscriptions: term(), updated_at: term() } | Ecto.Changeset.t(), map() ) :: Ecto.Changeset.t()
Builds a changeset for creating or updating a Customer.
Validates required fields, enforces Stripe-compatible metadata constraints, and applies optimistic locking.