# บันทึกการนำหลักสูตรขึ้น Cloudflare จริง

วันที่ตรวจ: **9 กันยายน 2026 เวลา 07:30 น. (Asia/Bangkok)**

เว็บไซต์: [AI Web Studio](https://vibe-to-production-academy.rawinnipa-soft.workers.dev) · [คลังเอกสารและดาวน์โหลด](/resources/)

![แผนภาพ deployment ของหลักสูตร แสดง browser เชื่อม Cloudflare Worker ซึ่งส่ง static assets และเรียก D1 managed data ผ่าน binding](/diagrams/cloudflare-deployment.svg)

[เปิดแผนภาพ deployment แบบเต็มหน้า](/diagrams/cloudflare-deployment.html) เพื่อทำความเข้าใจ topology ส่วนตารางด้านล่างเป็น snapshot หลักฐานวันที่ระบุ และไม่ควรตีความว่าแผนภาพยืนยันสถานะ uptime ปัจจุบัน

| รายการ | หลักฐานที่ตรวจแล้ว |
| --- | --- |
| Runtime | Cloudflare Workers + Static Assets |
| Database | D1 แยกสำหรับหลักสูตร; migration `0001_initial.sql` และ `0002_demo_retention.sql` สำเร็จบน remote |
| Worker | `vibe-to-production-academy` (ชื่อ resource เดิม เก็บไว้เพื่อไม่เปลี่ยน production identity) |
| Version ที่ตรวจ API ครั้งแรก | `bf1f89d0-f549-4f2e-a917-063089ce6d4d` หลังตั้ง secret; การอัปเดตเอกสาร/ไฟล์ดาวน์โหลดภายหลังมี version แยกใน deployment history |
| Health | HTTP 200, `ok: true`, `storage: d1`, `demo: true` |
| หน้าเว็บ | ห้องเรียน, resources, handbook และตัวอย่างทั้ง 4 แบบ HTTP 200 |
| Contact | POST ข้อมูลสังเคราะห์ได้ HTTP 201; ส่ง idempotency key เดิมซ้ำได้ response เดิม |
| Origin | POST จาก origin อื่นถูกปฏิเสธ HTTP 403 |
| Quotation | HTTP 201; หูฟัง 2 ชิ้นรวม 918,000 สตางค์ ตรงราคา D1 |
| Rental | HTTP 201; กล้อง 1 ชุด 1 วันรวม 189,000 สตางค์; response มี `expiresAt` ของ hold 30 นาที |
| ตรวจ D1 หลังส่ง | contact/quote/rental อย่างละ 1 รายการ ปกปิดชื่อ/อีเมล/ข้อความตาม fields ที่ใช้ และ rental มี expiry |
| Local regression | API 12/12 พร้อม database audit, browser 40/40; รายละเอียดอยู่ในไฟล์ผลทดสอบที่ดาวน์โหลดได้ |
| Retention | Cron `0 * * * *` ถูก deploy แล้ว; การล้างข้อมูลสาธิตมี automated local audit |

เว็บตัวอย่าง: [บริษัท](/examples/company/) · [ให้เช่าอุปกรณ์](/examples/rental/) · [สินค้า GSAP](/examples/store/) · [อสังหาริมทรัพย์ + ui-ux-pro-max](/examples/real-estate/)

นี่เป็น **เว็บสาธิตที่รันบน Cloudflare จริง** แบบฟอร์มไม่ได้ส่งอีเมลถึงธุรกิจ การจองและใบเสนอราคาไม่มีผลทางการค้า ไม่มีระบบชำระเงิน ข้อมูลและภาพอสังหาริมทรัพย์เป็นตัวอย่างสมมติ อ่าน [นโยบายข้อมูล](/learn/instructor/demo-data-policy/) ก่อนทดลอง

ไฟล์หลักฐานใน repository: `artifacts/production-smoke.json`, `production-d1-audit.json`, `remote-migrations.txt`, `production-browser-smoke.json`, `api-tests.txt`, `browser-tests.txt` และ `RELEASE.md` การเก็บ snapshot นี้ไม่รับรองสถานะ uptime ในอนาคต ผู้เรียนควรทำ smoke test อีกครั้งก่อนเริ่มอบรมแต่ละรุ่น

## สิ่งที่ปัญหา migration สอนเรา

SQL trigger ที่ผ่าน local เคยถูก D1 remote ปฏิเสธ จึงปรับเป็น trigger-level `WHEN` และทดสอบ concurrency ใหม่ ก่อน remote migration สำเร็จ รายละเอียดพร้อมแหล่งอ้างอิงอยู่ท้าย [บทเรียน 08](../lessons/08-cloudflare-deploy.md) หลักฐานจริงนี้แสดงเหตุผลที่เกณฑ์จบต้องรวม remote deploy และ verification

## 13 กันยายน 2026 — แพลตฟอร์มหลายหลักสูตรที่ course.rawinlab.com

วันที่บันทึก: **13 กันยายน 2026 (Asia/Bangkok)** — บันทึกการเปลี่ยนโครงสร้างเป็นแพลตฟอร์มหลายหลักสูตร พร้อมผลตรวจในเครื่อง ก่อน deploy จริง (ส่วนบนของเอกสารคือ snapshot วันที่ 9 กันยายน 2026 ที่คงไว้ตามเดิม)

Repository เปลี่ยนจากไซต์หลักสูตรเดียวเป็นแพลตฟอร์มหลายหลักสูตร: แต่ละหลักสูตรอยู่ใต้ `courses/<slug>/` (ปัจจุบัน slug เดียวคือ `ai-web-studio`) และเสิร์ฟที่ `/<slug>/…` โดยหน้า `/` กลายเป็นแคตตาล็อกหลักสูตร `wrangler.jsonc` เพิ่ม custom domain `course.rawinlab.com` ให้ Worker `vibe-to-production-academy` โดยคง URL workers.dev เดิมไว้ และ `TURNSTILE_HOSTNAME` เปลี่ยนจากค่าเดียวเป็น comma allowlist ของทั้งสอง hostname

URL เดิมที่ไม่มี prefix ตอบ **301 (ถาวร)** ไปที่ path เดิมใต้ prefix ใหม่ ทั้งสองโดเมน โดยเพิ่ม prefix เหล่านี้ใน `run_worker_first` ของ `wrangler.jsonc` เพื่อให้ Worker ทำงานก่อน asset layer:

| Path เดิม | ปลายทาง 301 |
| --- | --- |
| `/learn/…` | `/ai-web-studio/learn/…` |
| `/handbook` | `/ai-web-studio/handbook` |
| `/resources` | `/ai-web-studio/resources` |
| `/examples/…` | `/ai-web-studio/examples/…` |
| `/downloads/…` | `/ai-web-studio/downloads/…` |
| `/labs/…` | `/ai-web-studio/labs/…` |
| `/diagrams/…` | `/ai-web-studio/diagrams/…` |
| `/images/…` | `/ai-web-studio/images/…` |

ไม่ถูก redirect: `/api/*`, `/assets/*`, `/brand/*`, `/fonts/*` และหน้า `/` (แคตตาล็อกทั้งสองโดเมน)

ผลตรวจในเครื่อง (local preview 3320 / API test 3321) วันที่ 13 กันยายน 2026:

| รายการ | หลักฐานที่ตรวจแล้ว |
| --- | --- |
| Dead-link lint | `npm run lint` ผ่าน: ตรวจ 4,266 links/assets บน 91 หน้าใน `dist/` |
| Build layout | `npm run test:build` ผ่าน 8/8: แคตตาล็อกลิงก์ `/ai-web-studio/`, search index ต่อหลักสูตร, ไม่มี legacy root dirs ใน `dist/` และ redirect prefixes ครบใน Worker |
| API regression | `npm test` ผ่าน 12/12 พร้อม database audit |
| Browser suite | `npm run test:e2e` ผ่าน 66 tests (6 spec files รวม catalog) |
| Redirect matrix | ทุก path ในตารางข้างบนตอบ 301 ไป `/ai-web-studio/…` บน local preview |
| Diagram checks | `npm run check:diagrams` ผ่าน 17 แผนภาพ หลังอัปเดต sourcePaths ของ definitions.json ตาม layout ใหม่ |

**Production deploy + smoke (13 กันยายน 2026):** deploy ผ่าน `npm run deploy` จาก commit `6cf05f0` — Worker `vibe-to-production-academy` เวอร์ชัน `40ecb383-1494-45af-bbfb-2c82f6a4b4ea` อัปโหลด 81 ไฟล์ใหม่ (411 ไฟล์ reuse) และ attach custom domain สำเร็จ ผลตรวจที่ production:

| รายการ | หลักฐาน |
| --- | --- |
| แคตตาล็อก | `https://course.rawinlab.com/` → 200 พร้อมลิงก์ `href="/ai-web-studio/"` |
| หน้าหลักสูตร | `https://course.rawinlab.com/ai-web-studio/` → 200 พร้อม `data-course="ai-web-studio"` |
| API | `/api/health` → `{"ok":true,"storage":"d1","demo":true}` |
| Legacy redirect | `/learn/lessons/00-setup-and-web-basics/` → 301 → `/ai-web-studio/learn/lessons/00-setup-and-web-basics/` (query string คงเดิม) |
| workers.dev เดิม | `/resources/` → 301 → `/ai-web-studio/resources/` และ `/` → 200 (แคตตาล็อก) |
| Smoke suite | `node scripts/smoke-production.mjs https://course.rawinlab.com` ผ่าน: 12 pages/assets ใต้ `/ai-web-studio/`, 1 legacy redirect, D1 health/catalog, 0 synthetic mutations |

**เปลี่ยนโดเมนวันเดียวกัน:** custom domain ถูก attach ครั้งแรกเป็น `course.rawinsoft.com` (version `40ecb383`) แล้วเปลี่ยนเป็น `course.rawinlab.com` ตามคำสั่งในวันเดียวกัน (commit `740e2ee`, version `b5132b45` — route เดิมถูกแทนที่ ไม่คงสองโดเมน) ตาราง production ด้านบนคือผลตรวจซ้ำหลังเปลี่ยนโดเมน workers.dev เดิมยังใช้งานเหมือนเดิม

**อัปเดตดีไซน์ (13 กันยายน 2026):** deploy แบบ Full Width Background + Boxed Content (commit `60e38ad`, version `f910a161`) — ทุก section เป็น band เต็มความกว้าง (paper/mist/sky สลับกัน + hairline) เนื้อหาอยู่ใน container 1240px การ์ดเป็น box (token ใหม่ `--box`/`--panel`, dark sky `#141414`) ผ่าน e2e 66 tests รวม axe accessibility ทั้งสองธีม และ smoke ซ้ำที่ production ผ่าน
