Claude Code cho độ chính xác nhập/xuất dữ liệu: định nghĩa quy tắc xác thực, định dạng lỗi nhất quán và fuzz test cho import CSV/JSON để giảm ticket các trường hợp biên.

Việc nhập dữ liệu hiếm khi thất bại vì mã "sai". Chúng thất bại vì dữ liệu đời thực lộn xộn, không nhất quán, và do những người chưa từng thấy các giả định của bạn tạo ra.
Vấn đề với CSV thường là về hình dạng và định dạng. Vấn đề với JSON thường là về ý nghĩa và kiểu. Cả hai đều có thể vỡ theo những cách trông nhỏ nhưng tạo ra kết quả khó hiểu.
Những vấn đề này lặp lại trong các ticket hỗ trợ:
Độ đúng không chỉ là “có nhập được không”. Bạn phải quyết định những kết quả nào được chấp nhận, vì người dùng dễ nhận ra lỗi im lặng hơn là lỗi lớn.
Hầu hết đội ngũ có thể đồng ý về ba kết quả:
Các trường hợp biên trở thành công việc lặp lại khi người ta không thể biết chuyện gì đã sai hoặc cách sửa nhanh. Một kịch bản phổ biến: khách hàng tải lên CSV 5.000 dòng, importer báo “Invalid format”, và họ thử lại ba lần với chỉnh sửa ngẫu nhiên. Điều đó trở thành nhiều ticket cộng thêm người của bạn cố gắng tái tạo file cục bộ.
Đặt mục tiêu giảm chu trình đó: ít thử lại hơn, sửa lỗi nhanh hơn, kết quả có thể dự đoán. Trước khi viết quy tắc, quyết định "partial" có nghĩa là gì (và liệu bạn có cho phép nó), cách bạn báo lỗi ở cấp hàng, và người dùng nên làm gì tiếp theo (chỉnh sửa file, map trường, hay xuất phiên bản đã sửa). Nếu bạn dùng một nền tảng kiểu vibe-coding như Koder.ai (koder.ai) để sinh validator và test nhanh, hợp đồng nhập liệu vẫn là thứ giữ hành vi đó nhất quán khi sản phẩm phát triển.
Trước khi viết một quy tắc xác thực nào, quyết định "đầu vào hợp lệ" nghĩa là gì cho sản phẩm của bạn. Hầu hết lỗi nhập phát sinh từ kỳ vọng không khớp giữa file người dùng upload và giả định mà hệ thống bạn âm thầm dùng.
Bắt đầu với format, và nói rõ. “CSV” có thể nghĩa là comma hoặc semicolon, có header hay không, UTF-8 hay “mọi thứ Excel xuất ra”. Với JSON, quyết định bạn chấp nhận một object đơn, một mảng bản ghi, hay JSON Lines (một object JSON mỗi dòng). Nếu chấp nhận JSON lồng nhau, định nghĩa rõ đường dẫn nào bạn đọc và đường dẫn nào bạn bỏ qua.
Sau đó khoá hợp đồng trường. Với mọi trường, quyết định nó là bắt buộc, tùy chọn, hay tùy chọn kèm mặc định. Mặc định là một phần của hợp đồng, không phải chi tiết triển khai. Nếu country thiếu, bạn mặc định là rỗng, chọn một quốc gia cụ thể, hay từ chối hàng?
Hành vi parsing là nơi các importer "khoan dung" tạo ra đau đầu lâu dài. Quyết định trước mức độ nghiêm ngặt về việc trim khoảng trắng, chuẩn hoá chữ hoa/thường, và chấp nhận các biến thể như "yes"/"true"/"1". Khoan dung là được nếu nó có thể dự đoán và được ghi chép.
Trùng lặp là một quyết định hợp đồng khác ảnh hưởng tới độ đúng và niềm tin. Định nghĩa gì được tính là trùng lặp (cùng email, same external_id, hay tổ hợp trường), nơi bạn phát hiện (trong file, đối chiếu với dữ liệu hiện có, hay cả hai), và bạn làm gì khi gặp (giữ bản đầu, giữ bản sau, gộp, hoặc từ chối).
Danh sách kiểm tra hợp đồng bạn có thể dán vào spec:
Ví dụ: nhập "customers." Nếu email là khoá duy nhất, quyết định " [email protected] " có bằng "[email protected]" không, nếu email thiếu có được chấp nhận khi external_id tồn tại không, và trùng lặp bên trong file có bị từ chối ngay cả khi DB chưa có khớp hay không. Khi hợp đồng này cố định, hành vi nhất quán giữa UI và API dễ thực hiện hơn, dù bạn triển khai bằng Koder.ai hay công cụ khác.
Các nhập messy thường bắt đầu bằng một hàm validate() khổng lồ. Cách tiếp cận sạch hơn là các lớp quy tắc với tên rõ ràng và hàm nhỏ. Điều đó làm cho thay đổi dễ review hơn và tests dễ viết hơn.
Bắt đầu với quy tắc ở mức trường: kiểm tra một giá trị riêng lẻ có thể pass hoặc fail độc lập (kiểu, phạm vi, độ dài, giá trị cho phép, regex). Giữ chúng nhàm và có thể dự đoán. Ví dụ: email khớp một pattern email cơ bản, age là integer giữa 0 và 120, status là một trong active|paused|deleted.
Thêm quy tắc chéo trường chỉ nơi thực sự cần. Những kiểm tra này phụ thuộc vào nhiều trường, và lỗi thường ẩn ở đây. Ví dụ kinh điển: startDate phải trước endDate, hoặc total = subtotal + tax - discount. Viết những quy tắc này để chúng có thể chỉ tới trường cụ thể, không chỉ “record invalid”.
Tách quy tắc ở cấp bản ghi và cấp file. Quy tắc bản ghi kiểm tra một hàng (CSV) hoặc một object (JSON). Quy tắc file kiểm tra toàn bộ upload: header bắt buộc tồn tại, khoá duy nhất không lặp trong các hàng, số cột khớp mong đợi, hoặc file khai báo phiên bản được hỗ trợ.
Chuẩn hóa nên rõ ràng, không "ma thuật". Quyết định bạn chuẩn hóa gì trước khi xác thực, và ghi chép lại. Ví dụ phổ biến: trim khoảng trắng, chuẩn hóa Unicode (để ký tự trông giống nhau so sánh bằng nhau), và định dạng số điện thoại về một dạng lưu trữ nhất quán.
Một cấu trúc dễ đọc:
Version hóa quy tắc của bạn. Đặt một schemaVersion (hoặc profile import) trong file hoặc request API. Khi bạn thay đổi ý nghĩa của “valid”, vẫn có thể re-import các export cũ theo phiên bản cũ. Chỉ một lựa chọn này ngăn được rất nhiều ticket kiểu “hôm qua vẫn chạy được".
Một importer tốt thất bại theo cách hữu ích. Lỗi mơ hồ dẫn tới thử lại ngẫu nhiên và công việc hỗ trợ tránh được. Một định dạng lỗi rõ ràng giúp người dùng sửa file nhanh, và giúp bạn cải thiện xác thực mà không phá vỡ client.
Bắt đầu với một hình dạng đối tượng lỗi ổn định và giữ nó nhất quán giữa CSV và JSON. Bạn có thể dùng Claude Code để đề xuất schema và vài ví dụ thực tế, rồi khoá nó làm một phần của hợp đồng nhập.
Xử lý mỗi lỗi như một bản ghi nhỏ với các trường không thay đổi. Message có thể thay đổi, nhưng code và location nên giữ ổn định.
code: một identifier ngắn, ổn định như REQUIRED_MISSING hoặc INVALID_DATEmessage: một câu thân thiện cho UIpath: nơi vấn đề (JSON pointer như /customer/email, hoặc tên cột như email)row hoặc line: với CSV, bao gồm số hàng 1-based (và tuỳ chọn dòng gốc)severity: ít nhất error và warningLàm cho lỗi có thể hành động. Bao gồm điều bạn mong đợi và điều bạn thực sự thấy, và khi có thể thì cho ví dụ thỏa. Ví dụ: mong YYYY-MM-DD, nhưng thấy 03/12/24.
Ngay cả khi bạn trả một danh sách phẳng, bao gồm đủ dữ liệu để gom nhóm theo hàng và theo trường. Nhiều UI muốn “Hàng 12 có 3 lỗi” rồi highlight từng cột. Đội support thích gom nhóm vì các mẫu lỗi hiện ra rõ (ví dụ tất cả hàng thiếu country).
Một phản hồi gọn có thể trông như sau:
{
"importId": "imp_123",
"status": "failed",
"errors": [
{
"code": "INVALID_DATE",
"message": "Signup date must be in YYYY-MM-DD.",
"path": "signup_date",
"row": 12,
"severity": "error",
"expected": "YYYY-MM-DD",
"actual": "03/12/24"
},
{
"code": "UNKNOWN_FIELD",
"message": "Column 'fav_colour' is not recognized.",
"path": "fav_colour",
"row": 1,
"severity": "warning"
}
]
}
Lên kế hoạch cho localization mà không đổi mã lỗi. Giữ code trung lập về ngôn ngữ và bền vững, và coi message như văn bản có thể thay thế. Nếu sau này bạn thêm messageKey hoặc các thông điệp dịch, client cũ vẫn có thể dựa vào cùng mã để lọc, gom nhóm, và phân tích.
Để tránh các “mystery imports,” phản hồi API của bạn nên trả lời hai câu: chuyện gì đã xảy ra, và người dùng nên làm gì tiếp theo.
Ngay cả khi có lỗi, trả về một tóm tắt nhất quán để UI và công cụ hỗ trợ xử lý mọi import theo cùng cách.
Bao gồm:
created, updated, skipped, failed countstotalRows (hoặc totalRecords cho JSON)mode (ví dụ: "createOnly", "upsert", hoặc "updateOnly")startedAt và finishedAt timestampscorrelationId để support có thể hỏicorrelationId rất đáng có. Khi ai đó báo “nó không được nhập”, bạn có thể tìm đúng lần chạy và báo cáo lỗi mà không đoán mò.
Đừng đẩy 10.000 lỗi hàng vào phản hồi. Trả một mẫu nhỏ (ví dụ 20) cho thấy mẫu lỗi, và cung cấp cách riêng để truy xuất báo cáo đầy đủ nếu cần.
Làm cho mỗi lỗi cụ thể và ổn định:
Ví dụ hình dạng phản hồi (thành công với một số hàng lỗi):
{
"importId": "imp_01HZY...",
"correlationId": "c_9f1f2c2a",
"status": "completed_with_errors",
"summary": {
"totalRows": 1200,
"created": 950,
"updated": 200,
"skipped": 10,
"failed": 40
},
"errorsSample": [
{
"row": 17,
"field": "email",
"code": "invalid_format",
"message": "Email must contain '@'.",
"value": "maria.example.com"
}
],
"report": {
"hasMore": true,
"nextPageToken": "p_002"
},
"next": {
"suggestedAction": "review_errors"
}
}
Ghi chú trường next. Ngay cả payload thành công tối thiểu cũng nên giúp sản phẩm tiến lên: hiện màn review, đề nghị retry, hoặc mở collection đã nhập.
Người ta retry. Mạng lỗi. Nếu cùng file được import hai lần, bạn muốn kết quả có thể dự đoán.
Hãy rõ ràng về idempotency: chấp nhận idempotencyKey (hoặc tính hash file), và trả importId hiện có nếu request là trùng lặp. Nếu chế độ là upsert, định nghĩa quy tắc khớp (ví dụ, “email là khóa duy nhất”). Nếu là create-only, trả “skipped” cho trùng lặp, không phải “created again”.
Nếu toàn bộ request không hợp lệ (auth sai, content type sai, file không đọc được), fail nhanh và trả status: "rejected" với danh sách lỗi ngắn. Nếu file hợp lệ nhưng có vấn đề ở cấp hàng, coi đó là job hoàn thành với failed > 0 để người dùng có thể sửa và upload lại mà không mất summary.
Thói quen hữu ích: bắt model viết hợp đồng ở định dạng có cấu trúc, không chỉ văn mô tả. “Các đoạn văn hữu ích” thường bỏ qua chi tiết như quy tắc trim, giá trị mặc định, và liệu ô trống nghĩa là “missing” hay “empty”.
Dùng prompt buộc xuất một bảng mà con người có thể rà nhanh và dev có thể chuyển thành code. Yêu cầu mỗi trường có quy tắc, ví dụ pass/fail, và ghi chú rõ cho những chỗ mập mờ (ví dụ empty string vs null).
You are helping design an importer for CSV and JSON.
Output a Markdown table with columns:
Field | Type | Required? | Normalization | Validation rules | Default | Pass examples | Fail examples
Rules must be testable (no vague wording).
Then output:
1) A list of edge cases to test (CSV + JSON).
2) Proposed test names with expected result (pass/fail + error code).
Finally, list any contradictions you notice (required vs default, min/max vs examples).
Sau bản thảo đầu, thắt chặt bằng cách yêu cầu một ví dụ dương và một ví dụ âm cho mỗi quy tắc. Điều đó thúc ép phủ các góc khó như chuỗi rỗng, giá trị chỉ có whitespace, cột thiếu, null vs "null", số nguyên rất lớn, ký hiệu khoa học, ID trùng, và field JSON thừa.
Với kịch bản cụ thể: nhập “customers” từ CSV: email là bắt buộc, phone tùy chọn, signup_date mặc định là ngày hôm nay nếu thiếu. Model nên báo mâu thuẫn nếu bạn đồng thời nói “signup_date là bắt buộc”. Nó nên đề xuất tests như import_customers_missing_email_returns_row_error và chỉ rõ mã lỗi và hình dạng message bạn trả.
Làm thêm một lượt trước khi implement: yêu cầu model tóm tắt lại các quy tắc dưới dạng checklist và chỉ ra nơi defaults, required, và normalization có thể xung đột. Bước review đó bắt nhiều hành vi gây ticket.
Fuzz testing ngăn các “file kỳ quặc” trở thành ticket. Bắt đầu từ vài file CSV/JSON tốt, rồi sinh hàng nghìn biến thể lỗi nhỏ và đảm bảo importer xử lý an toàn và rõ ràng.
Bắt đầu với tập seed nhỏ gồm các ví dụ hợp lệ đại diện cho sử dụng thực tế: file hợp lệ nhỏ nhất, file điển hình, và file lớn. Với JSON, bao gồm một object, nhiều object, và cấu trúc lồng nếu bạn hỗ trợ.
Sau đó thêm một mutator tự động chỉnh một thứ mỗi lần. Giữ đột biến có thể tái tạo bằng cách log seed random để bạn replay khi tìm lỗi.
Chiều đột biến bắt được nhiều vấn đề đời thực:
Đừng chỉ dừng ở cú pháp. Thêm fuzz ngữ nghĩa: hoán đổi các trường tương tự (email vs username), ngày cực đoan, ID trùng, số âm, hoặc giá trị vi phạm enum.
Fuzz chỉ hữu ích nếu tiêu chí pass nghiêm ngặt. Importer không bao giờ được crash hoặc treo, và lỗi phải nhất quán và có thể hành động.
Tập tiêu chí pass thực tế:
Chạy các test này trong CI cho mọi thay đổi. Khi tìm thấy lỗi, lưu chính xác file đó làm fixture và thêm test hồi quy để nó không quay lại.
Nếu bạn dùng Claude Code để hỗ trợ, hãy để nó sinh fixture seed khớp hợp đồng, kế hoạch đột biến, và kết quả lỗi mong đợi. Bạn vẫn chọn quy tắc, nhưng nhận được bề mặt test rộng nhanh, đặc biệt cho quoting CSV và góc JSON.
Phần lớn ticket nhập tới từ quy tắc không rõ ràng và phản hồi không hữu ích.
Một bẫy phổ biến là parsing "best effort" không được ghi chép. Nếu importer âm thầm trim, chấp nhận cả comma và semicolon, hoặc dự đoán format ngày, người dùng xây quy trình dựa trên đoán đó. Rồi một thay đổi nhỏ, hoặc một công cụ xuất khác, phá vỡ mọi thứ. Chọn hành vi, ghi chép nó, và test.
Một kẻ phạm lỗi khác là thông báo lỗi chung chung. “Invalid CSV” hoặc “Bad request” buộc người dùng đoán. Họ upload cùng file năm lần, và support phải yêu cầu file. Lỗi nên chỉ tới hàng, trường, lý do rõ ràng, và mã lỗi ổn định.
Fail toàn bộ file vì một hàng xấu cũng là điểm gây khó chịu. Đôi khi điều đó đúng (ví dụ nhập tài chính nơi partial dữ liệu nguy hiểm). Nhiều trường hợp kinh doanh có thể tiếp tục và báo tóm tắt, miễn là bạn cung cấp tuỳ chọn rõ ràng như strict mode vs partial import.
Vấn đề encoding văn bản tạo ticket dai dẳng. UTF-8 là mặc định đúng, nhưng CSV thực tế thường có BOM, dấu ngoặc cong, hoặc khoảng trắng không phá vỡ từ copy từ spreadsheet. Xử lý nhất quán và báo bạn đã phát hiện gì để người dùng biết chỉnh setting export.
Cuối cùng, thay đổi mã lỗi giữa các release phá vỡ client và automation. Cải thiện wording thì được, nhưng giữ code và ý nghĩa ổn định. Chỉ version chúng khi thật cần.
Các bẫy đáng phòng trước:
Ví dụ: khách hàng xuất CSV từ Excel, Excel thêm BOM và format ngày là 03/04/2026. Importer của bạn đoán MM/DD, nhưng khách hàng mong DD/MM. Nếu báo lỗi của bạn bao gồm format được phát hiện, trường chính xác và gợi ý sửa, người dùng có thể sửa mà không trao đổi nhiều.
Hầu hết lỗi nhập là sự không khớp nhỏ giữa ý người dùng về file và điều hệ thống chấp nhận. Xem đây như một ngưỡng phát hành.
null rõ ràng, và text rỗng.Một test thực tế: dùng một file cố tình lộn xộn. Ví dụ: header xuất hiện hai lần (hai cột “email”), một field boolean dùng “Y”, và một ngày là “03/04/05”. Importer của bạn không nên đoán. Nó nên áp dụng mapping đã ghi chép hoặc từ chối với lỗi cụ thể.
Hai kiểm tra đội hay bỏ sót:
Đầu tiên, xác minh importer báo lỗi với chi tiết vị trí đủ để sửa file nguồn. “Invalid date” không hành động. “Hàng 42, cột start_date: mong YYYY-MM-DD, nhận 03/04/05” thì có.
Thứ hai, chạy cùng file lỗi hai lần và so sánh kết quả. Nếu thứ tự lỗi thay đổi, mã lỗi đổi, hoặc số hàng chệch, người dùng mất tin tưởng. Hành vi xác định là nhàm chán, và đó là mục tiêu.
Một import thực tế thường gặp là đơn hàng khách hàng từ export spreadsheet. Ai đó xuất CSV từ hệ thống cũ, sửa nó trong Excel, rồi upload. Phần lớn ticket xảy ra khi importer âm thầm “sửa” dữ liệu, hoặc khi thông báo lỗi không nói phải thay đổi gì.
Giả sử file orders.csv với các cột: order_id,customer_email,order_date,currency,total_amount.
Dưới đây là ba dòng xấu thực tế (như người dùng sẽ thấy):
order_id,customer_email,order_date,currency,total_amount
A-1001,[email protected],2026-01-05,USD,129.99
A-1002,not-an-email,01/06/2026,USD,49.00
,[email protected],2026-01-07,US, -10
Dòng 2 có email không hợp lệ và ngày mơ hồ. Dòng 3 thiếu order_id, có mã tiền tệ không hỗ trợ (US thay vì USD), và amount âm.
Nếu API trả lỗi, giữ hình dạng nhất quán và cụ thể. Ví dụ phản hồi hỗ trợ partial success:
{
"correlation_id": "imp_20260109_7f3a9d",
"import_id": "ord_01HZZ...",
"status": "partial_success",
"summary": {
"total_rows": 3,
"imported_rows": 1,
"failed_rows": 2
},
"errors": [
{
"row_number": 2,
"field": "customer_email",
"code": "invalid_email",
"message": "Email must contain a valid domain.",
"value": "not-an-email"
},
{
"row_number": 2,
"field": "order_date",
"code": "invalid_date_format",
"message": "Use ISO-8601 (YYYY-MM-DD).",
"value": "01/06/2026"
},
{
"row_number": 3,
"field": "order_id",
"code": "required",
"message": "order_id is required.",
"value": ""
},
{
"row_number": 3,
"field": "currency",
"code": "unsupported_currency",
"message": "Allowed values: USD, EUR, GBP.",
"value": "US"
},
{
"row_number": 3,
"field": "total_amount",
"code": "must_be_positive",
"message": "total_amount must be greater than 0.",
"value": " -10"
}
],
"retry": {
"mode": "upload_failed_only",
"failed_row_numbers": [2, 3]
}
}
Partial success quan trọng vì người dùng không nên phải upload lại toàn bộ file. Luồng retry đơn giản: sửa chỉ các hàng lỗi, xuất một CSV nhỏ chứa các hàng 2 và 3, rồi upload lại. Importer của bạn nên coi đó là idempotent khi order_id tồn tại, nên "retry" sẽ cập nhật cùng các bản ghi thay vì tạo trùng.
Với support, correlation_id là con đường nhanh nhất để chẩn đoán. Agent support có thể hỏi một giá trị đó, tìm lần import trong logs, và xác nhận parser đã thấy cột thừa, delimiter sai, hay encoding bất ngờ.
Các bước tiếp theo để lặp được:
Hầu hết lỗi xuất phát từ dữ liệu đời thực lộn xộn, chứ không phải "mã sai". Vấn đề với CSV thường liên quan đến cấu trúc (header, delimiter, quoting, encoding), trong khi với JSON thường là ý nghĩa (kiểu, null vs empty, nesting không mong đợi). Xử lý cả hai như đầu vào không tin cậy và xác thực theo một hợp đồng rõ ràng.
Định nghĩa ba kết quả trước:\n\n- Accepted: tất cả được nhập.\n- Rejected: không có gì được nhập vì file không đáng tin (header sai, JSON không đọc được, encoding sai).\n- Partially accepted: các bản ghi hợp lệ được nhập; các bản ghi không hợp lệ bị bỏ qua với lý do rõ ràng.\n\nChọn một mặc định (nhiều sản phẩm chọn partial) và giữ nó nhất quán trên UI và API.
Soạn một hợp đồng nhập liệu trước khi viết xác thực:\n\n- Các format chấp nhận được (delimiter CSV, yêu cầu header, xử lý UTF-8/BOM; JSON array vs object vs JSON Lines)\n- Quy tắc trường (bắt buộc/tùy chọn/giá trị mặc định)\n- Chuẩn hóa (trim, quy tắc chữ hoa/thường, định dạng ngày)\n- Định nghĩa và xử lý trùng lặp\n- Nơi thực hiện xác thực (client, server, hoặc cả hai)\n\nĐiều này ngăn các bất ngờ kiểu “hôm qua còn chạy được”.
Mặc định một định dạng không mơ hồ cho mỗi trường (ví dụ ngày dưới dạng YYYY-MM-DD). Nếu chấp nhận các biến thể, hãy quy định rõ và có thể dự đoán (ví dụ chấp nhận true/false/1/0, nhưng không phải mọi kiểu do spreadsheet đoán). Tránh đoán định các ngày mơ hồ như 01/02/03; hoặc yêu cầu ISO hoặc trả lỗi với thông báo rõ ràng.
Quyết định:\n\n- Cái gì được coi là trùng lặp (email, external_id, hay composite)\n- Phạm vi phát hiện (trong file, so với dữ liệu hiện có, hoặc cả hai)\n- Hành động (giữ bản ghi đầu, giữ bản ghi sau, gộp, hay từ chối)\n\nNếu người dùng có thể retry, kết hợp với idempotency để cùng một upload không tạo bản sao.
Sử dụng các lớp thay vì một validate() khổng lồ:\n\n- Normalize đầu vào thành hình thức canonical\n- Quy tắc từng trường (type, range, enum)\n- Quy tắc chéo trường (start < end, totals khớp)\n- Quy tắc file (header bắt buộc, key trùng, phiên bản được hỗ trợ)\n\nCác quy tắc nhỏ, có tên dễ test và an toàn khi thay đổi.
Trả về một hình dạng lỗi ổn định gồm:\n\n- code (mã định danh ổn định)\n- message (dễ hiểu cho con người)\n- path/field (tên cột hoặc JSON pointer)\n- / (cho CSV)\n- ( vs )\n\nLàm cho lỗi có thể hành động bằng cách bao gồm điều bạn mong đợi và điều bạn thấy khi có thể.
Luôn trả về tóm tắt nhất quán, ngay cả khi có lỗi:\n\n- các đếm: created, , , , cùng \n- (success, rejected, completed_with_errors)\n- timestamps (, )\n- một cho việc hỗ trợ/gỡ lỗi\n\nVới file lớn, cung cấp nhỏ và cách lấy báo cáo đầy đủ sau đó.
Hỗ trợ retry rõ ràng:\n\n- Chấp nhận idempotencyKey (hoặc dùng hash file)\n- Trả về importId tồn tại nếu request lặp lại\n- Định nghĩa quy tắc upsert (ví dụ email là khóa duy nhất)\n\nNếu không, retry của người dùng có thể tạo bản ghi trùng.
Bắt đầu với vài file seed hợp lệ, rồi tạo nhiều đột biến nhỏ (một thay đổi mỗi lần):\n\n- encoding (UTF-8 BOM, byte không hợp lệ)\n- cấu trúc (thiếu header, cột thừa, delimiter sai)\n- quoting/newlines (quotes chưa đóng, newline nhúng)\n- cạnh kiểu (số cực lớn, empty vs null, NaN/Infinity trong JSON)\n- giới hạn kích thước (field rất dài, nested sâu)\n\nMột bài test fuzz “pass” khi importer không crash/hang và trả lỗi có thể dự đoán, có thể hành động.
rowlineseverityerrorwarningupdatedskippedfailedtotalRows/totalRecordsstatusstartedAtfinishedAtcorrelationIderrorsSample