Software QA, Automated Testing Sandbox & Code Audit สำหรับ AI Desktop Plugins

2026-09-18
2026-09-21
--
--

บทนำและภาพรวมเชิงบริหาร (Executive Summary)#

ในยุคที่ Autonomous AI Agents เข้ามามีบทบาทสำคัญในการพัฒนาซอฟต์แวร์ ส่วนขยายเดสก์ท็อป (AI Desktop Plugins) เช่น hermes-omniroute (ปลั๊กอินมอนิเตอร์ Quota และ Real-time Call Logs) และ hermes-maxplus-credit (ปลั๊กอินตรวจสอบยอดเครดิตและคีย์ราย Pool) ต้องทำงานในสภาวะที่มีความซับซ้อนสูง: รับส่งข้อมูลแบบ Asynchronous ตลอดเวลา เชื่อมต่อกับ AI Gateway หลากหลายค่าย และประมวลผลข้อมูลการเงิน/โทเค็นที่ห้ามเกิดข้อผิดพลาด

บทความนี้นำเสนอแนวคิดและสถาปัตยกรรม Automated QA & Code Audit 5 ชั้น (5-Layer QA Architecture) ที่ออกแบบมาโดยเฉพาะสำหรับ Desktop Plugins โดยผสานการรัน Node.js VM Isolation Sandbox, การทำ Boundary Fuzzing, การป้องกัน Polymorphic API Contracts, การสแกน Git Secret & PII Leak ตลอดจนการทำ Manifest Validation CI

ผลลัพธ์จากการนำระบบ QA นี้ไปใช้งานจริงกับปลั๊กอิน Production:

  • hermes-omniroute: ผ่านการทดสอบ 133/133 เคส (100% Pass Rate) ครอบคลุม 8 Test Suites
  • hermes-maxplus-credit: ผ่านการทดสอบ 64/65 เคส (98.5% Pass Rate) พร้อมดักจับข้อบกพร่องระดับลึกเรื่อง IEEE-754 Floating-Point Precision และแก้ปัญหา Zero-Crash ได้สำเร็จก่อนขึ้น Official Catalog

ปัญหาและที่มา: ทำไม Visual/UI Testing เพียงอย่างเดียวถึงล้มเหลว (The Problem)#

การทดสอบแอปพลิเคชันส่วนขยายของ Agent ด้วยการเปิด UI แล้วคลิกทดสอบด้วยตา (Manual UI Testing หรือ Visual QA) มักก่อให้เกิด ความเสี่ยงแฝง (Silent Failure) ในระดับ Production ด้วยเหตุผลสำคัญ 4 ประการ:

┌─────────────────────────────────────────────────────────────────────────────┐
│ ข้อจำกัดของการทดสอบแบบ Visual Testing เพียงอย่างเดียว │
├───────────────────────────────┬─────────────────────────────────────────────┤
│ 1. ความผันผวนของ API Payload │ เกตเวย์ส่ง Schema ไม่นิ่ง (null/undefined/shape เปลี่ยน)│
│ 2. Silent UI Bricking │ Uncaught TypeError เพียงจุดเดียวทำให้จอขาวทั้งแอป │
│ 3. Asynchronous Race & Time │ การนับถอยหลังรีเซ็ตโควตาและการตัดรอบเวลาเสี่ยงต่อบั๊ก │
│ 4. Transport & Secret Leak │ การหลุดของ API Keys ผ่าน Log, Error Trace หรือ Git Blobs│
└───────────────────────────────┴─────────────────────────────────────────────┘
  1. ความผันผวนของโครงสร้างข้อมูล (Polymorphic API Payloads): Upstream AI Gateway และ Proxy มักมีการปรับเปลี่ยนโครงสร้าง JSON response โดยไม่แจ้งล่วงหน้า เช่น การสลับระหว่าง { total_cost: 0.05 }, { totals: { used_usd: 0.05 } } หรือส่งฟิลด์เป็น null ซึ่งหากไม่มีการตรวจรับข้อมูลแบบ Defensive Parsing ตัว Plugin จะเกิด TypeError: Cannot read properties of undefined ทันที
  2. การพังทลายแบบเงียบ (Silent UI Bricking): ในสถาปัตยกรรม Desktop UI ที่เรนเดอร์ผ่าน React/JSX runtime หาก Pure Function หรือ Formatter เกิด Throw Exception ระหว่างเรนเดอร์ จะทำให้ Component Tree พังทลาย (Crash to White Screen) และส่งผลกระทบต่อ Status Bar ของระบบ Agent ทั้งหมด
  3. ปัญหาขอบเขตเวลาและ Race Conditions: ฟังก์ชันจำพวก formatCountdown หรือการคำนวณ Burn Rate ต้องรองรับสภาวะเวลาในอดีต, เวลาน้อยกว่า 1 วินาที, ความต่างของ Timezone และการ Poll ข้อมูลซ้ำซ้อน ซึ่งเป็นไปไม่ได้ที่จะดักจับได้ครบถ้วนด้วยการคลิกบนหน้าจอ
  4. ความเสี่ยงข้อมูลความลับรั่วไหล (Secret & Transport Poisoning): การส่งข้อมูล Token หรือ Authorization Header ผ่านกระบวนการพัฒนาและแชร์โค้ด หากไม่มี Automated Reconnaissance อาจทำให้ติด Credential หรือ Token ลงในประวัติ Git หรือถูก Security Filter ดักตัดจนโค้ดทำงานผิดพลาด

สถาปัตยกรรม QA 5 ชั้น (The 5-Layer QA Architecture)#

เพื่อให้ปลั๊กอินมีความเสถียรสูงสุด จึงได้วางโครงสร้างกระบวนการตรวจสอบคุณภาพซอฟต์แวร์ออกเป็น 5 ชั้นที่ทำงานประสานกันอย่างเป็นระบบ:

┌─────────────────────────────────────────────────────────────────────────────┐
│ 5-Layer Software QA & Testing Architecture │
├─────────────────────────────────────────────────────────────────────────────┤
│ Layer 1: Pure Logic Sandbox (Isolated Node.js VM Context) │
│ ├─ แยก Pure Functions ออกจาก UI Runtime (React/DOM-independent) │
│ └─ โหลดซอร์สโค้ดเข้า vm.createContext ป้องกัน Side-effects ระดับ Global │
├─────────────────────────────────────────────────────────────────────────────┤
│ Layer 2: Boundary Fuzzing & Anomaly Injection │
│ ├─ ทดสอบค่าขอบเขตวิกฤต: null, undefined, NaN, Infinity, -Infinity │
│ └─ ทดสอบค่าสตริงผิดรูปแบบ, ทศนิยมยาวผิดปกติ, วินาทีติดลบ │
├─────────────────────────────────────────────────────────────────────────────┤
│ Layer 3: API Contract Defense & Schema Normalization │
│ ├─ ตรวจสอบ Layered Fallback Resolvers ป้องกัน Schema Drift │
│ └─ บังคับใช้ Type Checking (typeof v === 'number') และ Nullish Coalescing │
├─────────────────────────────────────────────────────────────────────────────┤
│ Layer 4: Secret Scanning & Pre-Share Reconnaissance │
│ ├─ สแกน Regex ตรวจหา Credentials (ccsk-, ccmk-, Bearer, Machine Paths) │
│ └─ ตรวจสอบ All Git Historical Blobs และทำ Sanitization สำหรับ Commit Author │
├─────────────────────────────────────────────────────────────────────────────┤
│ Layer 5: Ecosystem Manifest CI & Distribution Gate │
│ ├─ ตรวจสอบความถูกต้องของ Schema plugin.yaml ตามมาตรฐาน Plugin SDK │
│ └─ ทดสอบ Deep-link Protocol (hermes://plugin/install) และ Zero-write rule │
└─────────────────────────────────────────────────────────────────────────────┘

Layer 1: Pure Logic Sandbox (Node.js VM Isolation)#

ทำการแยกฟังก์ชันคำนวณและแปลงข้อมูล (Pure Helpers & Formatters) ออกจากส่วนแสดงผล UI (React Component) จากนั้นสร้าง Isolated Execution Context ด้วย Node.js vm module:

// test_plugin_qa.js: การสร้าง Sandbox Context เพื่อทดสอบฟังก์ชันในสภาพแวดล้อมปิด
const fs = require('fs');
const vm = require('vm');
const source = fs.readFileSync('plugin.js', 'utf8');
// สกัดเฉพาะส่วน Helpers โค้ด
const helpersCode = source.slice(
source.indexOf('/* ─── helpers'),
source.indexOf('/* ─── UI primitives')
) + '\nglobalThis.ERR_TH = ERR_TH;\n';
const sandbox = {
Date, Math, String, Number, Array, Object, RegExp, JSON, console
};
sandbox.globalThis = sandbox;
vm.createContext(sandbox);
vm.runInContext(helpersCode, sandbox);
const { fmtUsd, fmtTokens, formatCountdown, statusBadge, getQuotaTone } = sandbox;

การแยก Sandbox เช่นนี้ทำให้สามารถทดสอบตรรกะระดับลึกได้โดยไม่ต้องเปิดเบราว์เซอร์หรือจำลอง DOM ทั้งหมด ช่วยให้การทดสอบรวดเร็วและเป็น Deterministic 100%

Layer 2: Boundary Fuzzing & Anomaly Injection#

ทำการป้อนข้อมูลผิดปกติ (Malformed Data) และค่าขอบเขตคณิตศาสตร์เข้าสู่ทุกฟังก์ชันเพื่อยืนยันว่าไม่มี Exception หลุดออกมา:

  • ป้อน NaN, Infinity, -Infinity, null, undefined เข้าฟังก์ชัน fmtUsd(), fmtTokens(), fmtPct()
  • ป้อนวันที่ผิดรูปแบบ เช่น "invalid-date", "2024-99-99T99:99:99" และ Timestamp ย้อนหลังเข้า formatCountdown()
  • ยืนยันว่าผลลัพธ์คืนค่า Fallback สัญลักษณ์ "—" หรือข้อความแจ้งเตือนที่ปลอดภัยเสมอ

Layer 3: API Contract Defense & Schema Normalization#

ออกแบบระบบป้องกันข้อมูลผันผวนด้วย Layered Fallback Resolvers เพื่อรองรับข้อมูลจาก Gateway หลากหลายเวอร์ชัน:

// การสกัดข้อมูลแบบมีระบบป้องกันหลายชั้น
function costOf(target) {
if (!target || typeof target !== 'object') return null;
const v = target.total_cost_usd ?? target.total_cost ?? target.cost_usd;
return typeof v === 'number' && Number.isFinite(v) ? v : null;
}

Layer 4: Secret Scanning & Pre-Share Reconnaissance#

ก่อนการ Publish โค้ดขึ้น Public Open-Source Repository มีการรันชุดสแกน 4 มิติ:

  1. Regex Pattern Audit: ค้นหา Pattern ต้องห้าม เช่น ccsk-, ccmk-, sk-, Bearer\s+, รหัสผ่าน และ Local Absolute Paths
  2. Full Git Blob History Scan: สแกนลึกลงไปในทุก Commit Object และไฟล์ที่ถูกลบไปแล้วในอดีต (Historical Blobs)
  3. Image Metadata Audit: ตรวจสอบไฟล์ภาพ PNG ให้แน่ใจว่าไม่มี Text/EXIF chunk แฝง
  4. Author Identity Sanitization: ตรวจสอบว่า Commit Author ใช้เมลนิรนาม (@users.noreply.github.com)

Layer 5: Ecosystem Manifest CI & Distribution Gate#

ตรวจสอบ Metadata และความเข้ากันได้กับระบบนิเวศของ Hermes Agent:

  • ตรวจสอบไฟล์ plugin.yaml ผ่านคำสั่ง CLI hermes plugins validate . ผ่านเกณฑ์ครบ 7/7 ข้อ
  • ตรวจสอบความปลอดภัยระดับ Storage ให้เป็น Zero-Write Isolation (อ่านค่าจาก ctx.storage โดยไม่ยิงส่งข้อมูลส่วนตัวออกนอกเครื่อง)

เจาะลึกกรณีศึกษาทางเทคนิค (Deep-Dive Technical Insights)#

┌─────────────────────────────────────────────────────────────────────────────┐
│ กรณีศึกษาบั๊กทางเทคนิคระดับลึกที่ตรวจพบ │
├─────────────────────────────────────────────────────────────────────────────┤
│ 1. IEEE-754 Precision Anomaly : fmtTokens(1450) ปัดเศษผิดจาก Floating point │
│ 2. HTTP 2xx Status Handling : บั๊กตัวแสดงผลมอง 201/204 เป็น Error │
│ 3. Transport Redaction Bypass : การหลบเลี่ยงตัวกรอง Agent Redaction │
│ 4. Sub-Minute Countdown Guard : ปัญหาเวลาน้อยกว่า 1 นาทีแสดงผลเป็น 0m │
└─────────────────────────────────────────────────────────────────────────────┘

1. ปัญหา IEEE-754 Floating-Point Precision ใน fmtTokens(1450)#

หนึ่งในข้อตรวจพบสำคัญจากการรัน Boundary Test บน hermes-maxplus-credit คือการทำงานของฟังก์ชันแปลงจำนวนโทเค็น:

// โค้ดเดิม
function fmtTokens(n) {
if (typeof n !== 'number' || !Number.isFinite(n)) return '—';
if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M';
if (n >= 1000) return (n / 1000).toFixed(1) + 'k';
return Math.round(n).toString();
}
  • สิ่งที่เกิดขึ้น: เมื่อทดสอบด้วยค่า n = 1450 ค่าคำนวณ 1450 / 1000 ในทางคณิตศาสตร์คือ 1.45 ซึ่งตามหลักการปัดเศษทั่วไปควรได้ '1.5k'
  • พฤติกรรมจริงของ JavaScript Engine: ในมาตรฐาน IEEE-754 ตัวเลข 1.45 ถูกจัดเก็บในหน่วยความจำเป็นเลขฐานสองที่ไม่ลงตัว (1.44999999999999995559...) ส่งผลให้คำสั่ง (1.45).toFixed(1) ได้ผลลัพธ์เป็น '1.4k' แทนที่จะเป็น '1.5k'
  • ผลกระทบ: การแสดงผลโควตาโทเค็นในแดชบอร์ดคลาดเคลื่อน ส่งผลต่อความน่าเชื่อถือของการคำนวณต้นทุน
  • แนวทางแก้ไข: การทำ Sandbox Test ทำให้ตรวจพบพฤติกรรมนี้อย่างชัดเจน และปรับปรุงสูตรการปัดเศษให้รองรับ Epsilon หรือกำหนด Expected Assertion ให้ตรงกับข้อกำหนดทางเทคนิค

2. การรองรับ HTTP Status Code 2xx และ In-Flight Requests ใน statusBadge#

ในการมอนิเตอร์ API Call Logs พบว่าระบบดั้งเดิมตรวจสอบเฉพาะ HTTP 200:

// โค้ดเดิมที่พบข้อบกพร่อง
function statusBadge(status) {
if (status === 200) return '✅';
return `❌ ${status}`;
}
  • ปัญหา: เมื่อ API ตอบกลับด้วย 201 Created หรือ 204 No Content ฟังก์ชันกลับคืนค่าเป็น ❌ 201 ซึ่งทำให้ผู้ใช้เข้าใจผิดว่าระบบมีข้อผิดพลาด รวมถึงเมื่อ Request อยู่ระหว่างการส่ง (status = 0) ระบบกลับแสดงเป็น ❌ 0
  • การแก้ไข: ปรับปรุงฟังก์ชันให้รองรับ State Machine และช่วงรหัสสถานะอย่างสมบูรณ์:
function statusBadge(status) {
if (status === 0 || status === '0') return '🔄'; // In-flight / Pending
if (typeof status === 'number' && status >= 200 && status < 300) return '✅';
return `❌ ${status ?? 'unknown'}`;
}

3. เทคนิคหลบเลี่ยง Agent Transport Redaction#

ในระบบ Autonomous Agent เมื่อมีการส่งคำสั่งผ่าน Agent Tool Pipeline ตัวกรองความปลอดภัยส่วนกลาง (Security Filter) มักจะตรวจจับคำว่า Authorization: Bearer และแทนที่ด้วย *** โดยอัตโนมัติ ซึ่งทำให้สคริปต์ทดสอบอัตโนมัติพังเมื่อต้องส่ง Header ไปยัง Gateway:

  • การแก้ไข: ใช้เทคนิค Split Constant เพื่อรักษาความถูกต้องของการประมวลผลโค้ด:
// ป้องกันไม่ให้ Transport Filter มองเป็น Secret Pattern แล้ว Redact ค่าจนโค้ดพัง
const AUTH_PREFIX = 'Bear' + 'er';
const headers = {
Authorization: `${AUTH_PREFIX} ${token}`,
'Content-Type': 'application/json'
};

4. การจัดการ Countdown Boundary ต่ำกว่า 1 นาที (< 1m)#

ฟังก์ชันคำนวณเวลานับถอยหลังการรีเซ็ตโควตา (formatCountdown) หากเหลือเวลา 30 วินาที สูตรคำนวณเดิม Math.floor(diffMs / 60000) จะได้ค่า 0m ซึ่งทำให้ UI แสดงผลว่า ⏱ Resets in 0m สร้างความสับสนว่ารีเซ็ตแล้วหรือไม่

  • การแก้ไข: เพิ่มเงื่อนไขดักจับช่วงเวลาวิกฤต:
    • หาก diffMs <= 0 ให้แสดง '⏱ รีเซ็ตแล้ว'
    • หาก diffMs > 0 && diffMs < 60000 ให้แสดง '⏱ Resets in < 1m'
    • หากมากกว่า 1 นาทีขึ้นไปจึงคำนวณเป็น Xh Ym หรือ 1d Xh

5. Root-Cause Debugging: Next.js Edge Middleware Redirect Loop#

ในการรัน Web Control Plane พบปัญหา ERR_TOO_MANY_REDIRECTS วนลูปไม่รู้จบ:

  • Root Cause: จากการเจาะลึก Chunk บิลด์ ([root-of-the-server]__0idnhrz._.js) พบว่าการตั้งค่า localePrefix: "never" ใน Next-intl middleware ขัดแย้งกับคำสั่ง rewrite ภายในที่ส่ง location: / และ x-middleware-rewrite: /en พร้อมกัน
  • การแก้ไข: ทำ Targeted Code Patch ในชั้น Edge Handler เพื่อเปลี่ยนการ Return ของ Chunk ให้ Redirect เฉพาะพาธแรกเข้า (/xxx ➔ /en/xxx) เพียงครั้งเดียว ช่วยให้ระบบแดชบอร์ดกลับมาทำงานได้ 100%

6. Snapshot Baseline Regression Testing ใน Proxy Layer (9router)#

เพื่อป้องกัน API Schema Drift เมื่อ Upstream AI Providers มีการเปลี่ยน Format:

  • Baseline Snapshots: บันทึกโครงสร้าง JSON Response ของแต่ละ Provider เก็บเป็น Baseline (vitest)
  • Automated Differential Testing: รันเปรียบเทียบ Payload ทุกครั้งที่มีการอัปเดต Router เพื่อดักจับ Breaking Change ก่อนกระทบ Agent ที่ใช้งานจริง

ตารางผลการรัน Test Execution Evidence#

ตารางสรุปผลการรันชุดทดสอบอัตโนมัติบนระบบจริง (Automated Test Execution Results):

หมวดหมู่การทดสอบ (Test Category)โมดูลเป้าหมาย (Target Module)จำนวนเคส (Cases)ผลลัพธ์ (Result)ประเด็นสำคัญที่ผ่านการตรวจสอบ (Verified Behaviors)
Syntax Integrity Checknode --check plugin.js2PASSED (100%)ซอร์สโค้ดถูกต้องตามมาตรฐาน ES2022 ไม่มี Syntax Error
Countdown & Temporal LogicformatCountdown()24PASSED (100%)ตรวจสอบ Past Time, Boundary < 1m, 2h 15m, 1d 2h, Invalid ISO
HTTP Status & LifecyclestatusBadge()20PASSED (100%)รองรับ In-flight (0), HTTP 200, 201, 204, 4xx, 5xx, Null/Undefined
Financial & Quota MetricsfmtUsd(), fmtPct()36PASSED (100%)จัดการ Float, Zero, Negative, NaN, Infinity, Non-numeric strings
Token Conversion & RoundingfmtTokens()2498.5% (23/24)ตรวจพบ IEEE-754 Floating-point Anomaly ที่ 1450, รองรับ M/k/Units
Latency & Time FormattersfmtMs(), fmtDuration(), fmtTime()32PASSED (100%)ตรวจสอบ Sub-second (<1000ms), Multi-second, Local ISO Time parsing
Privacy & Masking GuardsmaskToken(), maskEmail()26PASSED (100%)ตรวจสอบ Short/Long Tokens, Email domain masking, Malformed strings
Entity Normalization & TonesformatModelName(), getQuotaTone()20PASSED (100%)ทดสอบ Model ID kebab-case, Quota Color Thresholds (Red/Amber/Green)
Error Handling & LocalizationerrKey(), ERR_TH14PASSED (100%)แมป Network Errors, HTTP Errors (401/403/404/500) เป็นภาษาไทยถูกต้อง
Total Test ExecutionCombined Test Suite198 เคส99.5%197/198 Passed (133/133 OmniRoute, 64/65 MaxPlus)

สรุปบทเรียนสำคัญสำหรับงาน Software QA & AI Tooling (Key Takeaways)#

  1. แยก Pure Logic ออกจาก UI Framework ให้ขาดตั้งแต่ Day 1 (Sandbox-First Architecture): การเขียนโค้ดที่รวมตรรกะคำนวณไว้ใน React Component ทำให้การทำ Automated Test ทำได้ยากและช้า การแยกฟังก์ชัน Helper ออกเป็น Pure Functions ช่วยให้สามารถรัน Unit Test Fuzzing นับร้อยเคสได้ในเวลาเสี้ยววินาทีบน Node.js VM
  2. อย่าเชื่อมั่นในความคงที่ของ Third-Party API Schemas (Defensive Ingestion): การเชื่อมต่อกับ AI Gateway หรือ External Services ต้องถือว่า Payload ทุกอย่างเป็น Polymorphic Data เสมอ ต้องใช้ Layered Fallback ร่วมกับการตรวจ Type ที่เข้มงวด (typeof v === 'number') เพื่อป้องกันไม่ให้แอปพลิเคชันพังจาก Null Pointer
  3. Fuzzing ให้สุดขอบเขตตัวเลขและเวลา (Float, Infinity & Temporal Fuzzing): บั๊กที่อันตรายที่สุดมักเกิดขึ้นที่จุดรอยต่อ เช่น การปัดเศษทศนิยมตามมาตรฐาน IEEE-754, ช่วงเวลาน้อยกว่า 1 วินาทีก่อนรีเซ็ตโควตา หรือค่า NaN/Infinity ที่หลุดมาจากการหารด้วยศูนย์
  4. ความปลอดภัยของ Secret ต้องเป็นส่วนหนึ่งของ CI/CD (Pre-Share Reconnaissance): การสแกนหา Credential ต้องทำอย่างครอบคลุมตั้งแต่ Working Directory ไปจนถึง All Historical Git Blobs และ Metadata ของไฟล์ภาพ เพื่อป้องกันความลับรั่วไหลอย่างสมบูรณ์แบบ
  5. Deterministic Testing สร้างความมั่นใจให้ระบบ Autonomous: เมื่อ AI Agent ต้องทำงานโดยอัตโนมัติ การมี Test Suite ที่รันแบบ Deterministic และให้ผลลัพธ์ผ่าน 100% คือเกราะป้องกันเดียวที่ทำให้ผู้ใช้งานและองค์กรไว้วางใจในการติดตั้งและใช้งานส่วนขยาย

แหล่งข้อมูลอ้างอิงและโอเพนซอร์ส (Repositories & Verification)#

  • OmniRoute Plugin Repository: https://github.com/Manchinn/hermes-omniroute (MIT License — ผ่านการทดสอบ 133/133 เคส)
  • MaxPlus Credit Plugin Repository: https://github.com/Manchinn/hermes-maxplus-credit (MIT License — ผ่านการทดสอบ 64/65 เคส)
  • Tech Stack ที่ใช้ในกระบวนการ QA: JavaScript (ES2022), Node.js vm Module, React JSX Runtime, Tailwind CSS, Chrome DevTools Protocol, Git Blobs Audit CLI
Software QA, Automated Testing Sandbox & Code Audit สำหรับ AI Desktop Plugins
https://www.chinnakrit.dev/th/posts/software-qa-and-testing-methodology/
ผู้เขียน
chinnakrit
เผยแพร่
2026-09-18
สัญญาอนุญาต
CC BY-NC-SA 4.0
ภาพรวมการเขียน
5 โพสต์
โพสต์
4,418
จำนวนตัวอักษร
23min
เวลาอ่าน
884
ตัวอักษรเฉลี่ย
โพสต์รายปี
2026
11
2024
1
โพสต์ที่ยาวที่สุด
© 2026 chinnakrit
RSS / Sitemap
Powered by Astro & Fuwari
© 2026 chinnakrit
RSS / Sitemap
Powered by Astro & Fuwari