Customer Data Import & Mapping to Existing Users
Overview
Unlike the import that creates new users, this job enriches users who already exist. The customer uploads a CSV containing columns such as phone number, email, purchase total, or membership tier, then maps each column onto a line_user field or a custom attribute. Rows are matched to users by a unique key — typically a phone number or a LINE User ID.
This queue is new to the Go implementation and has no counterpart in the legacy NestJS system. Its distinguishing features are per-cell validation and a downloadable error log that tells the user exactly which rows failed and why.
Business Flow
- Receive a payload carrying
importMappingJobId. If it is missing or not greater than zero, the handler returnsmq.Permanentso the message goes straight to the DLQ without retrying. - Load the
import_mapping_jobrow, joiningline_oato obtainline_oa_hashfor the error-log upload path. - Read the CSV from S3 and parse the header row to locate each column.
buildLookupbuilds a map from unique-key value toline_user.id. Two key forms are supported: direct field references such asfield.mobile_no,field.email, oruser_id, and custom attribute references.- Iterate row by row through
processRow, working in chunks of 500 and reporting progress as it goes.- Resolve the
line_userfrom the lookup; unmatched rows are skipped with a recorded reason. - Validate the value against the column type:
field.emailmust match^[^\s@]+@[^\s@]+\.[^\s@]+$, andfield.mobile_no, once spaces and dashes are stripped, must be 9 to 10 digits. - Write the value directly to its column, or merge it into the
line_user.custom_attributejsonb column.
- Resolve the
uploadErrorLogruns whenever rows were skipped: it builds a CSV of the failures with their reasons and uploads it to S3 atprivate/<lineOaHash>/import-mapping/error_<jobId>.csv.finalizeJobwrites the final status, the statistics (Stats), the skip reasons ranked by frequency viasortedReasons, and the error-log path back to the job row.- Because the service finalises the job itself, it only returns an error in cases where a retry still has a realistic chance of succeeding.
Key Files & Functions
internal/importmapping/service.goService.ProcessImportMappingJob(ctx, payload)— entry pointrun(),processRow(),buildLookup(),parseTarget(),validateFieldValue(),normalizeIdentifier(),stripPhone()uploadErrorLog(),finalizeJob(),findJobByID(),sortedReasons()- Key constants:
chunkSizeis 500,folderImportMappingErrorisimport-mapping, plusemailPatternandphonePattern
internal/importmapping/consumer.go—Consumer.HandleImportMappingJobandRegister()internal/importmapping/types.go— definesImportMappingJobPayload,Stats,ReasonCount, andskippedRow- Queue:
import_mapping_job(runtime profilemain)
Connections to Other Services
- Job source — cms-api-go, from the CMS import-mapping screen.
- Database —
import_mapping_job(status, statistics, error-log path),line_user(UPDATE of both direct columns and thecustom_attributejsonb), andline_oa(hash used to build the S3 path). - S3 — reads the source CSV and writes the error log.
- No LINE API calls — the job only touches users who are already known to the system.
- Shares the
Storageinterface with the CSV user-list import, through thelineUserStorageadapter incmd/worker/integration.go.