ตั้งค่า Attribute (Attribute Setup)
ภาพรวม
Attribute Setup (ฝั่ง backend ใช้ชื่อ attribute-master) คือหน้าจัดการ schema กลางของ custom attribute ที่ผูกกับผู้ใช้ LINE ในแต่ละ LINE OA พูดง่าย ๆ คือเป็นการ "ประกาศโครงสร้างข้อมูล" ไว้ล่วงหน้าว่า ระบบจะเก็บฟิลด์อะไรบ้าง แต่ละฟิลด์เป็นข้อมูลชนิดใด และฟิลด์ไหนบ้างที่นำไปใช้กรอง audience หรือแสดงในรายงานได้
หน้าจอนี้เหมาะกับผู้ดูแลระบบที่ต้องออกแบบโครงสร้างข้อมูลลูกค้าก่อนเริ่มเก็บข้อมูลจริง เพราะฟีเจอร์ปลายทางอย่าง Audience, Report, Workflow และ Friend Track จะดึงนิยามจากที่นี่ไปใช้ทั้งหมด เมนูอยู่ใต้กลุ่ม Settings → User Attribute Setup
ข้อมูล 1 รายการ (attribute master) ประกอบด้วย
| ข้อมูล | คำอธิบาย |
|---|---|
| ชื่อ (name) | ชื่อชุด attribute ที่ใช้อ้างอิงในตาราง บังคับกรอก ไม่เกิน 255 ตัวอักษร |
| คำอธิบาย (description) | รายละเอียดเพิ่มเติมของชุด attribute นี้ |
| สถานะ (status) | เปิดใช้งาน (active) หรือปิดใช้งาน (inactive) |
| Schema | โครงสร้างฟิลด์ทั้งหมดในรูปแบบ tree รองรับฟิลด์ซ้อน (nested) และ array |
แต่ละฟิลด์ภายใน schema มีคุณสมบัติดังนี้
| คุณสมบัติ | คำอธิบาย |
|---|---|
label | ชื่อที่ผู้ใช้เห็นและเป็น identity จริงที่ระบบตรวจสอบ ห้ามว่างและห้ามซ้ำกันทั้ง tree |
dataType | ชนิดข้อมูล เลือกได้ 6 แบบ: string, number, date, boolean, array, object |
filterable | อนุญาตให้นำฟิลด์นี้ไปใช้เป็นเงื่อนไขกรองใน Audience หรือไม่ |
displayInReport | อนุญาตให้แสดงเป็นคอลัมน์ในรายงาน All Friends หรือไม่ |
path | ตำแหน่งเต็มของฟิลด์ใน JSON ใช้ระบุตำแหน่งเวลาแก้ไข/ลบ |
key | รหัสภายในที่ระบบสร้างให้อัตโนมัติ ไม่แสดงและแก้ไขไม่ได้จากหน้าจอ |
จุดสำคัญที่ต้องทราบ
- ฟิลด์ที่มี
dataTypeเป็นobjectหรือarrayจะไม่สามารถเปิดfilterableหรือdisplayInReportได้ เพราะเป็นฟิลด์เชิงโครงสร้าง ไม่ใช่ค่าที่นำไปเปรียบเทียบตรง ๆ - การเลือก
dataTypeมีผลต่อ operator ที่เลือกได้ในหน้า Audience จึงควรกำหนดให้ถูกต้องตั้งแต่ต้น - สร้าง schema ได้ 2 ทาง คือ กรอกทีละฟิลด์ด้วยมือ หรือ Import from JSON โดยวาง JSON ตัวอย่างแล้วให้ระบบแปลงเป็นโครงสร้างให้
Business Flow
หน้ารายการ (/attribute-setup)
- เปิดหน้า ระบบตั้ง breadcrumb เป็น Settings → User Attribute Setup แล้วโหลดตารางรายการ
- ระบบอ่านเงื่อนไขการกรองล่าสุดจาก sessionStorage หากไม่มีจะใช้ค่าเริ่มต้น (หน้าแรก 10 รายการต่อหน้า ไม่มีคำค้น ไม่กรองสถานะ)
- ตารางแสดงลำดับ ชื่อ คำอธิบาย จำนวนฟิลด์ใน schema สถานะ และวันที่สร้าง คลิกที่ชื่อเพื่อเปิดดูรายละเอียดในโหมดอ่านอย่างเดียว
- ค้นหาด้วยชื่อ และกรองตามสถานะ (ทั้งหมด / เปิดใช้งาน / ปิดใช้งาน) ได้จากแถบเครื่องมือด้านบน มุมขวาแสดงจำนวนรายการทั้งหมด
- ทุกครั้งที่เปลี่ยนเงื่อนไขการกรองหรือหน้า ระบบจะจดจำค่าล่าสุดไว้ในเซสชัน ทำให้กลับเข้าหน้านี้แล้วยังเห็นผลเดิม
- ปุ่มมุมขวาบนมี 2 ปุ่ม คือ Import from JSON สำหรับเข้าโหมดนำเข้า และ Create สำหรับสร้างด้วยมือ
- การลบต้องยืนยันผ่านกล่องข้อความก่อน เมื่อสำเร็จระบบจะแจ้งผลและรีเฟรชตารางให้อัตโนมัติ
การสร้าง / แก้ไข / ดูรายละเอียด (/attribute-setup/form)
- หน้าฟอร์มทำงาน 3 โหมด ได้แก่ สร้างใหม่ แก้ไข และดูอย่างเดียว โดยดูจากพารามิเตอร์ใน URL (
idสำหรับระบุรายการที่แก้ไข และview=trueสำหรับโหมดอ่านอย่างเดียว) - กรณีแก้ไขหรือดู ระบบจะโหลดข้อมูลเดิมมาเติมลงฟอร์มทั้งชื่อ คำอธิบาย สถานะ และ schema
- โหมดดูอย่างเดียวจะปิดการแก้ไขทุกช่อง ตัวแก้ไข schema เป็นแบบอ่านอย่างเดียว และซ่อนปุ่มบันทึก
- เมื่อกดบันทึก ระบบจะไล่ตรวจ label ทุกฟิลด์แบบ recursive ทั้ง tree ก่อนเสมอ โดย label ต้องไม่ว่างและต้องไม่ซ้ำกัน (เทียบแบบไม่สนตัวพิมพ์เล็กใหญ่) ถ้าไม่ผ่านจะแจ้งเตือนและไม่ส่งข้อมูลไปยัง API
- ผ่านการตรวจแล้ว ระบบจะสร้างรายการใหม่หรืออัปเดตรายการเดิม แล้วพากลับสู่หน้ารายการ
โหมด Import from JSON
- ขั้นที่ 1 — กรอกข้อมูลและวาง JSON ผู้ใช้กรอกชื่อ (บังคับ) คำอธิบาย และ root path (ไม่บังคับ ใช้เมื่อต้องการชี้เข้าไปที่ object ย่อยแทนที่จะใช้ทั้งก้อน) จากนั้นวาง JSON ตัวอย่างลงในช่องข้อความ
- กด "Parse & Continue" ระบบจะตรวจรูปแบบ JSON ที่ฝั่งหน้าจอก่อน หากรูปแบบไม่ถูกต้องจะแจ้งเตือนทันทีโดยไม่เรียก API
- รูปแบบถูกต้องแล้ว ระบบส่ง JSON ไปให้ backend แปลงเป็น schema แล้วนำผลลัพธ์กลับมาแสดงในขั้นถัดไป หากแปลงไม่สำเร็จจะแจ้งเตือนพร้อมให้แก้ไขข้อมูลต้นทาง
- ขั้นที่ 2 — ตรวจสอบและปรับแต่ง ผู้ใช้แก้ชื่อและคำอธิบายได้อีกครั้ง พร้อมปรับ schema ที่แปลงมาได้ทั้ง label, ชนิดข้อมูล, สวิตช์ filterable/displayInReport และลบฟิลด์ที่ไม่ต้องการ
- ปุ่ม Back ย้อนกลับไปขั้นแรกได้โดยข้อมูล JSON เดิมยังอยู่ กด Save เพื่อบันทึกเป็น attribute master ใหม่ในสถานะเปิดใช้งาน
การแก้ไข schema ในตัวแก้ไข
- ตัวแก้ไขแปลงโครงสร้าง tree เป็นตารางแบบเยื้องระดับ ฟิลด์ที่มีฟิลด์ลูกจะมีปุ่มลูกศรสำหรับย่อ/ขยาย และมีปุ่ม Expand all / Collapse all สำหรับทั้งตาราง
- แต่ละแถวปรับได้ 4 ส่วน คือ Label, Data type, สวิตช์ Filterable และสวิตช์ Show in report พร้อมปุ่มลบท้ายแถว โดยสวิตช์ทั้งสองจะถูกปิดอัตโนมัติเมื่อชนิดข้อมูลเป็น
objectหรือarray - ปุ่ม "Add attribute" เพิ่มฟิลด์ใหม่ที่ระดับบนสุด โดยตั้งค่าเริ่มต้นเป็นชนิด
stringและเปิดทั้ง filterable และ displayInReport ไว้ให้ ผู้ใช้ต้องกรอก label เอง - การลบฟิลด์ของรายการที่ยังไม่เคยบันทึก จะลบออกทันที
- การลบฟิลด์ของรายการที่บันทึกไว้แล้ว ระบบจะเปิดกล่องเตือนผลกระทบและสอบถาม backend ก่อนว่ามีใครใช้ฟิลด์นั้นอยู่ ผลลัพธ์ครอบคลุม 4 ด้าน คือ จำนวนผู้ใช้ที่มีค่าในฟิลด์นั้น, trigger rule, audience และ rich message ที่อ้างถึง
- ผลการตรวจสอบเป็นเพียงข้อมูลประกอบการตัดสินใจ ไม่ได้บล็อกการลบ หากตรวจสอบไม่สำเร็จระบบก็ยังให้ลบได้
- การยืนยันลบในกล่องนี้เป็นการลบออกจาก schema ในหน้าจอเท่านั้น ต้องกดบันทึกที่ฟอร์มอีกครั้งเพื่อให้มีผลจริง
หน้าจอและองค์ประกอบหลัก
หน้ารายการ (/attribute-setup)
- แถบเครื่องมือ — ช่องค้นหาตามชื่อ (ค้นทันทีขณะพิมพ์) ตัวเลือกสถานะ และตัวเลขสรุปจำนวนรายการทั้งหมด
- ตารางรายการ — ลำดับ ชื่อ (คลิกเพื่อดูรายละเอียด) คำอธิบาย จำนวนฟิลด์ สถานะ วันที่สร้าง และปุ่มดำเนินการ พร้อมการแบ่งหน้า
- ปุ่มสร้าง — Import from JSON และ Create แยกกันชัดเจนที่มุมขวาบน
ไฟล์อ้างอิงหลัก: src/app/attribute-setup/page.tsx, src/components/attribute-setup/list/attribute-setup.container.tsx
หน้าฟอร์ม (/attribute-setup/form)
- การ์ดข้อมูลพื้นฐาน — ชื่อ (บังคับ) คำอธิบาย และสถานะ
- การ์ด Schema — ตัวแก้ไข schema แบบตาราง โดยค่าที่แก้ไขจะถูกเก็บกลับเข้าฟอร์มโดยอัตโนมัติ
- ตัวแก้ไข schema — ตารางแบบ tree รองรับการเยื้องระดับ ย่อ/ขยาย เพิ่ม แก้ และลบฟิลด์
- กล่องเตือนก่อนลบฟิลด์ — แสดงจำนวนผู้ใช้และรายการ trigger rule / audience / rich message ที่อ้างถึงฟิลด์นั้น
ไฟล์อ้างอิงหลัก: src/app/attribute-setup/form/page.tsx, src/components/attribute-setup/form/attribute-setup-form.container.tsx, src/components/attribute-setup/form/components/attribute-editor.tsx, src/components/attribute-setup/form/components/attribute-delete-warning-modal.tsx
บริการฝั่ง API
รวมอยู่ที่ src/services/attribute-master.service.ts ภายใต้ path หลัก attribute-master
| ความสามารถ | Endpoint |
|---|---|
| ดึงรายการ attribute master | GET /attribute-master |
| ดึงข้อมูลรายตัว | GET /attribute-master/{id} |
| สร้างรายการใหม่ | POST /attribute-master |
| แก้ไขรายการ | PUT /attribute-master/{id} |
| ลบรายการ | DELETE /attribute-master/{id} |
| แปลง JSON เป็น schema (พรีวิว) | POST /attribute-master/parse-json |
| ดึงเฉพาะ attribute ที่กรองได้ | GET /attribute-master/filterable |
| ดึงเฉพาะ attribute ที่แสดงในรายงานได้ | GET /attribute-master/reportable |
| ตรวจสอบการใช้งานของ attribute ก่อนลบ | GET /attribute-master/{id}/check-attribute-usage |
จุดเชื่อมต่อกับฟีเจอร์อื่น
- สิทธิ์การใช้งาน — เมนูและหน้าจอถูกควบคุมด้วยสิทธิ์ของโมดูล
attribute-masterซึ่งแมปกับเมนูattribute-setupใต้กลุ่ม Settings การกันสิทธิ์ทำที่เมนูด้านข้างและระบบ ability กลาง - Audience Multi-Source Filter — เมื่อเลือกแหล่งข้อมูลชนิด custom attribute ระบบจะดึงเฉพาะ attribute ที่เปิด filterable มาเป็นตัวเลือก และแยกกลุ่มระหว่างฟิลด์โปรไฟล์มาตรฐาน (path ขึ้นต้นด้วย
__fixed.) กับ custom attribute จาก schema นี้ ส่วน operator ที่เลือกได้ผันตามชนิดข้อมูลของ attribute - Report All Friends — ดึงเฉพาะ attribute ที่เปิด displayInReport มาสร้างคอลัมน์แบบไดนามิก สวิตช์ในหน้านี้จึงเป็นตัวควบคุมคอลัมน์ในรายงานโดยตรง
- Workflow — แผงตั้งค่า node เรียกดูรายการ attribute master ทั้งหมด และสร้าง/แก้ไข attribute master ได้จากในแผงนั้นเลยโดยไม่ต้องกลับมาหน้านี้
- Friend Track และ All Friends detail — ดึงรายการ attribute master เพื่อจับคู่ค่าที่เก็บไว้กับ label ที่ผู้ใช้เข้าใจ
- Import Mapping — ฟิลด์ปลายทางที่ขึ้นต้นด้วย
custom.ในหน้านำเข้าข้อมูล คือ custom attribute ที่ประกาศไว้จากหน้านี้ - System Attribute เป็นคนละฟีเจอร์ — ค่าแบบ key/value ระดับระบบที่ใช้ในหน้า LINE OA Management และ Workflow ไม่ได้เกี่ยวข้องกับ schema ของหน้านี้
- โครงสร้างพื้นฐานร่วม — ใช้ระบบยืนยันตัวตนและ HTTP client กลางของ CMS (ออกจากระบบอัตโนมัติเมื่อ token หมดอายุ) ระบบ breadcrumb และเมนูด้านข้าง รวมถึงการจดจำเงื่อนไขการกรองใน sessionStorage เช่นเดียวกับหน้ารายการอื่นในระบบ
รายละเอียดฝั่ง Backend (CMS API)
โค้ดฝั่ง backend อยู่ที่ internal/modules/attributemaster/ โดยมีส่วนที่แยกไฟล์ออกมาเฉพาะทางสองส่วน คือ ตัวแปลง JSON เป็น schema และ ตัวรักษาลำดับของคีย์ เพื่อให้ผลลัพธ์ที่ส่งกลับเรียงฟิลด์ตรงตามลำดับที่ผู้ใช้วางเข้ามา ไม่สลับไปมาตามการจัดเก็บภายใน
สิทธิ์ที่ต้องมี
- ทุก route ถูกครอบด้วย module gate ของโมดูล
attribute-master - policy แยกตามการกระทำ:
readAllสำหรับดึงรายการ,readสำหรับดูรายตัว ดึงรายการที่กรองได้/แสดงในรายงานได้ ตรวจการใช้งาน และการแปลง JSON เป็นพรีวิว,createสำหรับสร้างและนำเข้าเป็นชุด,updateและdeleteตามการกระทำ - การแปลง JSON เพื่อดูพรีวิวใช้สิทธิ์ระดับอ่านเท่านั้น เพราะยังไม่มีการบันทึกใด ๆ เกิดขึ้น
Validation และ Business Rule ที่ backend ตรวจ
- ตรวจโควตาจำนวน attribute ก่อนสร้างเสมอ (ค่า
maxAttributesของแพ็กเกจ) การสร้างจึงถูกปฏิเสธได้แม้ schema จะถูกต้องทุกอย่าง - การนำเข้าจาก JSON แยกเป็นสองจังหวะชัดเจน:
POST /api/attribute-master/parse-jsonแปลงและคืนพรีวิวเท่านั้น ยังไม่บันทึก โดยรับ root path มาด้วยได้เพื่อชี้เข้าไปที่ object ย่อย ส่วนการบันทึกจริงเป็นอีกคำขอต่างหาก - backend ยังเปิด
POST /api/attribute-master/import-jsonไว้สำหรับสร้าง attribute จาก schema ทั้งชุดในคำขอเดียว ซึ่งเป็นเส้นทางที่มีอยู่ฝั่ง API แม้หน้าจอปัจจุบันจะบันทึกผ่านเส้นทางสร้างปกติ GET /api/attribute-master/:id/check-attribute-usageรับคีย์ของ attribute ที่ต้องการตรวจมาทาง query string เป็นตัวระบุ ไม่ใช่ตรวจทั้งรายการรวดเดียว
สิ่งที่บันทึกและผลข้างเคียง (Side Effect)
- นิยาม schema เก็บอยู่ในตาราง
attribute_masterส่วนค่าจริงของแต่ละคนเก็บเป็น custom attribute ที่ผูกกับตารางline_user - การตรวจการใช้งานก่อนลบต้องมองข้ามไปหลายตาราง ทั้ง
audience,form_builder,import_mapping_jobและtemplate_messageเพื่อรวบรวมว่ามีใครอ้างถึงฟิลด์นั้นอยู่บ้าง - โมดูลนี้ไม่ได้เขียน cache และไม่ได้ส่งงานเข้าคิว การเปลี่ยน schema จึงมีผลทันทีกับฟีเจอร์ที่อ่านนิยามไปใช้
- ผลกระทบเป็นวงกว้าง — เพราะ Audience filter, รายงาน All Friends, merge tag ของข้อความ และฟิลด์ปลายทางของการนำเข้าข้อมูล ล้วนอ่านนิยามจากตารางนี้ การแก้ชนิดข้อมูลหรือลบฟิลด์จึงกระทบหลายฟีเจอร์พร้อมกัน
Attribute ระดับระบบ เป็นคนละโมดูลที่ backend
นอกจาก attribute ที่ตั้งเองต่อ LINE OA ระบบยังมี attribute ระดับระบบ ที่นิยามไว้กลางในโมดูลแยกต่างหาก (internal/modules/systemattribute/) เป็นชุด attribute พื้นฐานที่ทุก OA มีเหมือนกัน
- เป็นโมดูล CRUD เรียบง่ายเพียง 4 endpoint ภายใต้
/api/system-attribute - ผลลัพธ์ถูกนำไปรวมกับ custom attribute ในรายการ merge tag ของข้อความ (เมื่อร้องขอให้รวม attribute ระบบเข้าไปด้วย) และใช้ประกอบตอนสร้างฟอร์มและรายงาน
- ตารางนี้ใช้กลไก soft delete อัตโนมัติของ ORM จริง ๆ (ต่างจากหลายโมดูลในระบบที่ต้องเขียนเงื่อนไขเอง) การดึงรายการจึงกรองรายการที่ถูกลบออกให้เองอยู่แล้ว
- ข้อสังเกตด้านความปลอดภัย — โมดูลนี้ ไม่มี module gate และไม่มีการบังคับสิทธิ์ระดับ Super Admin ครอบไว้ ขอเพียงผ่านการยืนยันตัวตนกลางและมี LINE OA ที่เลือกไว้ก็เรียกได้ ทั้งที่ข้อมูลชุดนี้เป็นค่าที่ใช้ร่วมกันทั้งระบบ ไม่ใช่ข้อมูลเฉพาะของ OA ใด OA หนึ่ง
- Edge case — คำสั่งแก้ไข attribute ระบบถูกเขียนให้ไม่กรองรายการที่ถูกลบไปแล้วออก (คงพฤติกรรมเดิมของระบบก่อนหน้าไว้) ผลคือการแก้ไขด้วย id ของรายการที่ถูกลบไปแล้วยังทำได้สำเร็จ ทั้งที่รายการนั้นจะไม่ปรากฏในผลการดึงรายการ
Edge Case และข้อสังเกตที่ควรรู้
- ผลการตรวจการใช้งานก่อนลบเป็นเพียงข้อมูลประกอบการตัดสินใจ backend ไม่ได้บล็อกการลบ แม้จะพบว่ามีฟีเจอร์อื่นอ้างถึงอยู่ ความรับผิดชอบในการไม่ทำของพังจึงอยู่ที่ผู้ใช้
- การจัดการข้อผิดพลาดของโมดูลนี้จะส่งต่อข้อผิดพลาดที่รู้จัก (เช่น ไม่มีสิทธิ์ ไม่พบข้อมูล ข้อมูลไม่ถูกต้อง ข้อมูลชนกัน) กลับไปตามเดิม แต่ข้อผิดพลาดที่ไม่รู้จักทั้งหมดจะถูกยุบเป็นข้อผิดพลาดทั่วไปรหัสเดียว ทำให้รายละเอียดต้นเหตุหายไปจากคำตอบ ต้องไปดูที่ log ของ backend แทน
- ลำดับของฟิลด์ใน schema เป็นสิ่งที่โมดูลนี้ตั้งใจรักษาไว้ ไม่ใช่ผลพลอยได้ — การเรียงคอลัมน์ในรายงานและลำดับ merge tag จึงคาดเดาได้
- การแก้ชนิดข้อมูลของฟิลด์ที่มีข้อมูลอยู่แล้วไม่ได้ทำให้ค่าที่เก็บไว้เปลี่ยนตามไปด้วย มีเพียงชุดตัวดำเนินการที่เลือกได้ในหน้า Audience เท่านั้นที่เปลี่ยน ค่าที่เก็บไว้ก่อนหน้าจึงอาจเทียบเงื่อนไขไม่ได้ตามที่คาด