Skip to main content

หมวดหมู่เนื้อหา (Content Category)

ภาพรวม

Content Category คือหมวดหมู่ระดับบนสุด (level 1) ของระบบเนื้อหา ใช้จัดกลุ่มหน้าเนื้อหาให้เป็นระเบียบ และเป็นจุดตั้งต้นของ Content Subcategory ซึ่งแตกย่อยลงไปได้ถึงระดับ 4

หน้าจอนี้เหมาะกับผู้ดูแลระบบหรือทีมคอนเทนต์ที่ต้องวางโครงสร้างการจัดหมวดก่อนเริ่มสร้างหน้าเนื้อหาจริง เพราะหมวดหมู่ที่สร้างไว้จะถูกนำไปใช้เป็นตัวเลือกในอีกหลายหน้าจอ

ข้อมูล 1 หมวดหมู่ประกอบด้วย

ข้อมูลคำอธิบาย
ชื่อหมวดหมู่บังคับกรอก ความยาวไม่เกิน 255 ตัวอักษร
Slugบังคับกรอก ไม่เกิน 255 ตัวอักษร อนุญาตเฉพาะตัวอักษรพิมพ์เล็ก ตัวเลข และเครื่องหมายขีด
คำอธิบายไม่บังคับ ความยาวไม่เกิน 1,000 ตัวอักษร
รูปย่อรูปประกอบของหมวดหมู่
ลำดับการแสดงผลตัวเลขจำนวนเต็มไม่ติดลบ ใช้จัดลำดับในรายการ
สถานะเปิด (active) / ปิด (inactive) ค่าเริ่มต้นคือเปิดใช้งาน

จุดสำคัญที่ต้องทราบ

  • ข้อมูลที่ดึงมาแสดงในตารางจะแนบรายการหมวดย่อยมาด้วย จึงแสดงจำนวนหมวดย่อยของแต่ละหมวดได้ทันทีโดยไม่ต้องเรียกข้อมูลเพิ่ม
  • การลบหมวดหมู่กระทบทั้งหมวดย่อยและหน้าเนื้อหาที่ผูกอยู่ ระบบจึงเตือนก่อนยืนยันทุกครั้ง
  • นอกจากรายการปกติ โมดูลนี้ยังให้บริการรายการหมวดหมู่แบบ dropdown ที่หน้าจออื่นเรียกใช้เป็นจำนวนมาก

Business Flow

การจัดการรายการหมวดหมู่

  1. เปิดหน้ารายการที่ /content-category ระบบดึงข้อมูลแบบแบ่งหน้าพร้อมเงื่อนไขค้นหาและตัวกรองสถานะ
  2. ตารางแสดงชื่อหมวดหมู่ (คลิกเพื่อเข้าสู่หน้าแก้ไข) slug จำนวนหมวดย่อย ลำดับการแสดงผล สถานะ วันที่ปรับปรุงล่าสุด และเมนูการดำเนินการ
  3. ค้นหาด้วยคำค้นและกรองตามสถานะได้ เมื่อกดค้นหาระบบจะกลับไปหน้าแรกของรายการเสมอ
  4. กดที่ตัวเลขจำนวนหมวดย่อย หรือเลือกเมนู "ดูหมวดย่อย" ระบบจะพาไปหน้า Content Subcategory พร้อมกรองเฉพาะหมวดหมู่ที่เลือกไว้ให้แล้ว
  5. การลบเปิดกล่องยืนยันที่แจ้งเตือนผลกระทบต่อหมวดย่อยและเนื้อหาที่ผูกอยู่ก่อน เมื่อยืนยันสำเร็จระบบจะดึงข้อมูลตารางใหม่

การสร้างและแก้ไขหมวดหมู่

  1. เข้าฟอร์มที่ /content-category/form โดยระบบแยกโหมดสร้างใหม่กับโหมดแก้ไขจากรหัสหมวดหมู่ใน query string
  2. โหมดแก้ไขจะโหลดข้อมูลเดิมมาเติมลงฟอร์ม หากโหลดไม่สำเร็จระบบจะแจ้งข้อผิดพลาดและพากลับหน้ารายการ
  3. เมื่อพิมพ์ชื่อหมวดหมู่ ระบบสร้าง slug ให้อัตโนมัติโดยแปลงเป็นตัวพิมพ์เล็ก ตัดอักขระที่ไม่ใช่ตัวอักษรหรือตัวเลขออก และแทนช่องว่างด้วยเครื่องหมายขีด การสร้างอัตโนมัติจะทำเฉพาะตอนสร้างใหม่หรือเมื่อยังไม่มี slug เดิม เพื่อไม่ให้ slug ของหมวดที่เผยแพร่แล้วเปลี่ยนไปโดยไม่ตั้งใจ
  4. กรอกข้อมูลที่เหลือ ได้แก่ คำอธิบาย ลำดับการแสดงผล และสถานะ
  5. กดบันทึกเพื่อสร้างหรืออัปเดตหมวดหมู่ เมื่อสำเร็จระบบจะพากลับสู่หน้ารายการ

การนำหมวดหมู่ไปใช้ในฟีเจอร์อื่น

  1. หมวดหมู่ที่มีอยู่ในระบบถูกดึงไปแสดงเป็นตัวเลือกผ่าน endpoint แบบ dropdown ซึ่งคืนค่าเป็นคู่ของชื่อที่ใช้แสดงและรหัสอ้างอิง
  2. หน้าสร้าง/แก้ไขหน้าเนื้อหาใช้รายการนี้เป็นชั้นแรกของการเลือกหมวด แล้วจึงต่อด้วยหมวดย่อยของหมวดที่เลือก
  3. หน้ารายการและฟอร์มของ Content Subcategory ใช้รายการเดียวกันเพื่อระบุว่าหมวดย่อยนั้นอยู่ใต้หมวดใด
  4. หน้า Content Links ใช้เป็นเงื่อนไขกรองรายการลิงก์ตามหมวดหมู่
  5. หมวดหมู่ที่ตั้งสถานะปิดไว้ยังคงอยู่ในระบบและไม่ถูกลบ แต่ควรตรวจสอบก่อนว่าไม่มีเนื้อหาที่ยังต้องใช้งานผูกอยู่

หน้าจอและองค์ประกอบหลัก

หน้ารายการ (/content-category)

  • ส่วนกรองข้อมูล — ช่องค้นหาและตัวเลือกสถานะ ใช้รูปแบบตัวควบคุมมาตรฐานเดียวกับหน้ารายการอื่นในระบบ
  • ตารางหมวดหมู่ — ชื่อ slug จำนวนหมวดย่อย (แสดงเป็นป้ายตัวเลขที่กดเพื่อข้ามไปหน้าหมวดย่อยได้) ลำดับ สถานะ และวันที่อัปเดต รองรับการแบ่งหน้าและการเลื่อนตารางตามความกว้างจอ
  • เมนูการดำเนินการ — แก้ไข ดูหมวดย่อย และลบ
  • กล่องยืนยันการลบ — แจ้งผลกระทบต่อข้อมูลที่เกี่ยวข้องก่อนดำเนินการ

ไฟล์อ้างอิงหลัก: src/app/content-category/page.tsx

หน้าฟอร์ม (/content-category/form)

  • ช่องชื่อหมวดหมู่ — บังคับกรอก และเป็นตัวตั้งต้นของการสร้าง slug อัตโนมัติ
  • ช่อง Slug — บังคับกรอก ตรวจรูปแบบให้ประกอบด้วยตัวพิมพ์เล็ก ตัวเลข และขีดเท่านั้น
  • ช่องคำอธิบาย — ข้อความอธิบายหมวดหมู่แบบหลายบรรทัด
  • ช่องลำดับการแสดงผล — ตัวเลขไม่ติดลบ
  • ตัวเลือกสถานะ — ค่าเริ่มต้นเป็นเปิดใช้งาน

ข้อกำหนดของแต่ละช่องสรุปได้ดังนี้

ช่องข้อกำหนด
ชื่อหมวดหมู่บังคับกรอก ไม่เกิน 255 ตัวอักษร
Slugบังคับกรอก ไม่เกิน 255 ตัวอักษร รูปแบบตัวพิมพ์เล็ก ตัวเลข และขีดเท่านั้น
คำอธิบายไม่บังคับ ไม่เกิน 1,000 ตัวอักษร
ลำดับการแสดงผลตัวเลขตั้งแต่ 0 ขึ้นไป
สถานะเปิด/ปิดใช้งาน ค่าเริ่มต้นคือเปิด

ไฟล์อ้างอิงหลัก: src/app/content-category/form/page.tsx

บริการฝั่ง API

รวมอยู่ที่ src/services/content-category.service.ts ภายใต้ path หลัก content-categories

ความสามารถEndpoint
ดึงรายการหมวดหมู่GET /content-categories
ดึงรายการสำหรับ dropdownGET /content-categories/dropdown
ดึงข้อมูลหมวดหมู่รายตัวGET /content-categories/{id}
สร้างหมวดหมู่POST /content-categories
แก้ไขหมวดหมู่PATCH /content-categories/{id}
ลบหมวดหมู่DELETE /content-categories/{id}

service ยังเตรียม endpoint สำหรับดึงรายการแบบจัดกลุ่มและสถิติสรุปของหมวดหมู่ไว้ด้วย แต่ยังไม่มีหน้าจอใดในระบบเรียกใช้

จุดเชื่อมต่อกับฟีเจอร์อื่น

  • สิทธิ์การใช้งาน — เมนูนี้เป็นเมนูย่อยที่ควบคุมด้วยสิทธิ์โมดูล content-category และจะแสดงได้ต่อเมื่อผู้ใช้มีสิทธิ์เข้าถึงเมนูแม่ content-management ด้วย ทั้งสองปลดล็อกจากโมดูล line-oa ฝั่งหลังบ้าน
  • Content Subcategory — เป็นหมวดแม่ของโครงสร้างต้นไม้หมวดย่อย และเป็นปลายทางของการกดดูหมวดย่อยจากตาราง
  • Content Management — เรียกใช้รายการ dropdown ของหมวดหมู่เพื่อให้ผู้ใช้เลือกหมวดตอนสร้างและแก้ไขหน้าเนื้อหา
  • Content Links — ใช้หมวดหมู่เป็นเงื่อนไขในการกรองรายการลิงก์เนื้อหา
  • ตัวเลือกหมวดหมู่แบบ Cascader — เป็นคอมโพเนนต์ร่วมที่ดึงหมวดหมู่ระดับบนจากโมดูลนี้ แล้วต่อยอดด้วยหมวดย่อยแบบลำดับชั้น
  • โครงสร้างพื้นฐานร่วม — ใช้ HTTP client กลางของ CMS ที่แนบ token ให้อัตโนมัติและออกจากระบบเมื่อ token หมดอายุ พร้อมทั้งใช้ระบบ breadcrumb เมนูด้านข้าง ค่าคงที่ของตาราง/ตัวกรอง และชุดคำแปลหน้าจอร่วมกับโมดูลอื่น

รายละเอียดฝั่ง Backend (CMS API)

โค้ดฝั่ง backend อยู่ที่ internal/modules/contentcategory/ เป็นโมดูลขนาดเล็กที่นอกจาก CRUD ปกติแล้วยังทำหน้าที่เป็น ผู้ให้บริการรายการตัวเลือกหมวดหมู่ ให้หน้าจออื่นอีกหลายหน้า

สิทธิ์ที่ต้องมี

  • ทุก route ต้องผ่านการยืนยันตัวตนกลาง (JWT) แต่ ไม่ได้ครอบด้วย module gate และ policy ที่ประกาศไว้อ้างถึงโมดูล line-oa ซึ่งยังเป็นเพียงข้อมูลกำกับที่ยังไม่บังคับใช้
  • การควบคุมสิทธิ์รายเมนูจึงเกิดขึ้นที่ฝั่งหน้าจอเป็นหลัก ผู้ใช้ที่ล็อกอินแล้วยังเรียก endpoint จัดการหมวดหมู่ได้โดยตรง
  • ข้อมูลถูกจำกัดขอบเขตตาม LINE OA และองค์กรที่กำลังใช้งานอยู่เสมอ

Endpoint ที่ backend มีมากกว่าที่หน้าจอเรียกใช้

นอกจากรายการปกติและ dropdown ที่หน้าจอใช้อยู่ ฝั่ง API ยังเปิดไว้อีกสองตัว

Endpointใช้ทำอะไร
GET /api/content-categories/dropdown-groupคืนรายการตัวเลือกแบบจัดกลุ่ม สำหรับหน้าจอที่ต้องการดรอปดาวน์แบบมีหัวข้อกลุ่ม
GET /api/content-categories/statsคืนสถิติจำนวนคอนเทนต์ต่อหมวดหมู่

หมวดหมู่ที่สร้างไว้ยังถูกนำไปแสดงในเส้นทางสาธารณะสำหรับผู้อ่านด้วย ไม่ได้ใช้เฉพาะในหน้าจอผู้ดูแล

จุดที่ต้องระวังเรื่องการลบ

  • ตาราง content_category ใช้คอลัมน์ประทับเวลาลบแบบธรรมดา ไม่ใช่กลไก soft delete อัตโนมัติของ ORM ทุก query อ่านข้อมูลจึงต้องเขียนเงื่อนไข "ยังไม่ถูกลบ" เองทุกครั้ง หากลืมใส่ในที่ใดที่หนึ่ง หมวดหมู่ที่ลบไปแล้วจะโผล่กลับมาเป็นตัวเลือกในหน้าจออื่น
  • Edge case ที่ตั้งใจคงไว้ — คำสั่งอัปเดตหมวดหมู่ ไม่ได้กรองรายการที่ถูกลบไปแล้วออก (เพื่อคงพฤติกรรมเดิมของระบบก่อนหน้า) ผลคือการแก้ไขด้วยรหัสของหมวดหมู่ที่ถูกลบไปแล้วยังทำได้สำเร็จ ทั้งที่หมวดนั้นจะไม่ปรากฏในรายการใด ๆ
  • การลบตอบกลับเป็นสถานะสำเร็จแบบไม่มีเนื้อหา (204) ไม่ได้คืนข้อมูลของสิ่งที่ถูกลบกลับมา
  • backend ไม่ได้ตรวจการอ้างอิงก่อนลบ คำเตือนเรื่องผลกระทบต่อหมวดย่อยและหน้าเนื้อหาที่เห็นในกล่องยืนยัน เป็นการเตือนจากฝั่งหน้าจอ ไม่ใช่การป้องกันจากฝั่งเซิร์ฟเวอร์ หมวดย่อยและหน้าเนื้อหาที่ผูกไว้จึงอาจกลายเป็นรายการที่อ้างถึงหมวดที่ไม่มีแล้ว

สิ่งที่บันทึกและผลข้างเคียง (Side Effect)

  • ข้อมูลอยู่ในตาราง content_category และอ้างอิงกับ content_subcategory และ content_page
  • โมดูลนี้ไม่ได้เขียน cache และไม่ได้ส่งงานเข้าคิว การเพิ่มหรือแก้หมวดหมู่จึงมีผลกับดรอปดาวน์ในหน้าจออื่นทันทีที่โหลดใหม่
  • การดึงรายการแนบข้อมูลหมวดย่อยมาให้ในผลลัพธ์เดียวกัน จึงไม่ต้องเรียก API เพิ่มเพื่อนับจำนวนหมวดย่อย แต่ก็แปลว่ายิ่งมีหมวดย่อยมาก ผลลัพธ์ของการดึงรายการก็ยิ่งใหญ่ตาม

ข้อสังเกตเชิงเทคนิค

เส้นทางที่เป็นชื่อคงที่อย่าง dropdown, dropdown-group และ stats ถูกลงทะเบียนไว้ก่อนเส้นทางที่รับรหัสหมวดหมู่ เพื่อให้ตัวจัดเส้นทางเลือกได้ถูกตัว ไม่เช่นนั้นคำว่า dropdown จะถูกตีความเป็นรหัสหมวดหมู่ — เป็นรายละเอียดที่ต้องรักษาไว้เมื่อเพิ่ม endpoint ใหม่ในโมดูลนี้