defmodule Mv.Accounts.User.Changes.SyncEmailToMember do @moduledoc """ Synchronizes user email changes to the linked member. When a user's email is updated and the user is linked to a member, this change automatically updates the member's email to match. This ensures bidirectional email synchronization with User.email as the source of truth. Uses `around_transaction` to guarantee atomicity - both the user and member updates happen in the SAME database transaction. """ use Ash.Resource.Change alias Mv.EmailSync.Helpers @impl true def change(changeset, _opts, context) do cond do # Skip if already syncing to avoid recursion Map.get(context, :syncing_email, false) -> changeset # Only proceed if email is actually changing not Ash.Changeset.changing_attribute?(changeset, :email) -> changeset # Apply the sync logic true -> new_email = Ash.Changeset.get_attribute(changeset, :email) # around_transaction receives the changeset (cs) from Ash # and a callback that executes the actual database operation Ash.Changeset.around_transaction(changeset, fn cs, callback -> result = callback.(cs) with {:ok, user} <- Helpers.extract_record(result), linked_member <- get_linked_member(user) do Helpers.sync_email_to_linked_record(result, linked_member, new_email) else _ -> result end end) end end defp get_linked_member(%{member_id: nil}), do: nil defp get_linked_member(%{member_id: member_id}) do case Ash.get(Mv.Membership.Member, member_id) do {:ok, member} -> member {:error, _} -> nil end end end