Auto-response message
ภาพรวม
Auto-response message คือกฎแบบ "keyword → Rich message" เมื่อผู้ใช้พิมพ์ข้อความในห้องแชทตรงกับ keyword ที่ตั้งไว้ ระบบจะส่ง Rich message ที่ผูกไว้กลับไปให้อัตโนมัติโดยไม่ต้องมีแอดมินคอยตอบ เหมาะกับคำถามซ้ำ ๆ เช่น เวลาทำการ ที่ตั้งสาขา หรือวิธีสั่งซื้อ
จุดสำคัญที่ต้องเข้าใจก่อนเริ่มคือ เมนูนี้ไม่ได้เป็นผู้ตอบข้อความเอง — สิ่งที่การกดบันทึกทำจริงคือการเขียน ตาราง keyword ลง Redis ให้ครบทั้ง OA ใหม่ทั้งชุด แล้วบริการเบื้องหลังเป็นผู้อ่านตารางนั้นตอนมีข้อความเข้ามาและเป็นผู้ส่งจริง ผลที่ตามมาคือกฎที่ "ดูปกติ" ในหน้าจอนี้อาจไม่มีอยู่ในตารางที่ใช้ตอบจริงเลยก็ได้ ถ้าเงื่อนไขบางอย่างไม่ครบ (ดูหัวข้อ รายละเอียดสำคัญ)
บทบาทที่ใช้งาน — ทีมที่ดูแลแชทของ LINE OA (โมดูลนี้มี ModuleGate บังคับจริงที่ backend — ดูหัวข้อ สิทธิ์การเข้าถึง)
เส้นทางผู้ใช้งาน
1. ดูรายการกฎ
เปิดเมนู ข้อความตอบกลับอัตโนมัติ สิ่งแรกที่ระบบทำคืออ่านการตั้งค่าของ LINE OA แล้ว ขึ้นแถบเตือนสีเหลืองไว้เหนือตาราง ถ้าลำดับจัดการข้อความถูกตั้งเป็น ai_classifier_only — ข้อความเตือนบอกตรง ๆ ว่า "Auto-response ถูกปิดใช้งานอยู่ในขณะนี้" เพราะโหมดนั้นให้เวิร์กโฟลว์แชตบอทรับข้อความทั้งหมดไป กฎในเมนูนี้จะไม่ถูกกระตุ้นเลย พร้อมบอกที่แก้ให้ด้วย (ตั้งค่า LINE OA → Message Handling)
ตารางมีคอลัมน์ ลำดับ / ชื่อ / Rich message / การดำเนินการ พร้อมสวิตช์สถานะที่กดสลับได้จากหน้ารายการโดยตรง คอลัมน์ Rich message แสดงชื่อของ Rich message ที่ผูกไว้ พร้อม ป้ายกำกับสถานะ — ป้ายสีเขียวเมื่อยังใช้งานได้ และป้าย "ถูกลบแล้ว" เมื่อ Rich message นั้นไม่อยู่ในสถานะใช้งานอีกต่อไป
ตัวกรองมี 2 ช่อง — ค้นหา (ค้นได้ทั้งจาก ชื่อกฎและตัว keyword ตาม placeholder ที่บอกว่า "ชื่อหรือ keyword") และเลือกสถานะ
2. สร้างกฎใหม่
- กดปุ่ม สร้างการตอบกลับ เข้าสู่ฟอร์มสองฝั่ง
- กรอกชื่อกฎ — ไม่เกิน 100 ตัวอักษร ต้องไม่ซ้ำกับกฎอื่น ใต้ช่องชื่อมีกล่อง เงื่อนไขการกรอกข้อมูล อธิบายอักขระ/สัญลักษณ์ที่รองรับ และข้อจำกัดว่าห้ามขึ้นต้นด้วยสัญลักษณ์
- กรอก keyword แบบแท็ก — พิมพ์แล้วกด Enter หรือคั่นด้วยจุลภาคเพื่อเพิ่มหลายคำต่อกฎ กล่องคำแนะนำข้างช่องระบุกฎกติกาไว้ 3 ข้อ: ตอบเฉพาะ keyword ที่ตั้งไว้ (ถ้าตั้งหลายคำจะตอบเมื่อตรงคำใดคำหนึ่ง), แต่ละ keyword ยาวได้ไม่เกิน 30 ตัวอักษร, และ keyword ที่ถูกใช้แล้วจะใช้กับกฎอื่นไม่ได้
- ระบบตรวจ keyword ซ้ำทันทีที่เพิ่มแท็ก (หน่วงไว้ 0.5 วินาที) ถ้าซ้ำ ระบบจะ ลบแท็กนั้นออกให้ ขึ้นข้อผิดพลาดใต้ช่อง และเด้งการแจ้งเตือนมุมขวาบนพร้อมปุ่มเปิดกฎที่ใช้ keyword นั้นอยู่ในแท็บใหม่
- เลือก Rich message ที่ต้องการให้ตอบกลับ จากรายการที่มีอยู่ในเมนู Rich message
- ดูตัวอย่างข้อความ ที่คอลัมน์ขวาในรูปแบบหน้าจอแชทจริง
- เปิดสวิตช์สถานะ (ค่าเริ่มต้นเมื่อสร้างใหม่คือเปิดใช้งาน) แล้วกดบันทึก
3. แก้ไขกฎที่มีอยู่
เปิดฟอร์มแก้ไข ระบบเทียบ Rich message ที่บันทึกไว้กับรายการที่เลือกได้ในปัจจุบัน — ถ้า Rich message นั้น ไม่อยู่ในรายการอีกแล้ว (ถูกลบไป) ระบบจะ ล้างค่าในช่องให้เป็นว่าง และขึ้นข้อผิดพลาดกำกับไว้ บังคับให้เลือกใหม่ก่อนจะบันทึกได้ (ต่างจากหน้ารายการที่แค่ขึ้นป้าย "ถูกลบแล้ว" ให้เห็น)
การกดสวิตช์สถานะในหน้ารายการเรียกเส้นทางแยก (PUT /auto-response/:id/status) ไม่ต้องส่งข้อมูลทั้งฟอร์ม และทุกครั้งที่บันทึกหรือสลับสถานะ ระบบจะเขียนตาราง keyword ใน Redis ใหม่ทั้งชุด
รายละเอียดสำคัญที่ตรวจสอบจากซอร์สโค้ดจริง
ยืนยันจาก internal/modules/autoresponse/{controller,service,dto}.go ของ line-management-cms-api-go, internal/autoresponse/service.go และ internal/cronscheduler/auto_response_sync.go ของ line-management-worker-go:
- ทุกครั้งที่บันทึก ระบบเขียนตาราง keyword ของทั้ง OA ใหม่หมด ไม่ได้แก้เฉพาะกฎที่เพิ่งแตะ — กลไกคือลบคีย์ Redis
AUTO_RESPONSE:LINE_OA_ID:<id>ทิ้งทั้งอัน แล้วสร้างใหม่จากการอ่านกฎ ทุกกฎที่สถานะ active ในองค์กร+OA นั้น ได้ผลเป็น Redis hash ที่แมปkeyword → {autoResponseId, richMessageId}ทำงานเหมือนกันทั้งตอนสร้าง แก้ไข สลับสถานะ ลบ และลบถาวร — และถ้าคำนวณแล้วได้ตารางว่าง ระบบจะ ลบคีย์ทิ้งโดยไม่เขียนอะไรกลับเลย - กฎที่ผูกกับ Rich message ที่ใช้งานไม่ได้จะถูก "ตัดออกเงียบ ๆ" จากตารางที่ใช้ตอบจริง — ตอนสร้างตาราง ระบบดึงรายชื่อ Rich message ที่
status = activeของ OA นั้นมาก่อน แล้ว ข้าม keyword ทุกคำของกฎที่ชี้ไป Rich message ที่ไม่อยู่ในรายชื่อนั้น ผลคือกฎยังอยู่ในฐานข้อมูล ยังโชว์ในตาราง สวิตช์ยังเปิดอยู่ แต่ ไม่มีอยู่ในตารางที่ใช้ตอบจริง — ตรงกับป้าย "ถูกลบแล้ว" ที่หน้ารายการขึ้นให้เห็น - keyword ที่ซ้ำกันข้ามกฎ ตัวที่ถูกอ่านทีหลังจะทับตัวก่อน — ตารางถูกประกอบเป็น map ตรง ๆ ตามลำดับที่อ่านกฎมา จึงเหลือกฎเดียวที่ตอบ keyword นั้นได้ กลไกกัน keyword ซ้ำตอนกรอกฟอร์มจึงเป็นการป้องกันชั้นเดียวที่มี — ไม่มีข้อจำกัดที่ระดับฐานข้อมูลหรือ API ที่กันไว้อีกชั้น
- การจับคู่ keyword ตอนรันจริงเป็นการเทียบแบบตรงตัวทั้งคำ (exact match) — บริการเบื้องหลังใช้
HGETอ่านฟิลด์ตามชื่อ keyword ตรง ๆ ไม่ใช่การค้นแบบมีคำนั้นอยู่ในข้อความ (substring) หรือแบบใกล้เคียง ข้อความที่พิมพ์เกินมาแม้ตัวเดียวจะไม่ตรง POST /check-keyword-existsตอบ 500 เมื่อ keyword "ว่างอยู่" (ใช้ได้) — นี่คือบั๊กจากระบบต้นฉบับที่ถูกคงไว้โดยเจตนา คอมเมนต์ระบุไว้ตรง ๆ ว่า TS อ้างres[0].idบนอาเรย์ว่าง ทำให้เกิด TypeError ระบบจึงตอบ 500 พร้อมข้อความ JavaScript ตามตัวอักษรCannot read properties of undefined (reading 'id')แทนที่จะตอบ{exists: false}และ ฝั่งหน้าเว็บก็รับมือด้วยการถือว่า "คำขอล้มเหลว = keyword ใช้ได้" (เส้นทาง keyword ว่างคือ blockcatchที่แค่เขียน console log) นอกจากนี้ฟิลด์ที่ชื่อrichMessageIdในคำตอบ แท้จริงบรรจุ id ของ auto-response ไม่ใช่ของ Rich message (คอมเมนต์ระบุว่าตั้งชื่อผิดมาตั้งแต่ต้นฉบับ) — แต่นั่นคือค่าที่หน้าเว็บต้องใช้พอดีเพื่อทำลิงก์ "ดูกฎที่ใช้ keyword นี้" พฤติกรรมจึงถูกต้องแม้ชื่อฟิลด์จะผิด- เส้นทางสลับสถานะไม่มีการตรวจสอบข้อมูลใด ๆ เลย —
PUT /auto-response/:id/statusรับค่าstatusจาก body แล้วเขียนลงคอลัมน์ตรง ๆ โดยไม่ตรวจ เพราะในระบบต้นฉบับชนิดของ body เป็น type alias ซึ่งทำให้ ValidationPipe ไม่ทำงาน (คอมเมนต์อธิบายไว้ครบ) เรียก API ตรงด้วยค่าอะไรก็ถูกบันทึกลงไปได้ — และค่าที่ไม่ใช่activeจะทำให้กฎหลุดออกจากตารางที่ใช้ตอบจริงโดยปริยาย - ข้อความแจ้งข้อผิดพลาดของสถานะไม่ตรงกับค่าที่ระบบรับจริง — ข้อความบอกว่า "status must be one of the auto-response status values: active, inactive" แต่รายการค่าที่ผ่านการตรวจจริงคือ CommonStatus ทั้ง 9 ค่า (active, inactive, delete, process, processing, completed, expired, draft, failed) การส่ง
draftหรือfailedมาที่เส้นทางสร้าง/แก้ไขจึงผ่านการตรวจไปได้ ทั้งที่ข้อความบอกว่ารับแค่สองค่า - ค่า
statusที่ไม่ใช่สตริงทำให้เกิด 500 ก่อนที่ฟิลด์อื่นจะถูกตรวจ — ระบบคงพฤติกรรมของ class-transformer ไว้: การแปลงค่าทุกตัวเกิดขึ้น ก่อน การตรวจสอบทั้งหมด ดังนั้นการส่งstatusเป็นตัวเลขหรืออ็อบเจ็กต์จะได้ 500 พร้อมข้อความ JavaScript ตามตัวอักษรtext.toLowerCase is not a functionและ กลบข้อผิดพลาดของฟิลด์อื่นที่กรอกผิดไว้หมด - การตรวจ
keywordsและrichMessageIdหลวมกว่าที่หน้าจอบังคับไว้มาก —keywordsมีแค่กฎ "ต้องไม่ว่าง" ไม่มีกฎ "ต้องเป็นอาเรย์" จึงส่ง อาเรย์ว่าง[]ผ่านได้ (รวมถึงตัวเลขหรืออ็อบเจ็กต์) ส่วนrichMessageIdแปลงค่าตามกฎของ JavaScript ทำให้สตริงว่างกลายเป็นเลข 0 ซึ่งผ่านทั้งกฎ "ไม่ว่าง" และ "ต้องเป็นตัวเลข" — และ ไม่มีการตรวจเลยว่า Rich message นั้นมีอยู่จริงหรือเป็นของ OA ผู้เรียก (ต่างจากเมนู Rich message ที่ตรวจความเป็นเจ้าของของ quick reply อย่างเข้มงวด) กฎที่ชี้ไป id ที่ไม่มีอยู่จะถูกตัดออกจากตาราง Redis เงียบ ๆ อีกที - มีผู้เขียนตาราง keyword ถึงสามทาง และทางที่สามถูกเพิ่มเพื่อแก้อาการ "ตอบแค่ครั้งที่สอง" — นอกจากการบันทึกที่หน้าเว็บ ยังมี cron ทุก 5 นาที ที่ไล่ sync ทุก OA และ การอุ่นแคชแบบ cache-aside ตอนที่คีย์เย็น คอมเมนต์อธิบายอาการเดิมไว้ตรง ๆ ว่าตารางถูกเขียนจาก 2 ทางแรกเท่านั้น พอรีสตาร์ตหรือแคชถูกไล่ออก ข้อความ แรก จะไม่ตรงแม้ตั้งค่าถูก จึงเพิ่มกลไกอุ่นแคชที่ แยกแยะระหว่าง "คีย์ยังไม่มีเลย" (อุ่นจากฐานข้อมูลแล้วลองใหม่) กับ "มีคีย์แต่ไม่มี keyword นี้" (ปล่อยไป) เพื่อไม่ให้ข้อความคุยเล่นทั่ว ๆ ไปกระตุ้นการอุ่นแคชทุกครั้ง
- cron เดิมเคยหยุดกลางทางเมื่อ OA หนึ่งพัง — คอมเมนต์ระบุว่าโค้ดเดิมใช้
returnแทนcontinueOA เดียวที่ตั้งค่าเสียหรือใหญ่เกินจึงทำให้ OA ที่เหลือในรอบนั้นไม่ได้ sync เลย ("สาเหตุหลักอย่างหนึ่งของอาการ auto-response ทำงานแค่ครั้งที่สอง") ปัจจุบันแก้ให้ข้ามตัวที่พังแล้วไปต่อ - ถ้าไม่มี keyword ตรงและเปิดโหมดส่งต่อให้ AI ไว้ ข้อความจะถูกส่งต่อเข้าคิวของ AI — บริการเบื้องหลังจะ publish ข้อความนั้นเข้าคิว trigger ต่อให้ ไม่ได้ทิ้งไปเปล่า ๆ (ถ้าไม่ได้เปิดโหมดนี้ จะเพียงเขียน log ว่าไม่มีกฎรองรับ keyword นั้น)
- merge tag ในเนื้อหาถูกแทนค่าตอนส่ง ไม่ใช่ตอนบันทึก — ตอนจะส่งจริง ระบบตรวจว่าเนื้อหาของ Rich message มี merge tag หรือไม่ ถ้ามีจึงไปอ่านข้อมูลผู้ใช้ LINE คนนั้นมาแทนค่า และถ้า LINE OA ไม่อยู่ในสถานะ active ตอนนั้น งานจะถูกทำเครื่องหมายว่าล้มเหลวแบบถาวร ไม่ลองส่งซ้ำ
- การลบ Rich message ไปล้างตาราง keyword ให้ด้วย — โมดูล Rich message ไล่ลบทุกฟิลด์ใน Redis hash ของเมนูนี้ที่ชี้ไปที่ Rich message ที่ถูกลบ กฎที่ผูกไว้จึงเลิกตอบทันทีโดยไม่ต้องรอ cron รอบถัดไป
- การลบกฎเป็นการลบสองจังหวะ และการลบถาวรไม่ผูกกับ OA — การลบปกติเปลี่ยนสถานะเป็น
deleteก่อน แล้วประทับdeleted_dateอีกครั้งเป็นคำสั่งที่สอง ส่วนDELETE /:id/hardลบด้วยเงื่อนไขidเพียงอย่างเดียว ไม่ได้กรองline_oa_idจึงลบกฎของ OA ใดก็ได้ตาม id (จำกัดด้วยการต้องเป็น Super Admin เท่านั้น) และถ้าไม่ส่งconfirm=trueจะถูกปฏิเสธด้วย 400 ที่มีข้อความเป็นสตริงดิบErrorResponse.AUS_10ซึ่งคอมเมนต์เรียกตรง ๆ ว่าเป็นบั๊กของต้นฉบับที่คงไว้ตามตัวอักษร - ช่องค้นหาค้นทั้งชื่อและ keyword จริงตามที่ placeholder บอก — คำสั่ง SQL ค้นด้วย LIKE แบบไม่สนตัวพิมพ์เล็กใหญ่ทั้งที่คอลัมน์ชื่อ และไล่ดูทุกสมาชิกในอาเรย์ keyword (ผ่าน
jsonb_array_elements_text) ส่วนโหมดพิเศษที่เมนู Segment audience เรียกใช้ จะกรองเฉพาะกฎที่สถานะ active หรือ inactive และ สร้างภายใน 3 เดือนล่าสุด เท่านั้น
เมนูที่เกี่ยวข้องกันในเส้นทางนี้
- Rich message — เนื้อหาที่กฎนี้ส่งออกไป ถ้า Rich message ที่ผูกไว้ถูกลบ กฎจะหลุดจากตารางที่ใช้ตอบจริงทันที หน้ารายการขึ้นป้าย "ถูกลบแล้ว" ให้เห็น และฟอร์มแก้ไขจะบังคับให้เลือกใหม่
- Quick reply — keyword ของกฎที่เปิดใช้งานอยู่ในเมนูนี้จะโผล่เป็นคำแนะนำในช่องข้อความของปุ่มชนิด "ข้อความ" ที่เมนูนั้น เพราะข้อความที่ปุ่มส่งกลับเข้าแชทมากระตุ้นกฎที่นี่ได้จริง
- Template message — เช่นเดียวกัน keyword ที่เปิดใช้งานจะโผล่เป็นคำแนะนำในช่องข้อความของปุ่มชนิด "ส่งข้อความ"
- การตั้งค่า LINE OA — ค่าลำดับจัดการข้อความเป็นตัวตัดสินว่ากฎในเมนูนี้จะได้ทำงานหรือไม่ ถ้าตั้งเป็น
ai_classifier_onlyกฎทั้งหมดจะไม่ถูกกระตุ้น (หน้ารายการขึ้นแถบเตือนไว้ให้) - Segment audience — ใช้กฎในเมนูนี้เป็นเงื่อนไขสร้างกลุ่มเป้าหมายได้ โดยเห็นเฉพาะกฎที่สร้างภายใน 3 เดือนล่าสุด
จุดที่ควรระวัง
- แก้กฎแล้วบอทยังตอบเป็นค่าเดิม ให้รอสักครู่ — การตอบจริงเกิดที่บริการเบื้องหลังซึ่งอ่านจากตาราง Redis ตารางนั้นถูกเขียนใหม่ทันทีตอนกดบันทึก แต่ถ้าจังหวะไม่ลงตัวยังมี cron ทุก 5 นาทีตามมาเก็บอีกชั้น
- กฎที่ผูกกับ Rich message ที่ถูกลบจะเงียบสนิท ไม่มีข้อผิดพลาดที่ไหน — สวิตช์ยังเปิด กฎยังอยู่ในตาราง แต่ไม่มีใครตอบ ให้ดูป้ายกำกับในคอลัมน์ Rich message เป็นอย่างแรกเมื่อมีคนแจ้งว่า "บอทไม่ตอบ"
- keyword ต้องตรงทั้งคำ — ผู้ใช้พิมพ์ "เวลาทำการครับ" จะไม่ตรงกับ keyword "เวลาทำการ" ถ้าต้องการรองรับหลายรูปแบบ ต้องเพิ่มเป็นหลาย keyword ในกฎเดียว (ระบบตอบเมื่อตรงคำใดคำหนึ่ง)
- ถ้า LINE OA ตั้งลำดับจัดการข้อความเป็น
ai_classifier_onlyกฎทั้งหมดในเมนูนี้ไม่ทำงานเลย — แถบเตือนที่หน้ารายการเป็นสัญญาณเดียวที่มี และแถบนี้ปิดได้ ปิดไปแล้วจะไม่มีอะไรเตือนอีก - keyword ยาวเกิน 30 ตัวอักษรถูกกันที่หน้าเว็บเท่านั้น — เพดานนี้ไม่มีการตรวจซ้ำที่ backend เลย
- การกดสวิตช์สถานะเป็นเส้นทางที่ไม่ตรวจข้อมูล — ใช้งานผ่านหน้าเว็บปกติปลอดภัย แต่การเรียก API เส้นทางนี้เองมีความเสี่ยงเขียนค่าที่ระบบไม่รู้จักลงฐานข้อมูล ซึ่งจะทำให้กฎเงียบไปโดยที่หน้าจออาจแสดงผลไม่ตรงความจริง
- ชื่อกฎซ้ำถูกปฏิเสธเป็นรายฟิลด์ — ระบบตอบ 400 พร้อมชี้ที่ฟิลด์
nameว่า "Title is already exist" - ไม่มีการตรวจว่า Rich message ที่เลือกเป็นของ OA ตัวเอง — ในทางปฏิบัติหน้าเว็บให้เลือกได้แค่จากรายการของ OA ตัวเองอยู่แล้ว แต่ระดับ API ไม่มีการกันไว้
สิทธิ์การเข้าถึง (ตรวจสอบจากซอร์สโค้ดจริง)
- ฝั่งหน้าเว็บ — ทั้งหน้ารายการและหน้าฟอร์มถูกครอบด้วย
PermissionGuardตรวจ actionVIEWของ subjectauto-response - ฝั่งเซิร์ฟเวอร์ — ทุกเส้นทางทั้ง 8 เส้นทางของโมดูลนี้ถูกครอบด้วย
ModuleGate(d, "auto-response")ที่บังคับใช้จริง (เหมือนโมดูล Rich message, Template message และ Campaign และต่างจากโมดูล Quick reply ที่ไม่มี ModuleGate เลย) คอมเมนต์ในโค้ดระบุพฤติกรรมไว้ชัด: ผู้เรียกประเภทลูกค้าที่องค์กรถูกผู้ดูแลระดับแพลตฟอร์มปิดโมดูล "auto-response" ไว้ จะได้ 403 ส่วนผู้เรียกภายใน (onemoby) ผ่านได้ - คอมเมนต์บนหัวไฟล์
controller.goบันทึกไว้ว่า@Public()ระดับ controller ในระบบต้นฉบับถูกคอมเมนต์ทิ้งไว้ ทุกเส้นทางจึงวิ่งผ่านการตรวจ JWT ทั้งหมด ไม่มีเส้นทางสาธารณะในโมดูลนี้ - policy annotation ระดับการกระทำ (
create/read/readAll/update/delete) มีประกาศไว้ครบ แต่วิ่งผ่าน middleware ที่เป็น no-op เหมือนโมดูลอื่นส่วนใหญ่ — การบังคับจริงจึงอยู่ที่ ModuleGate ระดับโมดูล DELETE /api/auto-response/:id/hardต้องเป็น Super Admin และต้องส่งconfirm=true(ค่าที่ไม่ใช่true/falseตรงตัวจะถูกปฏิเสธด้วย "Validation failed (boolean string is expected)") — และตามที่ระบุไว้ข้างต้น การลบถาวรนี้ไม่ได้จำกัดอยู่แค่ OA ของผู้เรียก- การกันข้อมูลข้ามองค์กรบังคับที่เส้นทางอื่นทั้งหมด — การอ่าน รายการ แก้ไข สลับสถานะ และการลบแบบนุ่มนวล ผูก
line_oa_idของผู้เรียกไว้ทุกเส้นทาง การเรียก id ที่ไม่ใช่ของตนจะได้ 400APP_007ส่วนการลบที่ไม่พบเป้าหมายจะได้ 400AUS_102
ไฟล์อ้างอิงจากซอร์สโค้ด
Frontend (cms-web-2026)
src/app/auto-response/page.tsx— จุดเข้าหน้ารายการ,PermissionGuard, การอ่านค่า Message Handling ของ LINE OA เพื่อขึ้นแถบเตือนsrc/app/auto-response/form/page.tsx— จุดเข้าหน้าฟอร์ม (สร้าง/แก้ไข/ทำซ้ำ/ดู)src/components/auto-response/list/auto-response.container.tsx— ตาราง, สวิตช์สถานะ, ป้ายกำกับสถานะของ Rich messagesrc/components/auto-response/form/auto-response-form.tsx— ช่องกรอก keyword แบบแท็ก, การตรวจซ้ำแบบหน่วงเวลา, การแจ้งเตือนพร้อมลิงก์ไปกฎที่ชนกันsrc/components/auto-response/form/auto-response-form.container.tsx— การล้างค่า Rich message ที่ถูกลบตอนเปิดฟอร์มแก้ไขsrc/services/auto-response.service.ts— endpoint ทั้งหมดที่หน้าเว็บเรียกใช้messages/th/auto-response.json,messages/en/auto-response.json— ข้อความ UI ทั้งหมด
Backend (line-management-cms-api-go)
internal/modules/autoresponse/controller.go— 8 เส้นทาง,ModuleGate("auto-response"),SuperAdminGuardของ hard delete, เส้นทางสลับสถานะที่ไม่ตรวจข้อมูลinternal/modules/autoresponse/service.go— การเขียนตาราง keyword ใน Redis ใหม่ทั้งชุด, การตัดกฎที่ Rich message ใช้ไม่ได้ออก,IsKeywordExistsinternal/modules/autoresponse/dto.go— กฎตรวจสอบข้อมูลขาเข้าและพฤติกรรมการแปลงค่าแบบ JavaScriptinternal/modules/autoresponse/query.go— การ bind พารามิเตอร์รายการและการสร้างคีย์ cacheinternal/modules/richmessage/service.go— การล้างตาราง keyword เมื่อ Rich message ถูกลบ
Worker (line-management-worker-go)
internal/autoresponse/service.go— การอ่านตาราง keyword ตอนรันจริง, การอุ่นแคชแบบ cache-aside, การส่งต่อให้ AI, การแทน merge taginternal/cronscheduler/auto_response_sync.go— cron ทุก 5 นาทีที่ sync keyword ของทุก OA
ดูรายละเอียดเชิงเทคนิคเพิ่มเติม (เวอร์ชันก่อนหน้าของทีมเอกสาร) ที่ ตอบกลับอัตโนมัติ (Auto Response)