หน้าคอนเทนต์
ภาพรวม
Domain นี้มี 5 ตาราง: content_page เป็นตารางหลักเก็บข้อมูลหน้าคอนเทนต์ (slug, สถานะ,
การควบคุมการเข้าถึง, สถิติ) ส่วนอีก 4 ตารางเป็นส่วนขยายที่อ้างอิงกลับมาที่ content_page_id ได้แก่
content_page_translation (เนื้อหาและ SEO แยกตามภาษา), content_page_utm (พารามิเตอร์ UTM
แบบ 1:1), content_page_analytics (สคริปต์ tracking แบบ 1:1) และ content_page_view
(log การเข้าชมรายครั้ง)
ตาราง content_page
| Column | Type | Nullable | Default | คำอธิบาย |
|---|---|---|---|---|
id | SERIAL | NO | nextval(...) | Primary key |
uuid | UUID | NO | gen_random_uuid() | รหัสอ้างอิงภายนอกของหน้า (unique) |
line_oa_id | INTEGER | NO | - | LINE OA ที่หน้านี้สังกัด (FK ไป line_oa.id) |
user_id | INTEGER | NO | - | ผู้ใช้เจ้าของหน้า |
organization_id | INTEGER | NO | - | องค์กรเจ้าของหน้า |
slug | VARCHAR(255) | NO | - | slug ของหน้าใน URL |
status | ContentPageStatus (ENUM) | NO | draft | สถานะหน้า: draft, published, archived |
version | INTEGER | NO | 1 | เลขเวอร์ชันของหน้า |
public_token | VARCHAR(255) | YES | - | โทเคนสำหรับเปิดหน้าแบบสาธารณะ (unique) |
require_auth | BOOLEAN | NO | false | ต้องล็อกอินก่อนเข้าดูหน้านี้หรือไม่ |
password_protected | BOOLEAN | NO | false | ป้องกันด้วยรหัสผ่านหรือไม่ |
password_hash | VARCHAR(255) | YES | - | ค่า hash ของรหัสผ่านที่ใช้ป้องกันหน้า |
published_at | TIMESTAMPTZ(3) | YES | - | วันเวลาที่เผยแพร่ |
published_by | INTEGER | YES | - | ผู้เผยแพร่ (user id) |
archived_at | TIMESTAMPTZ(3) | YES | - | วันเวลาที่เก็บเข้าคลัง (archive) |
archived_by | INTEGER | YES | - | ผู้เก็บเข้าคลัง (user id) |
view_count | BIGINT | NO | 0 | จำนวนการเข้าชมทั้งหมด |
unique_view_count | BIGINT | NO | 0 | จำนวนผู้เข้าชมที่ไม่ซ้ำ |
category_id | INTEGER | YES | - | หมวดหมู่ของหน้า (FK ไป content_category.id) |
subcategory_id | INTEGER | YES | - | หมวดหมู่ย่อยของหน้า (FK ไป content_subcategory.id) |
audience_ids | JSONB | YES | '[]' | รายการ audience ที่กำหนดให้เห็นหน้านี้ |
friend_track_campaign_id | INTEGER | YES | - | แคมเปญ Friend Track ที่ผูกกับหน้านี้ (FK ไป friend_track_campaign.id) |
friend_track_button_text | VARCHAR(255) | YES | - | ข้อความบนปุ่ม Friend Track ที่แสดงในหน้า |
created_date | TIMESTAMPTZ(3) | NO | now() | วันเวลาที่สร้าง |
created_by | INTEGER | NO | - | ผู้สร้าง (user id) |
updated_date | TIMESTAMPTZ(3) | NO | now() | วันเวลาที่แก้ไขล่าสุด |
updated_by | INTEGER | NO | - | ผู้แก้ไขล่าสุด (user id) |
deleted_date | TIMESTAMPTZ(3) | YES | - | วันเวลาที่ลบ (soft delete) |
deleted_by | INTEGER | YES | - | ผู้ลบ (user id) |
ตาราง content_page_translation
| Column | Type | Nullable | Default | คำอธิบาย |
|---|---|---|---|---|
id | SERIAL | NO | nextval(...) | Primary key |
content_page_id | INTEGER | NO | - | หน้าคอนเทนต์ที่คำแปลนี้สังกัด (FK ไป content_page.id) |
language | VARCHAR(10) | NO | - | รหัสภาษาของคำแปล เช่น th, en |
title | VARCHAR(500) | NO | - | หัวเรื่องของหน้าในภาษานี้ |
content | TEXT | YES | - | เนื้อหาของหน้าในภาษานี้ |
excerpt | TEXT | YES | - | เนื้อหาย่อ/คำโปรยของหน้า |
meta_title | VARCHAR(160) | YES | - | SEO meta title |
meta_description | VARCHAR(320) | YES | - | SEO meta description |
meta_keywords | TEXT | YES | - | SEO meta keywords |
og_title | VARCHAR(160) | YES | - | Open Graph title สำหรับการแชร์ |
og_description | VARCHAR(320) | YES | - | Open Graph description สำหรับการแชร์ |
og_image_url | TEXT | YES | - | URL รูปภาพ Open Graph |
twitter_card | VARCHAR(50) | YES | - | ประเภท Twitter card |
created_date | TIMESTAMPTZ(3) | NO | now() | วันเวลาที่สร้าง |
created_by | INTEGER | NO | - | ผู้สร้าง (user id) |
updated_date | TIMESTAMPTZ(3) | NO | now() | วันเวลาที่แก้ไขล่าสุด |
updated_by | INTEGER | NO | - | ผู้แก้ไขล่าสุด (user id) |
ตาราง content_page_utm
| Column | Type | Nullable | Default | คำอธิบาย |
|---|---|---|---|---|
id | SERIAL | NO | nextval(...) | Primary key |
content_page_id | INTEGER | NO | - | หน้าคอนเทนต์ที่ผูกอยู่ (unique — ความสัมพันธ์แบบ 1:1) |
utm_source | VARCHAR(255) | YES | - | ค่า UTM source เริ่มต้นของหน้า |
utm_medium | VARCHAR(255) | YES | - | ค่า UTM medium เริ่มต้นของหน้า |
utm_campaign | VARCHAR(255) | YES | - | ค่า UTM campaign เริ่มต้นของหน้า |
utm_term | VARCHAR(255) | YES | - | ค่า UTM term เริ่มต้นของหน้า |
utm_content | VARCHAR(255) | YES | - | ค่า UTM content เริ่มต้นของหน้า |
created_date | TIMESTAMPTZ(3) | NO | now() | วันเวลาที่สร้าง |
created_by | INTEGER | NO | - | ผู้สร้าง (user id) |
updated_date | TIMESTAMPTZ(3) | NO | now() | วันเวลาที่แก้ไขล่าสุด |
updated_by | INTEGER | NO | - | ผู้แก้ไขล่าสุด (user id) |
ตาราง content_page_analytics
| Column | Type | Nullable | Default | คำอธิบาย |
|---|---|---|---|---|
id | SERIAL | NO | nextval(...) | Primary key |
content_page_id | INTEGER | NO | - | หน้าคอนเทนต์ที่ผูกอยู่ (unique — ความสัมพันธ์แบบ 1:1) |
ga_events | JSONB | YES | - | การตั้งค่า event ของ Google Analytics |
fb_pixel_events | TEXT | YES | - | การตั้งค่า event ของ Facebook Pixel |
line_tag_events | TEXT | YES | - | การตั้งค่า event ของ LINE Tag |
custom_head_scripts | TEXT | YES | - | สคริปต์เพิ่มเติมที่แทรกในส่วน head ของหน้า |
custom_body_scripts | TEXT | YES | - | สคริปต์เพิ่มเติมที่แทรกในส่วน body ของหน้า |
enable_ga | BOOLEAN | NO | true | เปิดใช้งาน Google Analytics หรือไม่ |
enable_fb_pixel | BOOLEAN | NO | false | เปิดใช้งาน Facebook Pixel หรือไม่ |
enable_line_tag | BOOLEAN | NO | false | เปิดใช้งาน LINE Tag หรือไม่ |
created_date | TIMESTAMPTZ(3) | NO | now() | วันเวลาที่สร้าง |
created_by | INTEGER | NO | - | ผู้สร้าง (user id) |
updated_date | TIMESTAMPTZ(3) | NO | now() | วันเวลาที่แก้ไขล่าสุด |
updated_by | INTEGER | NO | - | ผู้แก้ไขล่าสุด (user id) |
ตาราง content_page_view
| Column | Type | Nullable | Default | คำอธิบาย |
|---|---|---|---|---|
id | SERIAL | NO | nextval(...) | Primary key |
content_page_id | INTEGER | NO | - | หน้าคอนเทนต์ที่ถูกเข้าชม (FK ไป content_page.id) |
viewer_ip | VARCHAR(45) | YES | - | IP address ของผู้เข้าชม (รองรับ IPv6) |
viewer_user_agent | TEXT | YES | - | User agent ของผู้เข้าชม |
viewer_referrer | TEXT | YES | - | URL ต้นทางที่ผู้เข้าชมมา (referrer) |
viewer_line_uid | VARCHAR(255) | YES | - | LINE user id ของผู้เข้าชม (ถ้าระบุตัวตนได้) |
utm_source | VARCHAR(255) | YES | - | ค่า UTM source ที่ติดมากับการเข้าชม |
utm_medium | VARCHAR(255) | YES | - | ค่า UTM medium ที่ติดมากับการเข้าชม |
utm_campaign | VARCHAR(255) | YES | - | ค่า UTM campaign ที่ติดมากับการเข้าชม |
utm_term | VARCHAR(255) | YES | - | ค่า UTM term ที่ติดมากับการเข้าชม |
utm_content | VARCHAR(255) | YES | - | ค่า UTM content ที่ติดมากับการเข้าชม |
session_id | VARCHAR(255) | YES | - | รหัส session ของผู้เข้าชม (ใช้นับ unique view) |
language | VARCHAR(10) | YES | - | ภาษาที่ผู้เข้าชมใช้เปิดหน้า |
device_type | VARCHAR(50) | YES | - | ประเภทอุปกรณ์ของผู้เข้าชม |
viewed_at | TIMESTAMPTZ(3) | NO | now() | วันเวลาที่เข้าชม |
หมายเหตุ
content_pageมี unique constraint บน (line_oa_id,slug) — slug ห้ามซ้ำภายใน OA เดียวกัน แต่ต่าง OA ใช้ slug เดียวกันได้content_page.public_tokenและcontent_page.uuidต่างก็มี unique constraint- ตารางลูกทั้ง 4 ตารางมี FK ไปยัง
content_page.idพร้อมON DELETE CASCADE— ลบหน้าแล้ว คำแปล/UTM/analytics/log การเข้าชมจะถูกลบตามทั้งหมด content_page_utm.content_page_idและcontent_page_analytics.content_page_idมี unique constraint จึงเป็นความสัมพันธ์แบบ 1:1 กับcontent_pagecontent_page_translationมี unique constraint บน (content_page_id,language) — หนึ่งหน้ามีคำแปลได้ภาษาละหนึ่งชุดcontent_page.friend_track_campaign_idเป็น FK ไปfriend_track_campaign.idแบบON DELETE SET NULL— ลบแคมเปญแล้วหน้ายังอยู่แต่ค่าจะกลายเป็น NULLcontent_page.category_id/subcategory_idเป็น FK ไปcontent_category.idและcontent_subcategory.id(ดู หมวดหมู่คอนเทนต์และลิงก์รวม)content_page.view_countและunique_view_countเป็น counter ที่สรุปจากcontent_page_viewซึ่งเก็บ log รายครั้ง โดยมี index บนcontent_page_id,session_idและviewed_at