CRM · Customer CSV import
Bulk customer create/update from a CSV: the operator uploads the file, maps each CSV column to one of ~40 user attributes, picks the match key (id / email / VAT number), separator, date format, consent defaults and channels, then runs the import.
| Area | CRM |
| Routes | crm.users.import |
| Centre modules | crm |
| Staff levels | root · admin |
| Models | campaign · channel · load · user · user-account-type |
| UI label | import-csv.column-database |
| Coverage | 3 use cases · 1 happy · 7 failure |
How it works
The mapping table auto-matches CSV headers whose text equals an attribute value, so a template-shaped file needs no manual mapping. modelExample serves a different downloadable template when the centre has employee segments (baseContentCreatorCSV(userTypeCodes) instead of baseCSV). Validation lives on the load model: no duplicate column mappings, a date format when register_date/bdate are mapped, and at least one channel when importing users. nf-import adds a pre-flight (_validateSelectionsAndShowErrors) that collects the same issues into a summary banner before the model validation runs, and update: true controls insert-only vs update-and-insert.
Use cases
Why someone opens this (3)
- Onboarding a centre by loading its historical customer database.
- Periodic sync from a POS or legacy CRM keyed on email or VAT number.
- Bulk-assigning user tags or account types to an existing population.
Path map
flowchart LR F(["Customer CSV import"]):::feat F --> H1["Template-shaped import"]:::ok F -.-> X1["Same attribute mapped twice"]:::bad F -.-> X2["Date columns without a format"]:::bad F -.-> X3["No channel selected"]:::bad F -.-> X4["Required selections incomplete"]:::bad F -.-> X5["Server-side row errors"]:::bad F -.-> X6["Malformed CSV / wrong separator"]:::bad F -.-> X7["Upload rejected"]:::bad classDef feat fill:#157068,stroke:#157068,color:#ffffff,font-weight:bold classDef ok fill:#e3f1ea,stroke:#0d6b42,color:#0d4a2e classDef bad fill:#f7e6e2,stroke:#9a2d1c,color:#6e1f13
Happy paths
Template-shaped import
- Operator downloads the example CSV, fills it and uploads it.
- The file is parsed (
csv.parseCSV,;delimiter) and simultaneously uploaded to storage (apiFiles.uploadFile).- Columns auto-map; operator picks the match key, date format and channels.
load.validate()passes,load.save()queues the job and the success state is reported.
Failure paths
Same attribute mapped twice
Cause — Two CSV columns point at one database field.
What happens —
csvFieldscustom validation fails witherror.load.repeated-fields; the modal scrolls to the top to show it.
Date columns without a format
Cause —
register_dateorbdatemapped but no date format chosen.What happens —
error.load.format-date.required/import-csv.errors.load.format-date.required.
No channel selected
Cause — Importing users without
commons.channels.What happens —
error.load.channels.required/import-csv.errors.load.channels.required.
Required selections incomplete
Cause — Pre-flight finds any of the above.
What happens —
import-csv.errors.load.required-selectionsis shown as the banner — note this key’s value is in Portuguese while the rest of the file is English, a localisation inconsistency.
Server-side row errors
Cause — Rows rejected during processing.
What happens —
informative-message.import-csv.error.title+informative-message.import-csv.errorlist the errors returned by the API.
Malformed CSV / wrong separator
Cause — File does not parse into a header row.
What happens —
parseCSVthrows inside anasyncaction;nf-importwraps its import in try/catch and readserror.errors[0].status, but a parse failure inimport-csv.jsis unguarded and leavesisLoadingtrue.
Upload rejected
Cause — File type or size refused by storage.
What happens —
error.file.type.not_allowed,error.file.oversize,error.file.not_allowed.
QA checklist
Tick these off while regression-testing this feature. The boxes are plain Markdown, so progress is visible in git diffs.
- ✅ Template-shaped import
- ⛔ Same attribute mapped twice
- ⛔ Date columns without a format
- ⛔ No channel selected
- ⛔ Required selections incomplete
- ⛔ Server-side row errors
- ⛔ Malformed CSV / wrong separator
- ⛔ Upload rejected
Implementation
app/controllers/crm/users/import.jsapp/routes/crm/users/import.jsapp/components/nf-import.jsapp/components/import-csv.jsapp/models/load.jsapp/enums/csv-examples.js
Translation keys (9)
Key English import-csv.column-csvCSV Field import-csv.column-databaseDatabase field error.load.repeated-fieldsThere are fields have been selected more than once. Please select a single database field for each CSV column. error.load.format-date.requiredFormat date is required error.load.channels.requiredChannels are required import-csv.errors.load.required-selectionsAtenção! Faltam campos obrigatórios. Revise-os antes de importar. informative-message.import-csv.errorThe following errors have occurred import-csv.update-options.only-insertOnly insert new data without updating existing data import-csv.update-options.update-insertUpdate existing data and insert new data
Related
- Same area — Customer list & filtering · Customer create & edit · Customer deletion with unsubscribe notice · Customer CSV export with column picker · Children CSV import · AI natural-language customer filter · Save current filters as a segment · Segment list, refresh & export · Segment builder with automatic tag actions · Segment categories · User tags (user types) · Customer receipts tab & ticket-stamp generation · Customer loyalty — raffle tickets · Customer loyalty — cards & stamps · Customer loyalty — rewards · Customer loyalty — coupon exchanges · Customer children (dependants) · Receipt verification queue · Store list, filters & exports · Store create & edit · Store CSV import · Store labels (store types) · Customer action log (dormant)
- Shares data with — Staff member editor (levels, scope, API token) · Activity list & duplication · Activity editor (loyalty mechanics, rules & targeting) · Activity report & PDF · Activity campaigns (programme grouping) · Proposal editor (content, coupon, push, AI images) · Push notification editor (scheduling, geofencing, deep links) · App button manager (MOFs)
Generated from doc/feature-inventory.json · id crm-customer-import · commit 276788ca6