นำเข้าข้อมูลและ Mapping ฟิลด์ (Import Mapping)
ภาพรวม
Import Mapping คือฟีเจอร์สำหรับ นำเข้าไฟล์ CSV เพื่ออัปเดตข้อมูลโปรไฟล์ของเพื่อน (LINE friend) ที่มีอยู่แล้วในระบบ เหมาะกับผู้ดูแล CMS ที่ถือข้อมูลลูกค้าจากระบบภายนอก แล้วต้องการ sync ค่าลงมาที่โปรไฟล์เพื่อนหรือ custom attribute
หลักการสำคัญที่ต้องเข้าใจก่อนใช้งาน
- การนำเข้านี้เป็นแบบ update-only ระบบจะไม่สร้างผู้ใช้ใหม่จากไฟล์ CSV
- ต้องเลือก match key เสมอ ซึ่งเป็นการจับคู่ระหว่างฟิลด์ในโปรไฟล์กับคอลัมน์ใน CSV เพื่อระบุว่าข้อมูลแต่ละแถวตรงกับเพื่อนคนใด
- แถวที่หาเพื่อนไม่เจอจะถูกนับเป็น "no match" และถูกข้ามไป ไม่ทำให้ทั้งไฟล์ล้มเหลว
- การนำเข้าทำงานเป็น งานเบื้องหลัง (asynchronous job) เมื่อสั่งแล้วผู้ใช้จะกลับมาที่หน้ารายการเพื่อติดตามสถานะ
ฟีเจอร์นี้มี 2 หน้าจอ คือหน้ารายการประวัติการนำเข้า (/import-mapping) และหน้า wizard 4 ขั้นตอนสำหรับสร้างงานนำเข้าใหม่ (/import-mapping/import)
สถานะของงานนำเข้ามี 5 แบบ
| สถานะ | ความหมายที่แสดงบนหน้าจอ |
|---|---|
| pending | รอคิวประมวลผล |
| processing | กำลังประมวลผล |
| success | เสร็จสมบูรณ์ |
| partial | เสร็จแล้วแต่มีบางแถวผิดพลาด |
| failed | ล้มเหลว |
ฟิลด์ปลายทางที่เลือกได้มาจากฝั่ง backend และแบ่งเป็น 2 กลุ่ม คือฟิลด์ที่ใช้เป็น match key ได้ และฟิลด์ที่ใช้เป็นปลายทางในการเขียนค่า โดยฟิลด์ปลายทางที่ขึ้นต้นด้วย custom. จะถูกจัดกลุ่มแยกเป็น "Custom attributes" ซึ่งก็คือ custom attribute ที่ประกาศไว้ในหน้า Attribute Setup
Business Flow
หน้ารายการประวัติการนำเข้า (/import-mapping)
- เข้าหน้า ระบบตรวจสิทธิ์การเข้าถึงก่อน แล้วตั้ง breadcrumb และไฮไลต์เมนูด้านข้าง
- ระบบโหลดประวัติงานนำเข้าตามหน้าปัจจุบัน หน้านี้ไม่มีตัวกรองหรือการค้นหา มีเฉพาะการแบ่งหน้าเท่านั้น
- ระบบตรวจว่ามีงานที่สถานะ pending หรือ processing อยู่ในหน้าที่แสดงหรือไม่ ถ้ามีจะดึงข้อมูลใหม่อัตโนมัติทุก 10 วินาที และหยุดดึงเมื่อไม่มีงานค้างแล้ว
- ตารางแสดงชื่อไฟล์ (ตัดข้อความยาวพร้อม tooltip แสดงชื่อเต็ม) สถานะเป็นป้ายกำกับสี จำนวนเรคคอร์ด วันที่สร้าง และลิงก์ดาวน์โหลด log
- คอลัมน์จำนวนเรคคอร์ดปรับตามสถานะ งานที่จบแล้วจะแสดงจำนวนแถวที่อัปเดตสำเร็จและที่ถูกข้าม ส่วนงานที่ยังทำงานอยู่จะแสดงจำนวนแถวทั้งหมดที่รอประมวลผล
- หากงานสร้างไฟล์ log ไว้ คอลัมน์ Import log จะเป็นลิงก์ดาวน์โหลดที่เปิดในแท็บใหม่ หากไม่มีจะแสดงเครื่องหมายขีด
- เมื่อยังไม่มีประวัติใด ๆ ตารางจะแสดงสถานะว่างพร้อมคำอธิบายและปุ่ม "Import CSV" ให้เริ่มใช้งานได้ทันที
- กดปุ่ม "Import CSV" เพื่อเข้าสู่ wizard สร้างงานนำเข้าใหม่
Wizard นำเข้าข้อมูล (/import-mapping/import)
ขั้นที่ 1 — อัปโหลดไฟล์
- ลากไฟล์ CSV มาวางหรือกดเลือกไฟล์ รองรับครั้งละ 1 ไฟล์
- ระบบตรวจขนาดไฟล์ก่อนเสมอ หากเกิน 20 MB จะแจ้งเตือนทันทีโดยไม่ส่งไฟล์ขึ้นระบบ
- ผ่านแล้วระบบจะอัปโหลดไฟล์และรับข้อมูลกลับมา ได้แก่ ชื่อไฟล์ ตำแหน่งไฟล์ รายชื่อคอลัมน์ ตัวอย่างข้อมูล และจำนวนเรคคอร์ดทั้งหมด
- การอัปโหลดไฟล์ใหม่จะรีเซ็ตค่าทุกขั้นตอนที่ตามมาทั้งหมด ทั้ง match key, การจับคู่คอลัมน์ และผลการตรวจสอบ
- เมื่ออัปโหลดสำเร็จจะแสดงบรรทัดสรุปชื่อไฟล์และจำนวนเรคคอร์ด ปุ่มถัดไปจะเปิดใช้งานเมื่อมีไฟล์แล้วเท่านั้น
ขั้นที่ 2 — ดูตัวอย่างข้อมูล
- แสดงบรรทัดสรุปว่ากำลังแสดงตัวอย่างกี่แถวจากทั้งหมดกี่แถว
- ตารางตัวอย่างแสดงข้อมูลจริงจากไฟล์ โดยแต่ละช่องแสดงเป็นบรรทัดเดียวและมี tooltip แสดงค่าเต็ม ช่องที่ไม่มีค่าจะแสดงเป็นเครื่องหมายขีด
- ขั้นตอนนี้ใช้ยืนยันว่าไฟล์ถูกอ่านตรงตามที่คาดไว้ ก่อนไปตั้งค่าการจับคู่
ขั้นที่ 3 — จับคู่ฟิลด์
- การ์ด Match key — เลือกฟิลด์ในโปรไฟล์ทางซ้ายและคอลัมน์ใน CSV ทางขวา เพื่อกำหนดว่าจะใช้อะไรจับคู่หาเพื่อน โดยตัวเลือกฝั่งโปรไฟล์แบ่งกลุ่มเป็นฟิลด์โปรไฟล์และ custom attribute
- คอลัมน์ที่ถูกเลือกเป็น match key จะถูกถอดออกจากรายการคอลัมน์ที่จะเขียนค่าโดยอัตโนมัติ เพราะทำหน้าที่เป็นกุญแจค้นหาแล้ว
- การ์ด Column mapping — แสดงทุกคอลัมน์ใน CSV เป็นแถว โดยแต่ละแถวมีชื่อคอลัมน์พร้อมค่าตัวอย่างแรกที่ไม่ว่าง ตามด้วยลูกศรและตัวเลือกฟิลด์ปลายทาง
- คอลัมน์ที่เป็น match key จะไม่มีตัวเลือกปลายทาง แต่แสดงป้าย "match key" แทน
- ตัวเลือกฟิลด์ปลายทางมีตัวเลือกแรกคือ "Don't import" สำหรับคอลัมน์ที่ไม่ต้องการนำเข้า และรองรับการพิมพ์ค้นหาชื่อฟิลด์
- ฟิลด์ปลายทางที่ถูกคอลัมน์อื่นเลือกไปแล้วจะถูกปิดไม่ให้เลือกซ้ำ เพื่อบังคับความสัมพันธ์แบบ 1 คอลัมน์ต่อ 1 ฟิลด์
- หน้าจอใช้สีแยกที่มาของข้อมูลให้ชัดเจน ฝั่งคอลัมน์จากไฟล์ผู้ใช้เป็นสีกลาง ส่วนฝั่งฟิลด์ของระบบเป็นสีฟ้าตามสีแบรนด์
- ปุ่มถัดไปจะเปิดใช้งานเมื่อเลือก match key ครบทั้งสองฝั่ง และมีคอลัมน์อย่างน้อย 1 คอลัมน์ที่จับคู่ปลายทางไว้แล้ว
- เมื่อกดถัดไป ระบบจะส่งข้อมูลการจับคู่ไปให้ backend ตรวจสอบล่วงหน้า แล้วนำผลลัพธ์ไปแสดงในขั้นสุดท้าย
ขั้นที่ 4 — ตรวจทานและสั่งนำเข้า
- แสดงการ์ดสรุปตัวเลข 4 ใบ ได้แก่ จำนวนแถวทั้งหมด จำนวนแถวที่จะถูกอัปเดต จำนวนแถวที่หาเพื่อนไม่เจอ และจำนวนแถวที่ข้อมูลผิดรูปแบบ
- หากมีแถวที่จะถูกข้าม ระบบจะแสดงแถบเตือนพร้อมจำนวนรวม เพื่อให้ผู้ใช้ตัดสินใจว่าจะแก้ไฟล์ก่อนหรือดำเนินการต่อ
- หาก backend ส่งเหตุผลของการข้ามกลับมา ระบบจะแสดงเป็นตารางสรุปเหตุผลพร้อมจำนวนแถวของแต่ละเหตุผล
- กด "Start import" เพื่อสร้างงานนำเข้า โดยระบบจะส่งข้อมูลไฟล์ match key การจับคู่คอลัมน์ และผลการตรวจสอบจากขั้นก่อนหน้าไปพร้อมกัน เพื่อให้ backend เก็บเป็นภาพรวมของการตรวจสอบ ณ เวลานั้น
- เมื่อสร้างงานสำเร็จ ระบบจะแจ้งผลและพากลับสู่หน้ารายการเพื่อติดตามสถานะต่อ
ความหมายของตัวเลขในผลตรวจสอบ
| ตัวเลข | ความหมาย |
|---|---|
| Total rows | จำนวนแถวทั้งหมดในไฟล์ที่ถูกตรวจสอบ |
| Will update | จำนวนแถวที่จับคู่กับเพื่อนได้และจะถูกอัปเดตจริง |
| No match | แถวที่หาเพื่อนตาม match key ไม่พบ จะถูกข้าม |
| Invalid | แถวที่ข้อมูลผิดรูปแบบ จะถูกข้าม |
| Skip reasons | สรุปเหตุผลของการข้ามพร้อมจำนวนแถวของแต่ละเหตุผล |
ตัวเลขชุดเดียวกันนี้ถูกส่งไปพร้อมกับการสร้างงาน และใช้แสดงจำนวนแถวที่รอประมวลผลในหน้ารายการ ก่อนจะถูกแทนที่ด้วยผลจริงเมื่องานทำงานเสร็จ
หน้าจอและองค์ประกอบหลัก
หน้ารายการ (/import-mapping)
- หัวข้อหน้าและปุ่มนำเข้า — ใช้ส่วนหัวมาตรฐานของ CMS พร้อมปุ่ม Import CSV
- ตารางประวัติ — ชื่อไฟล์ สถานะ จำนวนเรคคอร์ด วันที่สร้าง และลิงก์ดาวน์โหลด log พร้อมการแบ่งหน้า
- สถานะว่าง — แสดงเมื่อยังไม่มีประวัติ พร้อมคำอธิบายและปุ่มเริ่มนำเข้า
- การติดตามสถานะอัตโนมัติ — รีเฟรชข้อมูลทุก 10 วินาทีเมื่อมีงานที่ยังทำงานอยู่ในหน้าที่แสดง
ไฟล์อ้างอิงหลัก: src/app/import-mapping/page.tsx, src/components/import-mapping/import-mapping-list.container.tsx, src/components/import-mapping/import-mapping-table.tsx
หน้า wizard (/import-mapping/import)
- แถบขั้นตอน — แสดงความคืบหน้า 4 ขั้น พร้อมปุ่มย้อนกลับและถัดไปที่เปลี่ยนตามขั้นตอนปัจจุบัน
- ขั้นอัปโหลด — พื้นที่ลากวางไฟล์พร้อมตรวจขนาดไฟล์และบรรทัดสรุปผลอัปโหลด
- ขั้นพรีวิว — ตารางตัวอย่างข้อมูลจากไฟล์
- ขั้นจับคู่ — การ์ด match key และการ์ดจับคู่คอลัมน์แบบรายแถว
- ขั้นตรวจทาน — การ์ดสรุปตัวเลข แถบเตือนแถวที่ถูกข้าม และตารางเหตุผล
ไฟล์อ้างอิงหลัก: src/app/import-mapping/import/page.tsx, src/components/import-mapping/import-wizard.container.tsx, src/components/import-mapping/steps/upload-step.tsx, src/components/import-mapping/steps/preview-step.tsx, src/components/import-mapping/steps/mapping-step.tsx, src/components/import-mapping/steps/review-step.tsx
บริการฝั่ง API
รวมอยู่ที่ src/services/import-mapping.service.ts ภายใต้ path หลัก import-mapping
| ความสามารถ | Endpoint | ใช้ที่ |
|---|---|---|
| อัปโหลดไฟล์ CSV | POST /import-mapping/upload | ขั้นที่ 1 |
| ดึงรายการฟิลด์ปลายทางและ match key | GET /import-mapping/fields | โหลดตอนเข้า wizard |
| ตรวจสอบข้อมูลก่อนนำเข้า | POST /import-mapping/validate | ขั้นที่ 3 ก่อนไปขั้นที่ 4 |
| สร้างงานนำเข้า | POST /import-mapping | ขั้นที่ 4 |
| ดึงประวัติงานนำเข้า | GET /import-mapping | หน้ารายการและการติดตามสถานะ |
ข้อจำกัดที่ควรทราบ
- ไม่มีหน้ารายละเอียดของงานนำเข้า และไม่มีปุ่มยกเลิกหรือลบงาน เมื่อสั่งแล้วต้องรอให้ประมวลผลจบ
- หน้ารายการไม่มีการค้นหา การกรอง หรือการเรียงลำดับ มีเพียงการแบ่งหน้า
- การติดตามสถานะอัตโนมัติทำเฉพาะงานที่ปรากฏในหน้าที่กำลังแสดงอยู่ หากงานที่ยังทำงานอยู่อยู่ในหน้าอื่นจะไม่ถูกรีเฟรช
- ลิงก์ดาวน์โหลด log เป็น URL ที่ backend สร้างให้และเข้าถึงได้ด้วยตัวเอง ไม่ได้ผ่านระบบยืนยันตัวตนของ CMS
- การย้อนกลับจากขั้นตรวจทานไปแก้การจับคู่ ต้องกดถัดไปเพื่อตรวจสอบใหม่ทุกครั้ง
จุดเชื่อมต่อกับฟีเจอร์อื่น
- สิทธิ์การใช้งาน — ทั้งหน้ารายการและ wizard ใช้สิทธิ์ดูข้อมูลของโมดูล
import-mappingร่วมกัน ผู้ที่เข้าดูหน้ารายการได้จึงสั่งนำเข้าได้ด้วย - Attribute Setup — ฟิลด์ปลายทางที่ขึ้นต้นด้วย
custom.คือ custom attribute ที่ประกาศไว้ในหน้า Attribute Setup การเพิ่มฟิลด์ใหม่ที่นั่นจึงทำให้มีปลายทางใหม่ให้เลือกที่นี่ - โปรไฟล์เพื่อน (Friend profile) — เป็นปลายทางของการอัปเดต ค่าที่นำเข้าจะไปปรากฏในรายงาน All Friends และใช้เป็นเงื่อนไขใน Audience ได้ตามการตั้งค่าของ attribute นั้น
- ระบบงานเบื้องหลัง — การประมวลผลจริงทำที่ฝั่ง server หน้าจอรับรู้ความคืบหน้าผ่านสถานะ ตัวเลขสรุป และไฟล์ log เท่านั้น
- Member Database — เป็นฟีเจอร์คนละตัว ใช้เก็บ CSV เป็นชุดข้อมูลอ้างอิงแยกต่างหาก ไม่ได้เขียนทับโปรไฟล์เพื่อนแบบฟีเจอร์นี้
- โครงสร้างพื้นฐานร่วม — ใช้ระบบยืนยันตัวตนและ HTTP client กลางของ CMS ระบบ breadcrumb และเมนูด้านข้าง รวมถึงส่วนหัวหน้าและพื้นที่เลื่อนตารางมาตรฐานเช่นเดียวกับหน้ารายการอื่นในระบบ
รายละเอียดฝั่ง Backend (CMS API)
โค้ดฝั่ง backend อยู่ที่ internal/modules/importmapping/ โมดูลนี้เป็น ผู้เตรียมงานและรับคำสั่ง เท่านั้น การอัปเดตข้อมูลโปรไฟล์จริงเกิดที่ line-management-worker-go ซึ่งเป็นคนละ service
สิทธิ์ที่ต้องมี
- ทุก route ถูกครอบด้วย module gate ของโมดูล
import-mapping - policy ที่ประกาศไว้ต่างกันตาม endpoint:
readAllสำหรับดึงประวัติงาน,readสำหรับดึงรายการฟิลด์ปลายทาง ส่วน การอัปโหลดไฟล์ การตรวจสอบล่วงหน้า และการสร้างงานนำเข้า ล้วนใช้ policy ระดับcreate - ข้อสังเกต — ฝั่งหน้าจอควบคุมทั้งหน้ารายการและ wizard ด้วยสิทธิ์ดูข้อมูลชุดเดียวกัน แต่ฝั่ง backend แยกระดับสิทธิ์ของการอ่านออกจากการสั่งนำเข้าไว้ชัดเจนกว่านั้น
แหล่งที่มาของฟิลด์ปลายทาง
- รายการฟิลด์ที่เลือกได้ (
GET /api/import-mapping/fields) ประกอบขึ้นจากสองแหล่งรวมกัน คือฟิลด์มาตรฐานของตารางline_userและ custom attribute ที่ประกาศไว้ในตารางattribute_master - ดังนั้นการเพิ่ม attribute ใหม่ในหน้า Attribute Setup จะทำให้มีปลายทางใหม่ให้เลือกที่นี่ทันที โดยไม่ต้องแก้อะไรที่โมดูลนำเข้า
Validation และ Business Rule ที่ backend ตรวจ
- ขั้นตอนอัปโหลด (
POST /api/import-mapping/upload) เก็บไฟล์ลง object storage ก่อน แล้วคืนเฉพาะหัวคอลัมน์ที่อ่านได้กลับมา ตัวไฟล์ไม่ได้ถูกส่งซ้ำในขั้นตอนถัดไป - ขั้นตอนตรวจสอบล่วงหน้า (
POST /api/import-mapping/validate) ไล่เทียบข้อมูลกับตารางline_userของ LINE OA ปัจจุบันจริง ๆ ไม่ใช่การตรวจเพียงรูปแบบข้อมูล ตัวเลข "จะอัปเดตกี่แถว" และ "หาไม่เจอกี่แถว" ที่เห็นในขั้นตรวจทาน จึงเป็นผลจากการค้นข้อมูลจริงในเวลานั้น - ทุก query ถูกจำกัดขอบเขตตาม LINE OA และองค์กรที่กำลังใช้งานอยู่ ข้อมูลจึงไม่ข้ามไปแตะเพื่อนของ OA อื่น
- การนำเข้าเป็นแบบอัปเดตเท่านั้น backend ไม่สร้างผู้ใช้ใหม่จากไฟล์ แถวที่จับคู่ไม่ได้จะถูกนับและข้าม ไม่ทำให้ทั้งงานล้มเหลว
สิ่งที่บันทึกและผลข้างเคียง (Side Effect)
- การกด "Start import" ไม่ได้อัปเดตข้อมูลทันที แต่สร้างแถวงานในตาราง
import_mapping_jobด้วยสถานะรอประมวลผล แล้ว ส่งรหัสงานเข้าคิวข้อความ ให้ worker รับไปทำ - worker เป็นผู้เขียนค่าลงตาราง
line_userจริง และเป็นผู้ปรับสถานะของงานตามความคืบหน้า สถานะที่หน้าจอ poll เห็นจึงมาจาก worker ไม่ใช่จาก cms-api - ผลลัพธ์การตรวจสอบล่วงหน้าถูกส่งไปเก็บพร้อมกับตอนสร้างงานด้วย เพื่อให้เป็นภาพรวมของสิ่งที่ตรวจไว้ ณ เวลานั้น ก่อนที่ผลจริงจะเข้ามาแทน
- ไฟล์ CSV ต้นฉบับยังคงอยู่บน object storage หลังงานเสร็จ
Edge Case และข้อสังเกตที่ควรรู้
- ผลการตรวจสอบล่วงหน้าเป็นภาพ ณ เวลาที่ตรวจ ไม่ใช่การจอง ถ้ามีเพื่อนถูกเพิ่มหรือถูกลบระหว่างที่รอคิว จำนวนแถวที่อัปเดตได้จริงอาจต่างจากตัวเลขในขั้นตรวจทาน
- ถ้า worker ไม่ทำงานหรือคิวติดขัด งานจะค้างอยู่ในสถานะรอประมวลผลไปเรื่อย ๆ โดยฝั่ง CMS ไม่มีสัญญาณผิดพลาดใด ๆ และไม่มี endpoint สำหรับยกเลิกงาน
- ไฟล์ log ที่ดาวน์โหลดได้เป็นไฟล์ที่ worker สร้างไว้บน storage ลิงก์ที่ได้จึงเป็นการเข้าถึงไฟล์ตรง ไม่ได้ผ่านการตรวจสิทธิ์ของ CMS อีกชั้น — ควรถือว่าใครที่ได้ลิงก์ไปก็เปิดดูได้
- โมดูลนี้ไม่มี endpoint สำหรับดูรายละเอียดงานรายตัว ข้อมูลทั้งหมดที่หน้าจอมีจึงมาจากรายการแบบแบ่งหน้าและไฟล์ log เท่านั้น