Merchant Data Enhancement#
Overview#
Merchant data enhancement is the process of enriching ProviderMerchant and FamilyMerchant records with website_url and logo_url fields. The two merchant subtypes use fundamentally different enrichment mechanisms: ProviderMerchant relies on an LLM pipeline triggered as an async job, while FamilyMerchant uses an automatic before_save callback that fires whenever a website URL is set.
ProviderMerchant: LLM-based Enrichment#
Pipeline Entry Point#
Enhancement is triggered via EnhanceProviderMerchantsJob, a medium_priority background job that accepts a family and calls ProviderMerchant::Enhancer.new(family).enhance . A cache key (enhance_provider_merchants:{family.id}) is cleared in an ensure block to prevent duplicate runs .
Enhancer Logic#
ProviderMerchant::Enhancer orchestrates the full pipeline:
- Target selection — fetches all
ProviderMerchantrecords assigned to the family wherewebsite_urlis blank . - LLM call — sends merchants to
Provider::Registry.preferred_llm_providerin batches of 25 viaenhance_provider_merchants(merchants:, family:). BothProvider::AnthropicandProvider::OpenAIimplement this method with provider-specific strategies (tool-use vs. JSON schema). - Update — for each merchant that the LLM returns a
business_urlfor,website_urlis written immediately.logo_urlis also set viabuild_logo_urlifSetting.brand_fetch_client_idis present . - Deduplication — any other
ProviderMerchantassigned to the family that shares the samewebsite_urlis treated as a duplicate: the family's transactions are re-pointed to the winning merchant .FamilyMerchantrecords are explicitly excluded from deduplication .
On-demand Logo Regeneration#
If a ProviderMerchant's website_url is manually corrected after the fact, generate_logo_url_from_website! can be called directly to rebuild the Brandfetch CDN URL. If website_url is blank, the method sets logo_url to nil .
FamilyMerchant: Automatic Callback Enrichment#
FamilyMerchant has no LLM step. Logo enrichment is handled entirely by a before_save callback: generate_logo_url_from_website runs whenever should_generate_logo? returns true — i.e., whenever website_url changes or website_url is present but logo_url is blank .
The callback builds the same Brandfetch CDN URL format as the ProviderMerchant pipeline, gated on Setting.brand_fetch_client_id . If website_url is cleared, logo_url is set to nil .
Because FamilyMerchant has no LLM pipeline, website_url must be supplied by the user (or copied from a ProviderMerchant during conversion). There is no automatic discovery of URLs for family-specific merchants.
Coverage Gap#
| Merchant Type | website_url Source | logo_url Source | Triggered by |
|---|---|---|---|
ProviderMerchant | LLM (EnhanceProviderMerchantsJob) | build_logo_url in Enhancer, or generate_logo_url_from_website! | Async job per family |
FamilyMerchant | User-supplied (or inherited from conversion) | before_save callback | Every save where URL changes |
The practical consequence: ProviderMerchant records created without a website_url will remain logo-less until the enhancement job runs (and until the LLM can identify the business URL). FamilyMerchant records get logos automatically the moment website_url is written, but only if the user provides the URL in the first place.
Domain Extraction#
Both types strip the www. prefix before constructing CDN URLs. ProviderMerchant does this inside Enhancer#extract_domain and the instance method extract_domain on the model . FamilyMerchant has its own identical private extract_domain .
Key Files#
| File | Role |
|---|---|
app/jobs/enhance_provider_merchants_job.rb | Job that kicks off LLM enrichment per family |
app/models/provider_merchant/enhancer.rb | Core LLM pipeline, deduplication, logo building |
app/models/provider_merchant.rb | generate_logo_url_from_website! for on-demand regeneration |
app/models/family_merchant.rb | before_save callback for automatic logo derivation |
See also: Merchant Data Model article (STI structure and relationships), Brandfetch Logo Integration article (CDN URL format and client ID configuration).