Dashboard
ภาพรวม
Dashboard คือหน้าแรกที่ผู้ดูแล LINE OA เห็นทันทีหลังเลือก channel ที่จะเข้าทำงาน ใช้เป็นจุดเช็กสถานะภาพรวมของเพื่อนใน OA นั้น (จำนวนรวม, สัดส่วนที่ยัง active, สัดส่วนที่ถูกบล็อก) พร้อมดูแนวโน้มย้อนหลัง 7 วัน และรายการแคมเปญที่ตั้งเวลาไว้ล่วงหน้า ก่อนตัดสินใจว่าจะทำอะไรต่อในเมนูอื่น
บทบาทที่ใช้งาน — ทุกคนที่ผ่านการตรวจสิทธิ์ดูข้อมูลแดชบอร์ดฝั่งหน้าเว็บ (ดูรายละเอียดจริงของสิทธิ์นี้ในหัวข้อ สิทธิ์การเข้าถึง ด้านล่าง — ในทางปฏิบัติหมายถึงผู้ใช้ทุกคนที่ล็อกอินและเลือก LINE OA แล้ว)

เส้นทางผู้ใช้งาน
1. เปิดเมนู Dashboard
เลือก LINE OA ที่ต้องการทำงานจากมุมขวาบน (ป้าย "F Test" ในภาพ) ระบบจะพาเข้าหน้า Dashboard ให้โดยอัตโนมัติ หรือคลิกเมนู Dashboard ที่อยู่บนสุดของเมนูซ้ายได้ทุกเมื่อ
2. ดูการ์ดสรุป 3 ใบด้านบน

- Total Friends — ตัวเลขใหญ่แสดงจำนวนเพื่อนสะสมทั้งหมดของ OA ณ ปัจจุบัน พร้อมคำอธิบาย "All registered friends on LINE OA"
- Active Friends — กราฟวงแหวนแบ่งสัดส่วนผู้เยี่ยมชม (Guest) กับสมาชิก (Member) ที่ ยังไม่ถูกบล็อก ในแต่ละกลุ่ม
- Blocked Users — กราฟวงแหวนแบบเดียวกัน แต่แสดงเฉพาะผู้ที่ถูกบล็อกแล้ว แยกเป็นผู้เยี่ยมชมกับสมาชิก (ถ้าไม่มีข้อมูลทั้งสองกลุ่มจะขึ้นวงแหวนสีเทาพร้อมคำว่า "No data")
3. ดูกล่อง "Last 7 Days Activity"

กล่อง Guests (พื้นสีฟ้าอ่อน) และกล่อง Members (พื้นสีม่วงอ่อน) แต่ละกล่องมีตัวเลข Active และ Blocked ของ 7 วันล่าสุด ตัวเลขจะเป็นสีเขียวพร้อมเครื่องหมาย + เมื่อเป็นค่าบวก และเป็นสีแดงเมื่อเป็นค่าลบ — ดูคำอธิบายเชิงลึกของตัวเลขคู่นี้ในหัวข้อ รายละเอียดการคำนวณตัวเลข เพราะมีจุดที่เข้าใจผิดได้ง่าย
4. ดูการ์ด "Upcoming Activities"

- การ์ดนี้ดึงรายการแคมเปญที่มีสถานะ ตั้งเวลาไว้ (Scheduled) ในช่วงตั้งแต่วันนี้ถึงอีก 7 วันข้างหน้า สูงสุด 10 รายการ เรียงจากวันที่ใกล้ที่สุดก่อน
- แต่ละรายการแสดงวันที่ ชื่อแคมเปญ เวลาที่จะส่ง (พร้อมคำกำกับ "Today" / "Tomorrow" หรือวันที่จริง) และป้ายสถานะ คลิกที่รายการเพื่อเปิดฟอร์มแคมเปญนั้นในเมนู Campaign ทันที
- กดปุ่ม View All เพื่อไปดูภาพรวมทั้งหมดที่เมนู Campaign Planner
- ถ้าไม่มีแคมเปญตั้งเวลาไว้เลย (ตามภาพ) จะขึ้นสถานะว่างพร้อมปุ่ม Create Campaign พาไปที่หน้ารายการของเมนู Campaign เพื่อสร้างแคมเปญใหม่
5. ดูกราฟ "Friends Growth Trend"

กราฟเส้นแสดง 3 เส้น (Total Friends, Members, Guests) ของ 7 วันล่าสุด — ตัวเลขต้นสัปดาห์และท้ายสัปดาห์เป็นข้อมูลจริง แต่จุดระหว่างกลางเป็นการคำนวณเส้นตรงเฉลี่ยขึ้นมาเอง ไม่ใช่ยอดจริงของแต่ละวัน เพราะฝั่งเซิร์ฟเวอร์ยังไม่มี endpoint ที่คืนยอดรายวันให้ (ดูยืนยันในหัวข้อจุดที่ควรระวังด้านล่าง)
6. ดูกราฟ "Activity Overview"

กราฟแท่งเปรียบเทียบ "เพื่อนใหม่" กับ "ผู้ถูกบล็อก" รายวันของ 7 วันล่าสุด (ในภาพยังไม่มีข้อมูลเพราะยอดรวมทั้งสัปดาห์เป็น 0) — เช่นเดียวกับกราฟเส้นด้านบน ตัวเลขรายวันในกราฟนี้เป็นค่าที่สุ่มกระจายขึ้นใหม่ทุกครั้งที่วาดหน้าจอใหม่ โดยคงผลรวมทั้งสัปดาห์ให้ตรงกับข้อมูลจริงเท่านั้น
รายละเอียดการคำนวณตัวเลข (ตรวจสอบจากซอร์สโค้ดจริง)
ยืนยันจากโมดูล internal/modules/dashboard/service.go ของ line-management-cms-api-go — ทุกยอดนับใช้เงื่อนไขฐานร่วมกัน 3 ข้อกับตาราง line_user คือ (1) line_oa_id ตรงกับ OA ที่กำลังทำงานอยู่ (2) created_date ไม่เกินวันที่ที่ต้องการดู (3) user_id IS NOT NULL (ต้องผูกกับผู้ใช้ LINE จริงแล้ว) และไม่รวมแถวที่ลบแบบ soft delete โดยอัตโนมัติ
จุดที่ควรรู้เพื่ออ่านตัวเลขให้ถูก:
memberและguestที่ API ส่งกลับมา คือยอดสะสมทั้งหมดของแต่ละกลุ่ม (รวมทั้งที่ยัง active และที่ถูกบล็อกไปแล้ว) ไม่ใช่ยอด active เพียว ๆ — การ์ด Active Friends ที่หน้าเว็บหักยอดบล็อกออกให้เห็นเฉพาะ active จริง (member - totalBlockedMembers,guest - totalBlockedGuests) ส่วนตัวเลขดิบจาก API ยังคงรวมทั้งสองกลุ่มไว้ด้วยกันblockGuest/blockMemberเป็นคนละตัวชี้วัดกับtotalBlockedGuests/totalBlockedMembers— สองตัวหลังนับจากสถานะ follow ปัจจุบัน (follow = No) ณ วันนั้น ส่วนblockGuest/blockMemberนับจากคนที่มีunfollow_dateอยู่ในหรือก่อนวันนั้น เป็นตัวที่การ์ด "Last 7 Days Activity" ใช้แสดงคอลัมน์ Blocked- ตัวเลข "Active" ในกล่อง Last 7 Days Activity ไม่ได้หักยอดบล็อกออก — เป็นเพียงส่วนต่าง (valueDiff = ยอดปลายช่วง − ยอดต้นช่วง) ของ
memberหรือguestแบบดิบที่รวมทั้งสองกลุ่มไว้ด้วยกันตามข้อด้านบน จึงเป็นคนละความหมายกับตัวเลข active ในการ์ด Active Friends ที่อยู่แถวบนสุด — ห้ามนำตัวเลขทั้งสองส่วนมาเทียบกันตรง ๆ percentDiffคำนวณจาก(ยอดปลายช่วง − ยอดต้นช่วง) / (ยอดปลายช่วง หรือ 1 ถ้าเป็น 0) × 100แต่ปัจจุบันหน้าเว็บยังไม่ได้นำค่านี้มาแสดงผลที่ใดเลย
เมนูที่เกี่ยวข้องกันในเส้นทางนี้
- Campaign — แหล่งข้อมูลของการ์ด "Upcoming Activities" และปลายทางของปุ่ม Create Campaign / การคลิกรายการแคมเปญ
- Campaign Planner — ปลายทางของปุ่ม View All มุมมองปฏิทินของแคมเปญชุดเดียวกัน
จุดที่ควรระวัง
- กราฟเส้น (Friends Growth Trend) และกราฟแท่ง (Activity Overview) ไม่ใช่ข้อมูลรายวันจริง โค้ดฝั่งหน้าเว็บมีคอมเมนต์ระบุตรงว่า
"Note: Replace this with actual daily data when backend supports it"— กราฟเส้นใช้การประมาณค่าเชิงเส้น (linear interpolation) ระหว่างยอดต้นสัปดาห์กับปลายสัปดาห์ ส่วนกราฟแท่งสุ่มกระจายผลต่างรายสัปดาห์ลงในแต่ละวันใหม่ทุกครั้งที่วาดหน้าจอ (ตัวเลขรายวันจึงเปลี่ยนไปเรื่อย ๆ แม้ข้อมูลจริงไม่เปลี่ยน) มีเพียงยอดรวมทั้งสัปดาห์เท่านั้นที่ตรงกับข้อมูลจริง - ตัวกรองช่วงวันที่มีอยู่ในโค้ดแต่ยังไม่เปิดให้ใช้จริง — หน้า Dashboard เตรียม state และฟังก์ชัน
onChangeDateไว้ในไฟล์dashboard.tsxแล้ว แต่ยังไม่มี date-range picker ใด ๆ วางอยู่บนหน้าจอให้ผู้ใช้กด ในทางปฏิบัติหน้านี้จึงล็อกช่วงเวลาไว้ที่ 7 วันล่าสุดเสมอ - มีฟีเจอร์ "Top Rich Menu" หลงเหลืออยู่ในซอร์สโค้ดแต่ไม่ได้แสดงผลจริง — พบไฟล์
TopRichMenu.tsx,dashboard-top-list.container.tsxและฟังก์ชันgetTopRichMenu()(เรียก/dashboard/top-rich-menu) อยู่ในโค้ดฝั่งหน้าเว็บ แต่ไม่ถูก import ไปใช้ในหน้า Dashboard จริงเลย และฝั่ง backend ก็ไม่ได้ลงทะเบียน route นี้ไว้ด้วยซ้ำ — คอมเมนต์ในซอร์ส backend ยืนยันว่า endpoint นี้ "ถูกปิดไว้ตั้งแต่ระบบเดิม" (disabled in TS) จึงเป็นโค้ดที่หลงเหลือ ไม่มีผลต่อผู้ใช้งานจริงในหน้าจอปัจจุบัน - หากตัวเลขเพื่อนดูไม่ตรงกับความเป็นจริง ต้นเหตุมักอยู่ที่ระบบซิงก์ผู้ติดตามหรือ webhook ที่อัปเดตตาราง
line_userไม่ใช่ที่หน้า Dashboard เอง เพราะหน้านี้เป็นเพียงตัวนับข้อมูลที่มีอยู่ ณ ขณะนั้น
สิทธิ์การเข้าถึง (ตรวจสอบจากซอร์สโค้ดจริง)
- ฝั่งหน้าเว็บ — หน้า Dashboard ถูกครอบด้วย
PermissionGuardตรวจ actionVIEWของ subjectdashboard(ไฟล์src/app/dashboard/page.tsx) ก่อน render เนื้อหา ถ้าไม่ผ่านจะไม่เห็นทั้งเมนูและหน้านี้ - ฝั่งเซิร์ฟเวอร์ — มี endpoint จริงเพียงตัวเดียวคือ
GET /api/dashboard/total-friendsต้องผ่าน JWT กลางที่บังคับกับทุกเส้นทางที่ไม่ประกาศเป็น public และมี policy annotation ประกาศไว้ว่าต้องมีสิทธิ์readของโมดูลdashboard— แต่ middleware ที่ตรวจ policy นี้ถูกเขียนให้เป็น no-op โดยเจตนา คอมเมนต์ในซอร์สระบุตรงว่า"Enforcement disabled — allow all authenticated requests (TS parity)"เพื่อคงพฤติกรรมเดิมของระบบ NestJS ต้นทางที่ปิดการบังคับสิทธิ์ระดับนี้ไว้ทั้งระบบ - ผลคือผู้ใช้ที่ล็อกอินสำเร็จและมี LINE OA ผูกกับ token แล้ว เรียก endpoint นี้ได้เสมอไม่ว่าสิทธิ์ย่อยจะเป็นอย่างไร การซ่อนเมนู/หน้าฝั่งหน้าเว็บจึงเป็นเพียงการควบคุมสิ่งที่ผู้ใช้ทั่วไปมองเห็น ไม่ใช่การปิดกั้นที่ตัว API จริง
ไฟล์อ้างอิงจากซอร์สโค้ด
Frontend (cms-web-2026)
src/app/dashboard/page.tsx— จุดเข้าหน้า, ตัวครอบสิทธิ์src/components/dashboard/dashboard.tsx,dashboard.container.tsx— โครงหน้าและ state ตัวกรองวันที่ (ยังไม่มี UI ให้ใช้)src/components/dashboard/dashboard-chart/—dashboard-chart.container.tsx(ดึงข้อมูลและคำนวณ),dashboard-chart.tsx(จัดวาง),pie-card.tsx,score-card.tsxsrc/components/dashboard/charts/—friends-growth-chart.tsx,activity-bar-chart.tsx,doughnut-chart.tsxsrc/components/dashboard/upcoming-activities/— ตัวควบคุมและ UI ของการ์ดกิจกรรมที่กำลังจะถึงsrc/services/dashboard.service.ts— เรียกGET /dashboard/total-friends(และgetTopRichMenuที่ไม่ถูกใช้งานจริง)
Backend (line-management-cms-api-go)
internal/modules/dashboard/controller.go— ลงทะเบียนเส้นทางเดียวคือGET /dashboard/total-friendsinternal/modules/dashboard/service.go— ตรรกะการนับและเปรียบเทียบยอดinternal/modules/dashboard/dto.go,types.go— โครงสร้างพารามิเตอร์และผลลัพธ์internal/modules/auth/policy.go— จุดที่ยืนยันว่าCheckPoliciesเป็น no-op ทั้งระบบ
ดูรายละเอียดเชิงเทคนิคเพิ่มเติม (เวอร์ชันก่อนหน้าของทีมเอกสาร) ที่ หน้าแดชบอร์ด