Technology

Directus CMS Feature Flag Management

directus cms feature flag management
Directus CMS Feature Flag Management | SiamCafe Blog
2025-07-17· อ. บอม — SiamCafe.net· 9,034 คำ

Directus Feature Flag

Directus Headless CMS REST GraphQL API Feature Flag Toggle Canary Release A/B Testing Kill Switch Progressive Rollout Role-based Access Webhooks Flows

Feature Flag Typeใช้เมื่อตัวอย่าง
Release Flagปล่อยฟีเจอร์ใหม่New checkout flow
Experiment FlagA/B TestingButton color test
Ops FlagควบคุมระบบMaintenance mode
Permission Flagควบคุมสิทธิ์Premium features
Kill Switchปิดฟีเจอร์ฉุกเฉินDisable payments

Directus Setup และ Feature Flag Schema

# === Directus Feature Flag Setup ===

# Docker Compose
# version: '3.8'
# services:
#   directus:
#     image: directus/directus:latest
#     ports:
#       - "8055:8055"
#     environment:
#       KEY: "random-key-here"
#       SECRET: "random-secret-here"
#       DB_CLIENT: "pg"
#       DB_HOST: "db"
#       DB_PORT: "5432"
#       DB_DATABASE: "directus"
#       DB_USER: "directus"
#       DB_PASSWORD: "directus"
#       ADMIN_EMAIL: "admin@example.com"
#       ADMIN_PASSWORD: "admin123"
#     depends_on:
#       - db
#
#   db:
#     image: postgres:15
#     environment:
#       POSTGRES_DB: directus
#       POSTGRES_USER: directus
#       POSTGRES_PASSWORD: directus
#     volumes:
#       - pgdata:/var/lib/postgresql/data
#
# volumes:
#   pgdata:

# Feature Flag Schema (SQL)
# CREATE TABLE feature_flags (
#   id SERIAL PRIMARY KEY,
#   name VARCHAR(100) UNIQUE NOT NULL,
#   description TEXT,
#   enabled BOOLEAN DEFAULT false,
#   rollout_percentage INT DEFAULT 0,
#   target_users JSONB DEFAULT '[]',
#   target_groups JSONB DEFAULT '[]',
#   metadata JSONB DEFAULT '{}',
#   created_at TIMESTAMP DEFAULT NOW(),
#   updated_at TIMESTAMP DEFAULT NOW()
# );

from dataclasses import dataclass, field
from typing import List, Dict, Optional

@dataclass
class FeatureFlag:
    name: str
    description: str
    enabled: bool
    rollout_pct: int
    target_groups: List[str]
    flag_type: str
    created: str

flags = [
    FeatureFlag("new_checkout", "New checkout flow with Stripe", True, 25,
        ["beta_users", "internal"], "Release", "2024-03-01"),
    FeatureFlag("dark_mode", "Dark mode UI", True, 100,
        ["all"], "Release", "2024-02-15"),
    FeatureFlag("ai_recommendations", "AI product recommendations", True, 10,
        ["premium"], "Experiment", "2024-03-10"),
    FeatureFlag("maintenance_mode", "Enable maintenance page", False, 0,
        ["all"], "Ops", "2024-01-01"),
    FeatureFlag("payment_gateway_v2", "New payment gateway", True, 50,
        ["beta_users"], "Release", "2024-03-05"),
    FeatureFlag("kill_notifications", "Disable push notifications", False, 0,
        ["all"], "Kill Switch", "2024-02-20"),
]

print("=== Feature Flags Dashboard ===")
for f in flags:
    status = "ON" if f.enabled else "OFF"
    groups = ", ".join(f.target_groups)
    print(f"  [{status}] {f.name} ({f.flag_type})")
    print(f"    {f.description}")
    print(f"    Rollout: {f.rollout_pct}% | Groups: {groups}")

API และ SDK Integration

# === Feature Flag API ===

# Directus REST API
# GET /items/feature_flags
# GET /items/feature_flags?filter[name][_eq]=new_checkout
# PATCH /items/feature_flags/1  {"enabled": true, "rollout_percentage": 50}

# Python SDK
# from directus_sdk import DirectusClient
#
# client = DirectusClient("http://localhost:8055", token="YOUR_TOKEN")
#
# # Get all flags
# flags = client.get_items("feature_flags")
#
# # Check flag for user
# def is_enabled(flag_name, user_id=None, user_group=None):
#     flag = client.get_items("feature_flags",
#         params={"filter[name][_eq]": flag_name})
#     if not flag:
#         return False
#     flag = flag[0]
#     if not flag["enabled"]:
#         return False
#     # Check target groups
#     if user_group and flag["target_groups"]:
#         if user_group not in flag["target_groups"] and "all" not in flag["target_groups"]:
#             return False
#     # Check rollout percentage
#     if flag["rollout_percentage"] < 100:
#         import hashlib
#         hash_val = int(hashlib.md5(f"{flag_name}:{user_id}".encode()).hexdigest(), 16)
#         if (hash_val % 100) >= flag["rollout_percentage"]:
#             return False
#     return True

# JavaScript Client
# import { createDirectus, rest, readItems } from '@directus/sdk';
#
# const client = createDirectus('http://localhost:8055').with(rest());
#
# async function getFlag(name) {
#   const flags = await client.request(
#     readItems('feature_flags', {
#       filter: { name: { _eq: name } },
#     })
#   );
#   return flags[0] || null;
# }
#
# // Usage in React
# function FeatureGate({ flag, children, fallback }) {
#   const [enabled, setEnabled] = useState(false);
#   useEffect(() => {
#     getFlag(flag).then(f => setEnabled(f?.enabled));
#   }, [flag]);
#   return enabled ? children : (fallback || null);
# }

import hashlib

def check_rollout(flag_name: str, user_id: str, rollout_pct: int) -> bool:
    hash_val = int(hashlib.md5(f"{flag_name}:{user_id}".encode()).hexdigest(), 16)
    return (hash_val % 100) < rollout_pct

print("\nRollout Simulation (new_checkout at 25%):")
users = [f"user_{i}" for i in range(20)]
enabled_count = sum(1 for u in users if check_rollout("new_checkout", u, 25))
print(f"  {enabled_count}/{len(users)} users enabled ({enabled_count/len(users)*100:.0f}%)")

Flows Automation และ Best Practices

# === Directus Flows for Feature Flags ===

# Flow: Auto-disable flag after date
# Trigger: Schedule (daily)
# Operations:
#   1. Read Items: feature_flags where end_date < today
#   2. Update Items: set enabled = false
#   3. Send Webhook: notify Slack

# Flow: Gradual rollout
# Trigger: Manual
# Operations:
#   1. Read current rollout_percentage
#   2. Increase by 10%
#   3. Wait 1 hour
#   4. Check error rate from monitoring
#   5. If OK: increase again, else rollback to 0%

best_practices = {
    "Naming": [
        "ใช้ snake_case: new_checkout, dark_mode",
        "Prefix ตาม type: release_, exp_, ops_",
        "ชื่อบอก context: payment_gateway_v2",
    ],
    "Lifecycle": [
        "สร้าง Flag ก่อน Deploy code",
        "เปิด Flag ทีละ % (5, 25, 50, 100)",
        "Monitor Metrics ทุกขั้น",
        "ลบ Flag หลังใช้เสร็จ (Technical Debt)",
    ],
    "Testing": [
        "ทดสอบทั้ง ON และ OFF",
        "ทดสอบ Default (Flag ไม่มี)",
        "ทดสอบ Rollout % ถูกต้อง",
        "ทดสอบ Target Groups ถูกกลุ่ม",
    ],
    "Operations": [
        "Kill Switch สำหรับทุกฟีเจอร์สำคัญ",
        "Audit Log ทุกการเปลี่ยนแปลง Flag",
        "Alert เมื่อ Flag เปลี่ยนใน Production",
        "Review Flags ทุกเดือน ลบที่ไม่ใช้",
    ],
}

print("Feature Flag Best Practices:")
for category, tips in best_practices.items():
    print(f"\n  [{category}]")
    for tip in tips:
        print(f"    - {tip}")

# Comparison with dedicated services
comparison = {
    "Directus (DIY)": {"cost": "Free (self-hosted)", "features": "Basic", "setup": "ง่าย"},
    "LaunchDarkly": {"cost": "$10/mo+", "features": "Enterprise", "setup": "SDK ครบ"},
    "Unleash": {"cost": "Free (OSS)", "features": "Advanced", "setup": "ปานกลาง"},
    "Flagsmith": {"cost": "Free (OSS)", "features": "Advanced", "setup": "ปานกลาง"},
}

print(f"\n\nFeature Flag Services:")
for service, info in comparison.items():
    print(f"  [{service}]")
    for k, v in info.items():
        print(f"    {k}: {v}")

เคล็ดลับ

การนำความรู้ไปประยุกต์ใช้งานจริง

แหล่งเรียนรู้ที่แนะนำ ได้แก่ Official Documentation ที่อัพเดทล่าสุดเสมอ Online Course จาก Coursera Udemy edX ช่อง YouTube คุณภาพทั้งไทยและอังกฤษ และ Community อย่าง Discord Reddit Stack Overflow ที่ช่วยแลกเปลี่ยนประสบการณ์กับนักพัฒนาทั่วโลก

เปรียบเทียบข้อดีและข้อเสีย

ข้อดีข้อเสีย
ประสิทธิภาพสูง ทำงานได้เร็วและแม่นยำ ลดเวลาทำงานซ้ำซ้อนต้องใช้เวลาเรียนรู้เบื้องต้นพอสมควร มี Learning Curve สูง
มี Community ขนาดใหญ่ มีคนช่วยเหลือและแหล่งเรียนรู้มากมายบางฟีเจอร์อาจยังไม่เสถียร หรือมีการเปลี่ยนแปลงบ่อยในเวอร์ชันใหม่
รองรับ Integration กับเครื่องมือและบริการอื่นได้หลากหลายต้นทุนอาจสูงสำหรับ Enterprise License หรือ Cloud Service
เป็น Open Source หรือมีเวอร์ชันฟรีให้เริ่มต้นใช้งานต้องการ Hardware หรือ Infrastructure ที่เพียงพอ

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

Directus คืออะไร

Open Source Headless CMS REST GraphQL API Database Admin UI RBAC Webhooks Flows PostgreSQL MySQL Self-hosted Cloud

Feature Flag คืออะไร

เปิด/ปิดฟีเจอร์ไม่ต้อง Deploy Canary Release A/B Testing Kill Switch ลดความเสี่ยง Config แทน Code

Directus ใช้เป็น Feature Flag Service ได้อย่างไร

สร้าง Collection feature_flags API Endpoint Client ดึง Flags Flows Automation Roles สิทธิ์ Webhooks แจ้งเตือน

Feature Flag กับ Feature Toggle ต่างกันไหม

คำเดียวกัน Toggle Boolean เปิด/ปิด Flag Conditions ซับซ้อนกว่า ทางปฏิบัติใช้แทนกัน LaunchDarkly Unleash Flagsmith

สรุป

Directus Headless CMS Feature Flag Toggle REST GraphQL API Canary Release A/B Testing Kill Switch Progressive Rollout Flows Automation Best Practices Lifecycle Cleanup Cache

📖 บทความที่เกี่ยวข้อง

TTS Coqui Feature Flag Managementอ่านบทความ → Directus CMS Event Driven Designอ่านบทความ → Btrfs Filesystem Feature Flag Managementอ่านบทความ → Directus CMS Automation Scriptอ่านบทความ → Directus CMS Metric Collectionอ่านบทความ →

📚 ดูบทความทั้งหมด →