API สาธารณะสำหรับผู้ใช้ปลายทาง
ภาพรวม
โมดูล publicmod รวม endpoint ที่ผู้ใช้ LINE ทั่วไปเรียกได้โดยไม่ต้องล็อกอินเข้า CMS ผู้บริโภคหลักคือ client-web ซึ่งใช้ตอน render หน้าคอนเทนต์และเมนูที่ถูกแชร์ผ่าน LINE
เนื่องจากเปิดให้เข้าถึงแบบสาธารณะ endpoint กลุ่มที่คืนรายการคอนเทนต์จึงถูกครอบด้วย rate limit ที่ 10 ครั้งต่อ 60 วินาที ส่วน endpoint ที่เข้าถึงด้วย token ไม่ถูกจำกัด เพราะตัว token เองเดาไม่ได้อยู่แล้ว
โมดูลนี้ยังรองรับ LIFF โดยคืน config ให้ client-web ใช้ initialize LIFF และรับ header x-liff-token เพื่อระบุตัวผู้ใช้ LINE ที่กำลังเปิดหน้าอยู่
Business Flow
เรียกดูรายการคอนเทนต์
GET /api/public/contentsพร้อม query ตามPublicContentQueryDtoคืนรายการคอนเทนต์ที่เผยแพร่แล้ว ในรูปแบบที่มี fielddata,total,page,limitและtotalPagesโดยถูก throttle ที่ 10 ครั้งต่อ 60 วินาทีGET /api/public/contents/categoriesพร้อม querylineOaIdคืนรายการหมวดหมู่ที่มีคอนเทนต์อยู่ ถูก throttle เช่นเดียวกัน
เปิดด้วย token
GET /api/public/menu/:tokenเปิดเมนูที่สร้างจาก Menu BuilderGET /api/public/content/:token/liff-configคืน LIFF config ของหน้านั้น เพื่อให้ client-web เรียกliff.init()ก่อนโหลดเนื้อหาGET /api/public/content/:tokenพร้อม querypasswordเปิดหน้าคอนเทนต์- หากส่ง header
x-liff-tokenมาด้วย ระบบจะใช้ระบุตัวผู้ใช้ LINE เพื่อบันทึกการเข้าชมแบบระบุตัวตนได้ - หน้าที่ตั้งรหัสผ่านไว้ต้องส่ง
passwordให้ถูกต้อง - หากไม่พบหน้าหรือหน้ายังไม่เผยแพร่จะได้ error
APP_007
- หากส่ง header
ข้อควรรู้เรื่อง soft delete
- ตาราง
content_page,content_categoryและcontent_subcategoryใช้คอลัมน์deleted_dateธรรมดา service จึงต้องใส่ predicate กรองแถวที่ถูกลบเอง เพราะ TypeORM ไม่ได้กรองให้อัตโนมัติ - ตาราง
line_oaมี@DeleteDateColumnจริง GORM จึงกรองให้อัตโนมัติ ส่วนเงื่อนไขdeletedAt: IsNull()ที่ปรากฏใน where ของโค้ด TypeScript เดิมชี้ไปยัง property ที่ไม่มีอยู่จริง จึงเป็น no-op
ไฟล์และฟังก์ชันหลัก
โค้ดอยู่ที่ internal/modules/publicmod/ ประกอบด้วย controller.go, service.go, liff.go และ dto.go
| Method | Route | Handler | Guard |
|---|---|---|---|
| GET | /api/public/contents | ct.listPublicContents | public + Throttle(10, 60000) |
| GET | /api/public/contents/categories | ct.listPublicCategories | public + Throttle(10, 60000) |
| GET | /api/public/menu/:token | ct.getMenuByToken | public |
| GET | /api/public/content/:token/liff-config | ct.getContentLiffConfig | public |
| GET | /api/public/content/:token | ct.getContentByToken | public |
route แบบ static ถูก register ก่อน route ที่มี :token เพื่อให้ gin resolve ไปยัง handler ที่ถูกต้อง และ RegisterRoutes ใช้เฉพาะ group public โดยมีบรรทัด _ = authed ยืนยันว่าไม่ได้ใช้ group authed
นอกจากนี้ยังมี endpoint สาธารณะที่อยู่ในโมดูลอื่นเป็นเส้นทางคู่ขนาน
| Route | โมดูล |
|---|---|
GET /api/public/content-pages/:token | Content Page |
POST /api/public/content-pages/:token/track | Content Page |
GET /api/menu-builder/public/:token | Menu Builder |
จุดเชื่อมต่อกับ Service อื่น
- สิทธิ์การเข้าถึง — ไม่มีการตรวจสิทธิ์ เพราะเป็น public ทั้งหมด ป้องกันด้วยกลไก token ที่เดาไม่ได้ร่วมกับ throttle แทน
- ตารางที่เกี่ยวข้อง —
content_page,content_page_translation,content_category,content_subcategory,content_link,menu_builderและline_oa - Middleware —
middleware.Throttle(10, 60000)(ดู Core HTTP Platform) - LIFF — ไฟล์
liff.goตรวจสอบx-liff-tokenและคืน config ให้ client-web - ผู้บริโภค — client-web-2026
- โมดูลที่เกี่ยวข้อง — Content Page, Content Link, Menu Builder และ Content Category