feat(contact): optimize contact import and pagination performance#40
Merged
DavidsonGomes merged 2 commits intoMay 5, 2026
Conversation
- Add support for person/company type differentiation - Add processing for social profiles (linkedin, facebook, instagram, twitter, github) - Add location attributes (city, country, country_code) - Add custom attributes auto-mapping for unknown fields - Add empresas_vinculadas field for linking persons to companies - Import companies first, then persons, then process linkages - Updated CSV sample with all 19 supported fields
Reviewer's GuideRefactors the contact CSV import pipeline to classify and import companies and persons separately with richer field mapping and logging, introduces tax ID sanitization and improved phone formatting in ContactManager, adds database indexes and a LEFT JOIN-based scope to speed up resolved contacts listing, caches contact count in the contacts API, and introduces roles/user_roles models to identify admin users via evo-auth roles for admin mailers, along with Docker entrypoint and schema/migration adjustments. Sequence diagram for the optimized contact CSV import processsequenceDiagram
actor Admin
participant DataImportJob
participant ContactManager
participant Contact
participant Mailer as AdministratorNotifications_AccountNotificationMailer
Admin->>DataImportJob: enqueue(data_import)
DataImportJob->>DataImportJob: perform(data_import)
DataImportJob->>DataImportJob: process_import_file
DataImportJob->>DataImportJob: parse_csv_and_classify_contacts
loop each CSV row
DataImportJob->>ContactManager: build_contact(params)
ContactManager-->>DataImportJob: contact
alt tipo == company
DataImportJob->>DataImportJob: classify as company_rows
else tipo == person
DataImportJob->>DataImportJob: classify as person_rows
end
end
DataImportJob->>DataImportJob: import_companies(company_rows)
DataImportJob->>Contact: import(companies)
Contact-->>DataImportJob: import_result_companies
DataImportJob->>DataImportJob: import_persons(person_rows)
DataImportJob->>Contact: import(persons)
Contact-->>DataImportJob: import_result_persons
DataImportJob->>DataImportJob: process_company_linkages(person_rows)
loop each person with empresas_vinculadas
DataImportJob->>Contact: companies.find_by(name, type company)
alt company exists
DataImportJob->>Contact: contact.add_company(company)
else company missing
DataImportJob->>Contact: create!(type company, name)
Contact-->>DataImportJob: new_company
DataImportJob->>Contact: contact.add_company(new_company)
end
end
DataImportJob->>DataImportJob: update_data_import_status
DataImportJob->>DataImportJob: save_failed_records_csv
alt success
DataImportJob->>Mailer: contact_import_complete(data_import)
Mailer-->>Admin: completion email
else CSV::MalformedCSVError
DataImportJob->>DataImportJob: handle_csv_error
DataImportJob->>Mailer: contact_import_failed
Mailer-->>Admin: failure email
end
Entity relationship diagram for users, roles, and user_roleserDiagram
users {
uuid id
varchar email
}
roles {
uuid id
varchar key
varchar name
}
user_roles {
uuid id
uuid user_id
uuid role_id
uuid granted_by_id
}
users ||--o{ user_roles : has_many
roles ||--o{ user_roles : has_many
users ||--o{ user_roles : grants
Class diagram for ContactManager and contact import mappingclassDiagram
class DataImport_ContactManager {
+find_or_initialize_contact(params)
+find_existing_contact(params)
+build_contact(params)
+find_contact_by_identifier(params)
+find_contact_by_email(params)
+find_contact_by_phone_number(params)
+find_contact_by_tax_id(params)
+format_phone_number(phone_number)
+sanitize_tax_id(tax_id)
+update_contact_with_merged_attributes(params, contact)
-update_contact_attributes(params, contact)
-build_name(params)
-process_location_attributes(params, contact)
-process_social_attributes(params, contact)
-process_description(params, contact)
-process_custom_attributes(params, contact)
}
class Contact {
+String name
+String last_name
+String email
+String phone_number
+String tax_id
+String type
+String website
+String industry
+String country_code
+Hash additional_attributes
+Hash custom_attributes
+add_company(company)
+self.import(records)
+self.companies()
+self.resolved_contacts()
}
DataImport_ContactManager ..> Contact : builds_and_updates
class DataImportJob {
+perform(data_import)
-process_import_file()
-parse_csv_and_classify_contacts()
-append_rejected_contact(row, contact, rejected_contacts)
-import_contacts(contacts)
-import_companies(company_rows)
-import_persons(person_rows)
-process_company_linkages(person_rows)
-update_data_import_status(processed_records, rejected_records)
-save_failed_records_csv(rejected_contacts)
-handle_csv_error(error)
-send_import_notification_to_admin()
-send_import_failed_notification_to_admin()
}
DataImportJob ..> DataImport_ContactManager : uses
DataImportJob ..> Contact : imports
Class diagram for User, Role, and UserRole relationshipsclassDiagram
class User {
+UUID id
+String email
+has_many user_roles
+has_many roles
}
class Role {
+UUID id
+String key
+String name
+has_many user_roles
+has_many users
+administrator?()
+self.administrator_role()
+self.administrator_users()
}
class UserRole {
+UUID id
+UUID user_id
+UUID role_id
+UUID granted_by_id
+belongs_to user
+belongs_to role
+belongs_to granted_by
}
User "1" -- "*" UserRole : has_many
Role "1" -- "*" UserRole : has_many
UserRole "*" -- "1" User : user
UserRole "*" -- "1" Role : role
UserRole "*" -- "0..1" User : granted_by
class AdministratorNotifications_BaseMailer {
-admin_emails()
-settings_url(section)
}
AdministratorNotifications_BaseMailer ..> User : queries
AdministratorNotifications_BaseMailer ..> Role : filters_by_role_key
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
3 tasks
🎯 Objetivo
Otimizar o processo de importação de contatos e melhorar a performance da listagem de contatos com mais de 1000 registros.
✅ Alterações Realizadas
1. Sanitização de CPF/CNPJ na Importação
sanitize_tax_idnoContactManagerfind_contact_by_tax_ideupdate_contact_attributes2. Otimização de Performance
contact_inboxese contatosresolved_contactsotimizada comLEFT JOIN3. Correções
format_phone_numberpara manter prefixo+🧪 Testes
tax_idé armazenado apenas com númerosSummary by Sourcery
Optimize contact import, enrichment, and listing performance while integrating role-based admin notifications.
New Features:
Bug Fixes:
Enhancements:
Build: