การพัฒนาในเครื่องและคู่มือ repository

Dee Wan CMS (ดีหวาน 🇹🇭) คือ headless CMS แบบ multi-tenant และหลายภาษา ที่ทำงานบน Cloudflare ทั้งหมด: Hono Worker บน D1 สำหรับ API และ admin ที่เป็น SvelteKit บน Pages
มันเป็น CMS เป็นอันดับแรก: สร้าง model เนื้อหา เขียนเนื้อหา เผยแพร่ และจัดการเนื้อหา สิ่งที่ทำให้มันแตกต่างจาก headless CMS อื่น ๆ คือสิ่งที่มันส่งมอบให้คุณได้ในตอนท้าย — การสร้างแบ็กเอนด์อิสระ เปลี่ยนไซต์ให้เป็น repository ที่คุณเป็นเจ้าของ พร้อม Prisma schema ที่ normalize แล้ว, migration แบบเพิ่มต่อท้ายอย่างเดียวที่ตรวจทานได้, route ที่สร้างขึ้นซึ่งใช้ semantics ของ query แบบ Prisma ที่คุ้นเคย, ฐานข้อมูล deployment และ credential ของตัวเอง และไม่ ขึ้นกับ Dee Wan ขณะ runtime โค้ดของคุณเองคงอยู่เมื่อสร้างใหม่ (regeneration) และการแยกตัวจาก Dee Wan โดยสิ้นเชิงเป็นผลลัพธ์ที่รองรับ
Dee Wan ให้บริการเนื้อหาได้สองแบบที่มีพฤติกรรมต่างกัน API สาธารณะของ CMS ให้บริการเนื้อหาแบบสด และอัปเดตทันทีที่เผยแพร่ ส่วน แบ็กเอนด์อิสระ เป็นชุดสคีมาและเนื้อหาที่ส่งมอบแยกต่างหาก การเปลี่ยนแปลงใน CMS ภายหลังจะไปถึงแบ็กเอนด์นี้ก็ต่อเมื่อคุณสั่งสร้างและดีพลอยใหม่เท่านั้น
Pre-release: Dee Wan 1.0 ยังไม่ใช่ผลิตภัณฑ์ที่ release แล้ว acceptance บน Cloudflare จริง การตรวจเบราว์เซอร์ขั้นสุดท้าย และการย้ายไซต์จริงยังเปิดอยู่ ดู ขอบเขตผลิตภัณฑ์ 1.0 ว่าอะไรครอบคลุมและอะไรไม่ครอบคลุม
เริ่มที่นี่:
- ลองบน local — ไม่ต้องมีบัญชี Cloudflare
- การติดตั้ง Dee Wan — คู่มือฉบับเต็มสำหรับบัญชี Cloudflare ของคุณเอง
- Public read API — เว็บไซต์อ่านเนื้อหาที่เผยแพร่แล้วอย่างไร
- แบ็กเอนด์อิสระ: ภาพรวม — แบ็กเอนด์ที่สร้างขึ้นคืออะไรและสร้างอย่างไร
- การต่อยอดแบ็กเอนด์ของคุณ — การทำงานในแบ็กเอนด์อิสระ ที่สร้างขึ้น
- Migration ของฐานข้อมูล — การเปลี่ยนและ apply schema
มันทำอะไรได้
หัวข้อที่มีชื่อว่า “มันทำอะไรได้”- ตัวสร้าง model — กำหนด content model และฟิลด์ (text, rich text, number, boolean, select, date, media, JSON, relation, component) ใน UI model ถูกเก็บเป็นข้อมูล ดังนั้นการเพิ่มประเภท “Recipe” จึงไม่ต้องเขียนโค้ดและไม่ต้องมี migration การเปลี่ยนแปลงถูก diff ก่อนนำไปใช้ และการแก้ไขที่จะ ทำให้เนื้อหาที่มีอยู่ไม่ถูกต้องจะถูกแจ้งก่อน
- หลายไซต์ — การติดตั้งหนึ่งชุดให้บริการได้หลายไซต์ ทุก request ของ admin ระบุไซต์ของตัวเอง และ ชั้นข้อมูลเพิ่มไซต์ลงในทุก query API ปฏิเสธที่จะเดาไซต์แทนที่จะเสี่ยงอ่าน ข้อมูลของไซต์อื่น
- หลายภาษา — กำหนดค่าภาษาใน UI เนื้อหาถูกเก็บแยกตามภาษา
- การจัดการเวอร์ชันและการเผยแพร่ — revision ของเนื้อหาพร้อม publish และ unpublish การ review เชิงบรรณาธิการเป็น โหมดต่อไซต์ที่เลือกใช้ได้ ปิดไว้โดยค่าเริ่มต้น: ไซต์ใหม่เผยแพร่จาก draft ได้ทันที และไม่มี ตัวควบคุม review ปรากฏจนกว่าจะมีคนเปิด review ที่ การตั้งค่า → ขั้นตอนงาน
- ผู้ช่วย AI — สร้างและแปลข้อความ และสร้างภาพ ผ่าน Worker key ของ provider ไม่ไปถึงเบราว์เซอร์เลย
- สื่อ — อัปโหลดไปยัง R2 หรือ Cloudflare Images พร้อมการแปลงเป็น WebP/AVIF อัตโนมัติ
- การลงชื่อเข้าใช้ — บัญชีและ session ของการติดตั้งเอง claim link ใช้ครั้งเดียวสร้าง ผู้ดูแลคนแรกด้วยรหัสผ่าน, magic link, Google หรือ GitHub การเข้าสู่ระบบด้วยรหัสผ่าน magic link, Google และ GitHub ไม่สร้างบัญชี Cloudflare Access เลือกใช้ได้และปิดไว้โดยค่าเริ่มต้น เมื่อผู้ดูแลไซต์เพิ่มกฎ Access ไว้ identity ของ Access ที่ยืนยันแล้วและตรงกับกฎจะได้บัญชีและบทบาทของไซต์นั้นเมื่อเข้าสู่ระบบ
- Remote plugin — ปลั๊กอินเป็นบริการที่ deploy แยกต่างหาก โค้ดของปลั๊กอินไม่ทำงานบน
backend ของ Dee Wan หรือในเอกสารหลักของหน้าแอดมิน ส่วนติดต่อของปลั๊กอินทำงานในเฟรมที่แยกไว้
ปลั๊กอินไม่มีสิทธิ์เข้าถึงฐานข้อมูลโดยตรง HTTP protocol ที่มีเวอร์ชันช่วยให้ทำงานกับเนื้อหา สื่อ
และขั้นตอนการอนุมัติได้ ภายใน grant ต่อไซต์ที่เลือกใน การตั้งค่า → ปลั๊กอิน และสิทธิ์ที่ผู้ใช้
มอบหมายไว้ในขณะนั้น การตั้งเวลาเผยแพร่เป็นหน้าที่ของปลั๊กอิน Scheduling (
plugins/scheduling/) ไม่ใช่ฟีเจอร์หลัก สำหรับนักพัฒนา plugin: การเขียน plugin · protocol v1 · ความปลอดภัย · การทดสอบ · manifest schema · protocol schema
แต่ละคนได้รับ role ต่อไซต์ role ในตัว:
| Role | ทำอะไรได้ |
|---|---|
admin |
ทุกอย่างบนไซต์: เนื้อหา, การเผยแพร่, model, settings, ผู้คน, role, plugin, import และ export |
editor |
สร้าง แก้ไข publish unpublish และอนุมัติเนื้อหาใดก็ได้ export เปลี่ยน model หรือ settings ไม่ได้ |
author |
สร้างเนื้อหาและอ่านเนื้อหาทั้งหมด แต่แก้ไขได้เฉพาะเนื้อหาที่ตนสร้าง publish, unpublish, อนุมัติ หรือกู้คืนไม่ได้ |
viewer |
อ่านอย่างเดียว |
กฎของ author ทำงานอย่างไร:
- ความเป็นเจ้าของคือบัญชีที่สร้าง item นั้น item ที่ไม่มีบันทึกผู้สร้างจะแก้ไข โดย author ไม่ได้
- คำแปลของ item หนึ่งรวมเป็นกลุ่มที่มี item หลักหนึ่งรายการ และทุกการบันทึกจะเขียน item หลักด้วย ดังนั้น author จะแก้คำแปลได้ก็ต่อเมื่อตนสร้างทั้งคำแปลนั้นและ item หลักของ กลุ่ม
- ทุกการกระทำที่ author ได้รับอนุญาตบน item — การแก้ไข และขั้นตอน workflow เช่นการส่งไป
review — จะถูกปฏิเสธด้วย
not_ownerบน item ของคนอื่น และ editor จะซ่อนตัวควบคุมที่ author ใช้ไม่ได้
superadmin ไม่ถูกจำกัดด้วยสิ่งเหล่านี้เลย
สถาปัตยกรรม
หัวข้อที่มีชื่อว่า “สถาปัตยกรรม”| ส่วน | Stack |
|---|---|
| Admin UI | SvelteKit (single-page app), shadcn-svelte, TipTap — บน Cloudflare Pages |
| Admin API | Hono บน Cloudflare Worker |
| Public read API | Worker ตัวที่สอง อ่านเฉพาะเนื้อหาที่เผยแพร่แล้ว |
| ฐานข้อมูล | D1 ผ่าน Prisma (@prisma/adapter-d1) |
| Media | R2 หรือ Cloudflare Images |
| Auth | session ของ Better Auth Cloudflare Access เลือกใช้ได้ |
| Inference | DeepInfra |
repository นี้เป็น npm workspace library ที่ใช้ร่วมกันส่วนใหญ่ใน packages/ เป็น git submodule ดังนั้นให้ clone
ด้วย --recurse-submodules ส่วน page-contract และ plugin-conformance อยู่ใน repository นี้
backend/ Admin and public Workers: API, auth, site-scoped data access, AI proxy, Prisma schemafrontend/ SvelteKit admin UIpackages/ submodules: schema-parser, prisma-guard, prisma-rbac, prisma-generator-express, eav-to-prisma, cache, prisma-query-builder-ui. In this repository: page-contract, plugin-conformanceplugins/ remote plugins built against protocol v1 (Scheduling)scripts/ install, deploy, migrate, health, teardownลองบน local โดยไม่ต้องมีบัญชี Cloudflare
หัวข้อที่มีชื่อว่า “ลองบน local โดยไม่ต้องมีบัญชี Cloudflare”สิ่งนี้รันผลิตภัณฑ์ทั้งหมดกับไฟล์ D1 บน local ในเครื่องของคุณ: ไม่ต้องมีบัญชี ไม่ต้องมี API token ไม่ต้องมี DNS คุณต้องมี Node และ npm ตามที่ระบุในสิ่งที่ต้องมีก่อน
git clone --recurse-submodules https://github.com/dee-wan-cms/dee-wan.gitcd dee-wannode scripts/install-dependencies.mjs # root and backend dependenciesnode scripts/install-dependencies.mjs frontend # admin UI dependenciesnpm run local:migrate # apply the schema to the local databasenpm run local:api # admin Worker on http://localhost:8787 (leave running)npm run local:seed # sample sites and content (in a second terminal)npm run local:admin # admin UI on http://localhost:5173 (leave running)local:seed แสดงบัญชีลงชื่อเข้าใช้ที่มันสร้าง: admin@localhost.test รหัสผ่าน
local-dev-password-1234 การรันอีกครั้งจะรายงานสิ่งที่มีอยู่แล้วแทนการสร้างสำเนา
มัน seed สองอย่าง ซึ่งเป็นคำสั่งแยกกันด้วย:
| คำสั่ง | สร้างอะไร |
|---|---|
npm run local:seed:fixture |
Local Dev Site: ผู้ดูแลคนแรก, model Article, draft สามรายการ และหน้า demo หนึ่งหน้า |
npm run local:seed:corpus |
ไซต์สมมติที่สมจริงสองไซต์ — Meridian Review นิตยสารที่มีคลังย้อนหลังสิบแปดเดือน และ Fern & Ash ไซต์สตูดิโอขนาดเล็ก สร้างบนนิยามของ blog fixture มีราวห้าสิบ item ในสถานะ published, draft, in-review, approved และ scheduled พร้อม relation, ภาพที่มี alt text และคำแปลภาษาเยอรมัน ต้องมีผู้ดูแลของ fixture ก่อน |
วันที่ใน corpus ยึดกับเวลาที่ corpus ถูกสร้างครั้งแรก ดังนั้นการรันซ้ำจะไม่ย้ายเนื้อหา
ที่มีอยู่ ภาพมาจาก backend/scripts/fixtures/media/ เมื่อไดเรกทอรีนั้นมีภาพอยู่ มิฉะนั้น
corpus จะสร้างภาพตัวยึดตำแหน่งแบบง่าย
จากนั้น ใน admin UI เปิด เนื้อหา แก้บทความที่ seed ไว้หนึ่งรายการ แล้วเผยแพร่
หากต้องการอ่านสิ่งที่คุณเผยแพร่แบบที่เว็บไซต์อ่าน:
npm run local:public # public read Worker on http://127.0.0.1:8788 (leave running)curl -H "Host: localhost" http://127.0.0.1:8788/v1/articlepublic Worker หาไซต์จาก header Host และจากสิ่งนั้นเท่านั้น ดังนั้น request ที่ไม่มี header นี้
จะตอบ 404 — กฎเดียวกับที่ deployment ใช้
นำเข้าและส่งออกเนื้อหาได้ที่ การตั้งค่า → ย้ายข้อมูล ลิงก์ ส่งมอบแบ็กเอนด์แบบแยก บน dashboard เปิด การตั้งค่า → ซอร์สโค้ดและการเผยแพร่ เพื่อเชื่อมต่อ repository และจัดการ deployment การสร้างโปรเจกต์เป็นอีกขั้นตอนหนึ่ง ส่วน deployment ต้องมีบัญชี Cloudflare
rig นี้ใช้ backend/wrangler.dev.jsonc ซึ่งถูก track ไว้ ไม่มี credential หรือ account id และ
ไม่แตะ Cloudflare เลย
ติดตั้งบน Cloudflare
หัวข้อที่มีชื่อว่า “ติดตั้งบน Cloudflare”คู่มือฉบับเต็ม รวมถึงการติดตั้งแบบไม่มีผู้ดูแล การอัปเกรด และ teardown คือ การติดตั้ง Dee Wan ฉบับย่ออยู่ด้านล่าง
สิ่งที่ต้องมีก่อน
หัวข้อที่มีชื่อว่า “สิ่งที่ต้องมีก่อน”- บัญชี Cloudflare ที่มี Workers, D1, Pages และ R2 หรือ Cloudflare Images
- Node 22 (≥22.14) หรือ 24 (≥24.10)
.nvmrcของ repository pin 24.18.1 ไว้ ดังนั้นnvm useจะเลือกมัน - npm ตรงตามที่
package.json#packageManagerประกาศ (11.16.0) ซึ่งเป็น npm ที่มากับ Node ตาม.nvmrcติดตั้งด้วยnode scripts/install-dependencies.mjsเสมอ อย่าใช้npm installหรือnpm ciเปล่า ๆ: มันปฏิเสธ npm อื่น ติดตั้ง tree ที่ล็อกไว้โดย ปิด install script ตรวจทุก dependency script เทียบกับpackage.json#allowScriptsและจึง rebuild เฉพาะตัวที่อนุมัติแล้ว - DeepInfra API key สำหรับฟีเจอร์ AI (ไม่บังคับ)
ไม่จำเป็นต้องมี Cloudflare Access (Zero Trust) setup จะถามว่าจะเปิดหรือไม่ ค่าเริ่มต้นคือ ไม่ และการลงชื่อเข้าใช้จะทำงานผ่าน session ของการติดตั้งเอง
Quickstart
หัวข้อที่มีชื่อว่า “Quickstart”git clone --recurse-submodules https://github.com/dee-wan-cms/dee-wan.gitcd dee-wannode scripts/install-dependencies.mjsnode scripts/install-dependencies.mjs frontend
npm run setup # provisions everything, builds and deploys the admin UI and both Workersnpm run health # checks the deployment answerssetup สร้างฐานข้อมูล D1 และที่เก็บ media, apply schema, build และ deploy admin
UI, admin Worker และ public read Worker, เก็บ secret ของพวกมัน และเสนอ DNS กับ Access
ที่เลือกใช้ได้ ตอนจบมันแสดง claim link: เปิดลิงก์แล้วเลือกวิธีที่ตั้งค่าไว้ ได้แก่ รหัสผ่าน,
magic link, Google หรือ GitHub ทุกวิธีต้องยืนยัน BOOTSTRAP_ADMIN_EMAIL หลัง normalize ให้ตรงกัน
ลิงก์ใช้ได้ครั้งเดียวและหมดอายุใน 15 นาที หากพลาดไป ให้รัน npm run setup อีกครั้ง — ลิงก์ที่
หมดอายุโดยไม่ได้ใช้นับว่ายังไม่เสร็จ ดังนั้นการรันจะออกลิงก์ใหม่ตราบที่ยังไม่มีใคร claim
การติดตั้ง
การเปลี่ยนโค้ดหรือการตั้งค่าภายหลังจะส่งออกด้วย npm run deploy (ดู Deploy)
clone ใหม่ไม่ต้อง build ด้วยมือ: packages/*/dist และ Prisma client เป็นผลลัพธ์ของ build
และ setup, deploy และ migrate:d1 จะ build ให้เมื่อยังไม่มี npm run doctor เป็นการตรวจแบบ
read-only บน clone ใหม่มันจะรายงานว่าผลลัพธ์เหล่านั้นหายไป ดังนั้นให้รันหลัง setup หรือ
หลัง npm run build:packages && npm run prisma:generate
การให้บริการเนื้อหาที่เผยแพร่แล้ว (public read Worker)
หัวข้อที่มีชื่อว่า “การให้บริการเนื้อหาที่เผยแพร่แล้ว (public read Worker)”เนื้อหาที่เผยแพร่แล้วให้บริการโดย public read Worker แยกต่างหาก ซึ่งตั้งค่าด้วย
backend/wrangler.public.jsonc
npm run setup เขียนไฟล์นั้นให้คุณ เมื่อบัญชี zone และ database id
ลงตัวแล้ว และไม่เขียนทับไฟล์ที่มีอยู่ หากหาค่าใดค่าหนึ่งไม่ได้ setup จะบอกโดยระบุ
ชื่อแทนการเดา นั่นคือกรณีที่คุณต้องเตรียมไฟล์ด้วยมือ:
cp backend/wrangler.public.example.jsonc backend/wrangler.public.jsonc# edit backend/wrangler.public.jsonc — account id, D1 id, routenpm run deploydeploy ปฏิเสธที่จะรันเมื่อไม่มีไฟล์นั้น เพราะการติดตั้งที่ไม่มี public Worker
จะให้บริการเนื้อหาที่เผยแพร่แล้วแก่ใครไม่ได้เลย การติดตั้งที่ต้องการแค่ admin บอกเช่นนั้นด้วย
npm run deploy -- --admin-only ซึ่งจะถูกรายงานเป็น admin-only แทนที่จะเป็นครบถ้วน
admin config ที่ไม่ใช่ค่าเริ่มต้น (--config) ต้องระบุ public config ของมันด้วย เช่น
npm run deploy -- --config wrangler.v3.jsonc --public-config wrangler.v3.public.jsonc ทั้งสองถูก
อ่านและเปรียบเทียบค่า account_id ก่อน deploy สิ่งใด
public cache ปิดอยู่จนกว่าคุณจะเปิด การติดตั้งเริ่มต้นตั้ง
PUBLIC_CACHE_MAX_AGE=0 และ public Worker ตอบ Cache-Control: no-store ดังนั้นทุกการ publish,
update, unpublish หรือ delete จะมองเห็นในการอ่านครั้งถัดไป หากจะ cache admin Worker ต้อง
purge ได้เมื่อเผยแพร่ ซึ่งต้องมี CF_PURGE_ZONE_ID และ CF_PURGE_API_TOKEN ที่มี Zone → Cache Purge (ดู Secrets) การเพิ่ม PUBLIC_CACHE_MAX_AGE ยังทำให้คุณได้รับผลจาก
Browser Cache TTL ของ zone ซึ่งเขียน browser caching ใหม่ทุกครั้งที่ origin ขอค่าที่น้อยกว่า และการ purge
ล้างเบราว์เซอร์ไม่ได้เลย ตั้ง Browser Cache TTL เป็น Respect Existing Headers ก่อนพึ่งพา
cache
Credential
หัวข้อที่มีชื่อว่า “Credential”setup ต้องใช้ Cloudflare API token มันจะถามหาหากยังไม่ได้ตั้งไว้ และแสดงรายการ
สิทธิ์ที่แน่นอนพร้อมเหตุผลของแต่ละสิทธิ์ การติดตั้ง Dee Wan
ระบุว่าสิทธิ์ใดขึ้นอยู่กับตัวเลือกของคุณ เช่น domain ของคุณเองหรือ Access npm run doctor แสดงรายการเดียวกัน
export CLOUDFLARE_API_TOKEN=… # optional — skips the promptexport CLOUDFLARE_ACCOUNT_ID=… # optional — skips the account pickersetup เองไม่ต้องใช้ตัวแปร environment อื่น secret ของแอปพลิเคชันถูกตั้งด้วย
wrangler secret put (ด้านล่าง) ไม่ใช่ในไฟล์ ตัวแปรที่ไม่บังคับซึ่งคำสั่งอื่นใช้:
| ตัวแปร | ใช้โดย |
|---|---|
DEEWAN_RESOURCE_PREFIX |
setup — แยก namespace ให้ทุกชื่อทรัพยากร ดูบัญชีที่ใช้ร่วมกัน |
DEEWAN_YES=1 หรือ CI=true |
setup, install:cms — ไม่ถามเลย ใช้ค่าเริ่มต้นหรือล้มเหลว |
D1_PLAN (free หรือ paid) |
การติดตั้งแบบไม่มีผู้ดูแล — ตอบคำถามเรื่อง D1 plan |
DEEWAN_CF_OAUTH_CLIENT_ID, DEEWAN_CF_OAUTH_REDIRECT |
install:web — การลงชื่อเข้า Cloudflare หากไม่มี client id ตัวติดตั้งแบบเว็บเชื่อมต่อ Cloudflare ไม่ได้ |
DEEWAN_INSTALL_PORT |
install:web, install:web:dry-run — port บน 127.0.0.1 |
CF_ACCESS_CLIENT_ID, CF_ACCESS_CLIENT_SECRET |
health — service token ของ Cloudflare Access เพื่อตรวจขอบเขต Access เมื่อเปิด Access |
DEE_WAN_ADMIN_COOKIE |
provision:site, acceptance — cookie ของ admin session สำหรับการตรวจที่ต้องใช้ |
DEEWAN_GITHUB_CLIENT_ID |
wire:github, backend:deliver — GitHub OAuth client ที่ใช้ลงชื่อเข้าแบบ device |
VERIFY_ADMIN_URL, VERIFY_PUBLIC_URL, VERIFY_EMAIL, VERIFY_PASSWORD |
verify (รหัสผ่านอ่านจาก environment เท่านั้น) |
DEEWAN_ACCEPTANCE_ADMIN_EMAIL, DEEWAN_ACCEPTANCE_SITE_ID, DEEWAN_PUBLIC_HOST, DEEWAN_PUBLIC_STRANGER_HOST |
acceptance |
DEEWAN_SMOKE_PAGES, DEEWAN_SMOKE_HOST |
smoke test ของ deployment |
PUBLIC_BACKEND_URL |
local:admin — admin API ที่ UI บน local คุยด้วย (ค่าเริ่มต้น http://localhost:8787) |
Secrets
หัวข้อที่มีชื่อว่า “Secrets”secret ไม่ถูกเก็บใน wrangler.jsonc หรือในฐานข้อมูลเลย ตั้งค่าจากไดเรกทอรี backend/:
npx wrangler secret put DEEPINFRA_API_KEY # AI text and image generationการตั้งค่าธรรมดา (ไม่ใช่ secret) อยู่ใต้ vars ใน backend/wrangler.jsonc และมีผลใน
npm run deploy ครั้งถัดไป ทุกอย่างด้านล่างไม่บังคับ ฟีเจอร์ที่ขาดการตั้งค่าจะปิดอยู่
| ชื่อ | ประเภท | เปิดอะไร |
|---|---|---|
DEEPINFRA_API_KEY |
secret | การเชื่อมต่อ DeepInfra เริ่มต้นสำหรับแชท ภาพ และข้อมูลแบบมีโครงสร้าง |
AI_RATE_LIMIT_PER_HOUR |
var | จำนวนการเรียก AI ที่อนุญาตต่อไซต์ต่อชั่วโมง ค่าเริ่มต้น 250 |
CF_IMAGES_API_TOKEN |
secret | การอัปโหลดเมื่อ STORAGE_PROVIDER เป็น cf-images |
R2_PUBLIC_DOMAIN |
var | ที่อยู่สาธารณะที่ให้บริการ media ของ R2 setup เขียนค่านี้ media ของ R2 ต้องใช้ |
CF_PURGE_ZONE_ID |
var | การ purge edge cache เมื่อเผยแพร่ ร่วมกับ CF_PURGE_API_TOKEN เฉพาะเมื่อคุณเพิ่ม PUBLIC_CACHE_MAX_AGE |
CF_PURGE_API_TOKEN |
secret | token ที่มี Zone → Cache Purge สำหรับ zone นั้น |
RESEND_API_KEY |
secret | การเข้าสู่ระบบด้วย magic link อีเมลและรหัสของคำเชิญ และการส่งลิงก์รหัสผ่านที่ผู้ดูแลออกผ่าน Resend ต้องมี MAIL_FROM หากไม่มีทั้งสอง magic link จะใช้ไม่ได้ และลิงก์คำเชิญและลิงก์รหัสผ่านจะแสดงให้ผู้ดูแลส่งต่อเอง |
MAIL_FROM |
var | ที่อยู่ผู้ส่ง เช่น Dee Wan <cms@example.com> ต้องเป็นผู้ส่งที่ยืนยันแล้วที่ Resend หรือที่ตัวส่งอีเมลของคุณเอง |
MAIL_TRANSPORT_URL |
var | ที่อยู่ https:// ของบริการอีเมลของคุณเอง เมื่อตั้งแล้วจะใช้แทน Resend กับทุกข้อความ ต้องมี MAIL_TRANSPORT_TOKEN และ MAIL_FROM หากไม่มีทั้งสอง อีเมลจะรายงานว่าไม่ได้ตั้งค่า และลิงก์จะแสดงให้ส่งต่อเอง ที่อยู่ที่ไม่ใช่ https หรือไม่เป็นสาธารณะจะถูกปฏิเสธ ดู ตัวส่งอีเมล |
MAIL_TRANSPORT_TOKEN |
secret | โทเคน Bearer ที่ Dee Wan ส่งไปยัง MAIL_TRANSPORT_URL |
AUTH_INITIAL_METHODS |
var | วิธีที่เสนอได้ก่อนมีผู้ดูแลคนแรก คั่นด้วยจุลภาค: password, magic_link, google, github ค่าเริ่มต้นคือ password วิธีที่ขาด binding ยังใช้ไม่ได้ |
GOOGLE_CLIENT_ID |
var | Google OAuth client สำหรับเข้าสู่ระบบ CMS Callback: BACKEND_URL/api/auth/callback/google |
GOOGLE_CLIENT_SECRET |
secret | Secret ของ Google OAuth client สำหรับเข้าสู่ระบบ |
GITHUB_CLIENT_ID |
var | GitHub OAuth App สำหรับเข้าสู่ระบบ CMS Callback: BACKEND_URL/api/auth/callback/github แยกจาก ซอร์สโค้ดและการเผยแพร่ และ device flow ของ CLI |
GITHUB_CLIENT_SECRET |
secret | Secret ของ GitHub OAuth App สำหรับเข้าสู่ระบบ |
GITHUB_APP_ID, GITHUB_APP_SLUG, GITHUB_APP_CLIENT_ID |
var | GitHub App สำหรับ การตั้งค่า → ซอร์สโค้ดและการเผยแพร่ (การเชื่อมต่อรีโพซิทอรีและการจัดการดีพลอย) หากไม่มีค่า GITHUB_APP_* ครบทั้งห้า หน้าจอนั้นจะรายงาน github_app_not_configured |
GITHUB_APP_CLIENT_SECRET, GITHUB_APP_PRIVATE_KEY |
secret | ส่วนที่เหลือของ GitHub App นั้น |
PLUGIN_CATALOGUE_URLS |
var | ส่วน «ค้นหาปลั๊กอิน» ใน การตั้งค่า → ปลั๊กอิน URL ของแคตตาล็อกปลั๊กอินคั่นด้วยจุลภาค ต้องเป็น https:// อ่านได้สูงสุด 4 รายการ ค่าเริ่มต้นไม่มี การอยู่ในแคตตาล็อกไม่ได้ให้สิทธิ์อะไร การติดตั้งยังตรวจ manifest เหมือนเดิม ดู docs/plugins/security.md |
OPERATOR_SENTRY_DSN |
secret | ส่งรายงานข้อผิดพลาดที่ทำความสะอาดแล้วไปยังโปรเจกต์ Sentry ของคุณเอง |
DEEWAN_ERROR_REPORTING |
var | off หยุดการส่งรายงานไปยังโปรเจกต์ Sentry ของ Dee Wan |
TEMPLATE_ARTIFACTS |
binding | template ของไซต์: bucket R2 แบบ private ที่ bind ไว้ใต้ r2_buckets เก็บ source, ผลลัพธ์ที่ compile แล้ว และรายงาน gate ของ template candidate แต่ละตัว การยอมรับ template ต้องใช้เพียงค่านี้ ดู docs/MANAGED-TEMPLATES.md |
TEMPLATE_BUILD_SERVICE_URL |
var | การอัปโหลด template ของไซต์ และการสร้าง template เมื่อมี DEEPINFRA_API_KEY คือ origin ของ host ที่รัน npm run template-build-service: origin https:// เปล่า ๆ หรือ http:// บน localhost, 127.0.0.1 หรือ [::1] ต้องมี TEMPLATE_BUILD_SERVICE_KEY, TEMPLATE_SANDBOX_IMAGE และ TEMPLATE_ARTIFACTS ด้วย |
TEMPLATE_BUILD_SERVICE_KEY |
secret | ลงนามทุก request สำหรับ build build host ถือค่าเดียวกัน key ที่สั้นกว่า 32 ตัวอักษรนับว่าไม่ได้ตั้งค่า |
TEMPLATE_PREVIEW_SERVICE_URL |
var | การ preview template candidate ของไซต์ คือ origin ของ preview host ตามกฎเดียวกัน host เดียวอาจให้บริการทั้งสองอย่างได้ ต้องมี TEMPLATE_PREVIEW_SERVICE_KEY, TEMPLATE_SANDBOX_IMAGE และ TEMPLATE_ARTIFACTS ด้วย |
TEMPLATE_PREVIEW_SERVICE_KEY |
secret | ลงนามทุก request สำหรับ preview preview host ถือค่าเดียวกัน key ที่สั้นกว่า 32 ตัวอักษรนับว่าไม่ได้ตั้งค่า |
TEMPLATE_SANDBOX_IMAGE |
var | container image ที่ build host และ preview host ใช้รันโค้ดที่ถูกสร้างขึ้น ตรึงด้วย digest (<repository>@sha256:<64 hex>) tag นับว่าไม่ได้ตั้งค่า การอัปโหลด การสร้าง และการ preview ต้องใช้ค่านี้ |
MANAGED_RENDER_HMAC_KEY |
secret | ลงนามการ render ดีไซน์ของไซต์แบบตรงตัวใน page editor key ที่สั้นกว่า 32 ตัวอักษรนับว่าไม่ได้ตั้งค่า การ render นี้ต้องมี managed renderer release ที่ใช้งานอยู่ด้วย หากไม่มี ไซต์จะเห็น Structure preview การเตรียม การเปิดใช้งาน และการย้อนกลับ release ก็ต้องใช้ key นี้ด้วย: admin ส่งให้ deployment service เฉพาะ key ของแต่ละไซต์ที่ derive มาจาก key นี้ ห้ามให้ค่านี้แก่ renderer ของไซต์หรือ deployment service |
MANAGED_RENDER_DEPLOY_SERVICE_URL |
var | การเตรียม การเปิดใช้งาน และการย้อนกลับ managed renderer release คือ origin ของ host ที่รัน npm run managed-deploy-service: origin https:// เปล่า ๆ หรือ http:// บน localhost, 127.0.0.1 หรือ [::1] ต้องมี MANAGED_RENDER_DEPLOY_SERVICE_KEY, MANAGED_RENDER_INSTALLATION_ID, MANAGED_RENDER_HMAC_KEY, TEMPLATE_ARTIFACTS และ site binding ที่ใช้งานอยู่ของไซต์ด้วย |
MANAGED_RENDER_DEPLOY_SERVICE_KEY |
secret | ลงนามทุก request สำหรับ deployment และตรวจสอบทุก receipt deployment host ถือค่าเดียวกัน ยาวอย่างน้อย 32 ตัวอักษร |
MANAGED_RENDER_INSTALLATION_ID |
var | id ของการติดตั้งนี้ที่คงที่และไม่ใช่ความลับ: ตัวอักษรอังกฤษพิมพ์เล็ก ตัวเลข และขีดกลาง ยาว 3 ถึง 63 ตัวอักษร ชื่อ renderer Worker ของแต่ละไซต์ derive มาจากค่านี้และ id ของไซต์ ห้ามเปลี่ยนค่านี้หลัง release แรก |
การสร้าง การอัปโหลด การ preview หรือการยอมรับ template ของไซต์โดยไม่มีการตั้งค่าที่จำเป็นจะตอบ
503 template_operation_unavailable พร้อมชื่อ operation และชื่อของสิ่งที่ขาด ไม่ใช่ค่าของมัน
การตั้งค่าสำหรับ build และ preview ไม่ deploy สิ่งใด และการยอมรับ template ไม่เปลี่ยนแปลงสิ่งที่ใช้งานจริงอยู่เลย
release ถูกส่งมอบโดย deployment service แยกต่างหากซึ่งถือ Cloudflare API token ส่วน admin Worker
ไม่เคยถือ token นี้ หากไม่มีการตั้งค่าสำหรับการส่งมอบ ส่วน การตั้งค่า จะแสดงสิ่งที่ขาด ดู
docs/MANAGED-TEMPLATES.md
admin API คุยกับ AI provider ผ่าน /api/ai/* บน Worker เท่านั้น ซึ่งถือ key และ
บังคับใช้ quota รายชั่วโมง
รายงานข้อผิดพลาด ข้อผิดพลาดที่ไม่ได้จัดการสามารถรายงานพร้อมประเภทข้อผิดพลาด ข้อความที่ทำความสะอาดแล้ว stack
frame และ route — ไม่มีเนื้อหา ค่าในฟอร์ม อีเมล หรือ credential เลย เมื่อตั้ง
OPERATOR_SENTRY_DSN รายงานจะไปที่โปรเจกต์ Sentry ของคุณ build นี้ไม่มีที่อยู่ Sentry ของ Dee Wan
ดังนั้นไม่มีอะไรถูกส่งไปยัง Dee Wan เว้นแต่ตั้ง DEEWAN_SENTRY_DSN จากนั้น การติดตั้ง → รายงานข้อผิดพลาด (เฉพาะ superadmin) จะแสดง บิลด์นี้ไม่มีปลายทางของ Dee Wan ไม่มีการส่งอะไร สวิตช์บนหน้าจอนั้นและ DEEWAN_ERROR_REPORTING=off มีผลเฉพาะกับรายงานไปยัง Dee Wan
ไม่ใช่ DSN ของคุณเอง secret เป็นของ Worker ตัวเดียว หากต้องการให้ข้อผิดพลาดของ Worker สำหรับอ่านสาธารณะ
ถูกรายงานด้วย ให้ตั้ง DEEWAN_SENTRY_DSN หรือ OPERATOR_SENTRY_DSN บน Worker นั้นด้วย
(npx wrangler secret put <NAME> --config wrangler.public.jsonc)
npm run deploy # admin UI (Pages), admin Worker, and the public read Workernpm run health # post-deploy checks; with Access on, also checks the perimeterdeploy build admin UI โดยตั้ง PUBLIC_BACKEND_URL ใน environment ของ build เป็น
FRONTEND_URL จาก backend/wrangler.jsonc ไม่ต้องมี frontend/.env มันปฏิเสธการส่ง
admin Worker ขณะที่ฐานข้อมูลมี migration ค้างอยู่ หรือเมื่อมันบอกไม่ได้ — ให้ apply ด้วย
npm run migrate:d1 ก่อน หรือส่ง --skip-migration-check เมื่อคุณรู้ว่าโค้ดใหม่ไม่
ต้องการมัน
การอัปเกรดไปยัง release ที่ใหม่กว่า (pull, ติดตั้งใหม่, migrate, deploy) อธิบายทีละขั้นใน การติดตั้ง Dee Wan
Migration
หัวข้อที่มีชื่อว่า “Migration”การติดตั้งใหม่ไม่ต้องใช้สิ่งนี้เลย — setup apply schema ให้ หลังจากนั้น:
| คำสั่ง | ใช้กับ |
|---|---|
npm run migrate:d1 |
ฐานข้อมูลควบคุมที่ deploy แล้ว |
npm run tenant:upgrade |
ฐานข้อมูลรายไซต์ที่สร้างโดย provision:site |
npm run local:migrate |
ฐานข้อมูลของ local rig (backend/wrangler.dev.jsonc) ใช้ได้กับทุก clone |
npm run migrate:d1:local |
mirror บน local ของการตั้งค่าที่ติดตั้งแล้ว อ่าน backend/wrangler.jsonc จึงล้มเหลวบน clone ที่ไม่เคยติดตั้ง |
migration คือ Prisma migration ใต้ backend/prisma/migrations/ ซึ่งถูก mirror ไปยัง
backend/migrations-wrangler/ สำหรับ D1 โดย npm run migrate:sync (npm run migrate:check ตรวจ
mirror) schema.prisma ประกอบจากไฟล์ fragment ให้แก้ fragment การ apply ไม่เคย
เขียน migration การเขียน migration เป็นขั้นตอนแยกที่ต้องสั่งชัดแจ้ง ดู
Migration ของฐานข้อมูล สำหรับ workflow ฉบับเต็ม
ผู้ให้บริการ AI
หัวข้อที่มีชื่อว่า “ผู้ให้บริการ AI”DeepInfra ยังเป็นค่าเริ่มต้น หากต้องการใช้ผู้ให้บริการอื่นที่มี API เข้ากันได้กับ OpenAI
ให้ตั้งค่าตัวแปรด้านล่างและเก็บคีย์ด้วย wrangler secret put AI_API_KEY จากไดเรกทอรี backend/:
| ตัวแปร | ค่า |
|---|---|
AI_PROVIDER |
openai-compatible |
AI_BASE_URL |
ที่อยู่ฐาน API เช่น https://inference.example/v1 ต้องไม่มีข้อมูลเข้าสู่ระบบ พารามิเตอร์คำขอ หรือส่วน fragment |
AI_TEXT_MODEL |
โมเดลแชทเริ่มต้น ใช้สำหรับการแปลและการสร้างข้อมูลแบบมีโครงสร้างด้วย |
AI_VISION_MODEL |
โมเดลที่รับภาพได้สำหรับคำอธิบายสื่อ ไม่บังคับ |
AI_IMAGE_MODEL |
โมเดลสร้างภาพ ไม่บังคับ หากไม่ได้ตั้งค่า การสร้างภาพจะใช้ไม่ได้ |
AI_TEXT_MODELS, AI_VISION_MODELS, AI_IMAGE_MODELS |
ID โมเดลเพิ่มเติมสำหรับแต่ละตัวเลือก คั่นด้วยจุลภาค สูงสุด 100 โมเดลต่อความสามารถ รวมโมเดลเริ่มต้น |
รายการโมเดลของผู้ให้บริการที่เข้ากันได้ใช้การตั้งค่าที่ตรวจสอบแล้วนี้ ไม่เดาความสามารถจากรายการ
โมเดลของผู้ให้บริการ และไม่แสดงราคาที่ไม่ทราบ ใช้ ID ที่ผู้ให้บริการรองรับจริง การสร้างภาพขอข้อมูล
b64_json ในคำตอบ การเชื่อมต่อนี้ไม่รองรับผู้ให้บริการที่ส่งกลับเฉพาะ URL ของภาพ ต้องใช้ HTTPS
ยกเว้น localhost ระหว่างพัฒนาในเครื่อง คำขอจากไคลเอนต์เปลี่ยนที่อยู่ผู้ให้บริการหรือคีย์ไม่ได้
เลือกโมเดลที่ตั้งค่าไว้ใน การตั้งค่า → การสร้าง คีย์ยังเป็นความลับของ Worker และไม่อยู่ใน การตั้งค่าเว็บไซต์ คำขอจากเบราว์เซอร์ หรือโค้ดที่สร้างขึ้น ทั้งสองการเชื่อมต่อใช้โควตาของเว็บไซต์ ขั้นตอนตรวจผลก่อนนำไปใช้ และการจัดการข้อผิดพลาดแบบเดียวกัน การเปลี่ยนผู้ให้บริการไม่เปลี่ยน โมเดลที่บันทึกไว้ ให้เลือก ID ที่ผู้ให้บริการใหม่รองรับ
การนำเนื้อหาเข้า และนำออก
หัวข้อที่มีชื่อว่า “การนำเนื้อหาเข้า และนำออก”ทั้งสองอยู่ใน admin ที่ การตั้งค่า → ย้ายข้อมูล — ไม่ต้องใช้ terminal ไม่ต้องแก้ JSON
- นำเข้า: archive ที่ export จาก Strapi (
.tar/.tar.gzทดสอบกับ Strapi 4.25.9 และ 5.51.1) หรือ สำเนาเว็บไซต์ Dee Wan (.json) ที่ export จากการติดตั้งอื่น wizard ตรวจ archive แสดงสิ่งที่พบ map ประเภทและภาษา ตรวจแผน แล้วรัน ไม่มีสิ่งใด ถูกเขียนทับ: การนำเข้าสร้างเนื้อหาหรือข้ามไป และงานทั้งหมด undo ได้ - ส่งออก: ดาวน์โหลดสำเนาเว็บไซต์ เขียนไฟล์เดียวที่มี model, ฟิลด์, ภาษา, workflow, settings, เนื้อหาปัจจุบัน, เวอร์ชันที่เผยแพร่ในที่ที่ต่างกัน และ byte ที่แน่นอนของทุกภาพ หากภาพใดอ่านจาก R2 หรือ Cloudflare Images ได้ไม่ตรงทุกประการ การ ดาวน์โหลดจะถูกปฏิเสธโดยระบุชื่อ แทนที่จะเขียนสำเนาที่ไม่ครบ
- สเปรดชีต (CSV / Excel) อัปเดตแถวที่มีอยู่แล้ว โดยเริ่มจากรายการเนื้อหาของ model หนึ่ง
การนำเข้า archive ต้องมี IMPORT_BUCKET ส่วนตัว npm run setup เสนอให้สร้าง และ
npm run doctor รายงานว่าเปิดใช้อยู่หรือไม่ ทุกอย่างอื่นทำงานได้โดยไม่มีมัน การนำเข้า
สร้างแล้วแต่ยังไม่ครบสำหรับ 1.0 ดูขอบเขตผลิตภัณฑ์ 1.0
การลงชื่อเข้าใช้ และการกลับเข้ามาใหม่
หัวข้อที่มีชื่อว่า “การลงชื่อเข้าใช้ และการกลับเข้ามาใหม่”ปิดการลงทะเบียนสาธารณะ บัญชีจะสร้างได้ผ่านผู้มีสิทธิ์เท่านั้น หากตั้งค่าการส่งอีเมลไว้ ผู้ใช้ที่มีบัญชีอยู่แล้วสามารถขอลิงก์รีเซ็ตรหัสผ่านจากหน้าเข้าสู่ระบบได้ เจ้าของบัญชีเป็นผู้ตั้งรหัสผ่าน ผ่านลิงก์ใช้ครั้งเดียว ผู้ส่งลิงก์ไม่ได้เป็นผู้เลือกรหัสผ่าน
ทุกลิงก์ด้านล่างใช้ได้ครั้งเดียว หมดอายุใน 15 นาที และแสดงเพียงครั้งเดียวพอดี เก็บเพียง hash ของมัน ดังนั้นไม่มีอะไรแสดงมันซ้ำได้ การออกลิงก์ใหม่ทำให้ลิงก์แรกใช้ไม่ได้ รหัสผ่านต้องยาว อย่างน้อย 12 ตัวอักษร
การ claim การติดตั้งใหม่
หัวข้อที่มีชื่อว่า “การ claim การติดตั้งใหม่”ตัวติดตั้งแสดง claim link ตอนจบการติดตั้งใหม่ เปิดลิงก์แล้วเลือกวิธีที่ตั้งค่าไว้ ได้แก่ รหัสผ่าน,
magic link, Google หรือ GitHub ทุกวิธีต้องยืนยันที่อยู่หลัง normalize จาก
BOOTSTRAP_ADMIN_EMAIL ให้ตรงกัน หน้ารับสิทธิ์เปลี่ยนที่อยู่นี้ไม่ได้ หลังเข้าสู่ระบบ เจ้าของบัญชีสามารถเปลี่ยนอีเมลได้ที่
หน้า ความปลอดภัยของบัญชี โดยยืนยันที่อยู่ใหม่ก่อน
หากลิงก์หมดอายุโดยไม่ได้ใช้ ให้รันตัวติดตั้งอีกครั้ง (npm run setup หรือ
npm run install:cms -- resume) มันจะออกลิงก์ใหม่ตราบที่ยังไม่มีใคร claim การติดตั้ง
สำหรับการติดตั้งที่ยังไม่มีผู้รับสิทธิ์ ให้แทนลิงก์ที่สูญหายหรือหมดอายุอย่างชัดเจน:
npm run claim:link -- --remote --bootstrap --email owner@example.comหากไม่มี --bootstrap คำสั่งจะคืนบัญชี active superadmin เพียงคนเดียวให้เจ้าของ และปฏิเสธเมื่อ
ไม่มีบัญชีดังกล่าว ดู สร้างและเปลี่ยนผู้ดูแลระบบคนแรก
มีคนลืมรหัสผ่าน
หัวข้อที่มีชื่อว่า “มีคนลืมรหัสผ่าน”superadmin สร้างลิงก์จากรายการ ผู้ใช้ เมื่อตั้งค่าอีเมลไว้ (RESEND_API_KEY และ
MAIL_FROM) ลิงก์จะถูกส่งทางอีเมลด้วย ไม่ว่าแบบใด ลิงก์จะแสดงครั้งเดียวให้ superadmin ส่งต่อ
ด้วยวิธีใดก็ได้
superadmin คนสุดท้ายถูกล็อกออก
หัวข้อที่มีชื่อว่า “superadmin คนสุดท้ายถูกล็อกออก”นี่คือกรณีเดียวที่ไม่มีใครอื่นแก้ได้ จึงต้องใช้ credential ของ deployment:
npm run claim:link -- --remote --email locked-out@example.comมันปฏิเสธเว้นแต่ที่อยู่นั้นเป็น superadmin ที่ active เพียงคนเดียว หากมีสองคน อีกคน ควรออกลิงก์จากรายการ ผู้ใช้ แทน
บัญชีของคุณเอง
หัวข้อที่มีชื่อว่า “บัญชีของคุณเอง”ผู้ใช้ที่เข้าสู่ระบบทุกคนเปิด ความปลอดภัยของบัญชี จากเมนูตัวตนได้ เพื่อเปลี่ยนภาษาของหน้าผู้ดูแล ยกเลิกการเชื่อมต่อ Google หรือ GitHub ของตนเอง และจัดการพาสคีย์ของตนเอง ดู ความปลอดภัยของบัญชี
การพัฒนา
หัวข้อที่มีชื่อว่า “การพัฒนา”cd backend && npm test # backend unit tests (Vitest, local SQLite)cd frontend && npm test -- --run # admin UI unit tests (Vitest, single run)cd frontend && npm run check # admin UI type checknpm run lint # lint the backend and scriptsnpm run typecheck:scripts # type check scripts/npm run submodules:check # fail if a submodule pin or worktree has driftedหากต้องการรัน admin Worker บน local จาก backend/wrangler.jsonc ที่ติดตั้งแล้ว แทน dev
config ที่ถูก track ให้ใช้ npm run dev:install --workspace backend
การติดตั้งและการดำเนินงาน:
| คำสั่ง | ทำอะไร |
|---|---|
npm run doctor |
preflight แบบ read-only: ระบุสิ่งที่ขาดและวิธีแก้ |
npm run plan |
read-only: ทุกขั้นตอนการติดตั้งและสถานะ จากไฟล์บนดิสก์ -- --json สำหรับเครื่อง |
npm run setup |
การติดตั้งแบบโต้ตอบ: จัดเตรียม apply schema build และ deploy ทุกอย่าง แสดง claim link |
npm run install:cms -- <verb> |
ตัวติดตั้งตาม verb: plan, apply, resume, doctor, verify, teardown, manifest |
npm run install:web |
ตัวติดตั้งแบบเว็บบน 127.0.0.1 ไม่ใช่เส้นทางการติดตั้งที่รองรับ: ต้องใช้ Cloudflare OAuth application ของคุณเอง (DEEWAN_CF_OAUTH_CLIENT_ID) ดูตัวอย่างตัวติดตั้งแบบเว็บ |
npm run install:web:dry-run |
ตัวติดตั้งแบบเว็บที่จำลองผลกระทบภายนอกทั้งหมด สำหรับตรวจทาน ไม่เปลี่ยนทรัพยากรภายนอก |
npm run deploy |
build และ deploy admin UI และ Worker ทั้งสอง --config, --public-config, --admin-only, --skip-migration-check |
npm run health |
การตรวจหลัง deploy กับที่อยู่ที่ deploy แล้ว |
npm run probe |
การตรวจการเข้าถึงได้แบบไม่ระบุตัวตนและ read-only |
npm run verify -- --read-only --public <url> |
การตรวจหลัง deploy ที่ไม่เขียนอะไรเลย --model <slug> อ่าน model หนึ่งตัว |
npm run verify -- --admin <url> --public <url> --email <addr> --disposable |
การตรวจเต็มรูปแบบบน deployment แบบใช้แล้วทิ้ง: สร้างไซต์ model และเนื้อหา ต้องมี VERIFY_PASSWORD |
npm run migrate:d1 |
apply migration ที่ค้างอยู่กับฐานข้อมูลควบคุมที่ deploy แล้ว |
npm run migrate:d1:local |
เช่นเดียวกัน กับ mirror บน local ของการตั้งค่าที่ติดตั้งแล้ว |
npm run provision:site -- --site <id> |
ให้ไซต์หนึ่งมีฐานข้อมูล D1 ของตัวเองและ redeploy Worker ทั้งสอง --plan เพื่อดูตัวอย่าง --repair เพื่อตรวจซ้ำ มีค่าใช้จ่าย |
npm run tenant:upgrade |
apply การเปลี่ยน schema รายไซต์ที่ค้างอยู่กับทุกฐานข้อมูลรายไซต์ที่ active --plan, --site <id> |
npm run claim:link |
ออกลิงก์รหัสผ่านใช้ครั้งเดียวสำหรับ active superadmin เพียงคนเดียว เพิ่ม --bootstrap เพื่อแทน claim link ของผู้ดูแลคนแรกใน installation ที่ยังไม่มีผู้รับสิทธิ์ |
npm run revoke:sessions |
ทางฉุกเฉิน: ลงชื่อออกทุกคน |
npm run teardown |
ลบสิ่งที่ setup บันทึกไว้ว่าการติดตั้งหนึ่งชุดสร้างขึ้น ค่าเริ่มต้นคือ backend/wrangler.jsonc พร้อม config ของ public และ intake เป็น dry run เว้นแต่ใช้ --apply เก็บทรัพยากรที่นำมาใช้ ที่เปลี่ยนไป และที่อ่านไม่ได้ไว้ ดูเริ่มใหม่หรือรื้อถอน |
npm run backend:generate -- --site <id> --source <cms.sqlite> --dest <dir> --db <scratch.sqlite> |
สร้างแบ็กเอนด์อิสระบน local จากสำเนา SQLite ของฐานข้อมูล CMS ไม่ deploy อะไร ไซต์ที่มี managed renderer release ที่ใช้งานอยู่ต้องใส่ --template-artifacts <dir> เพิ่ม คือสำเนา local ของ template artifact ของ release นั้น ซึ่งจะถูก export ไปที่ managed-renderer/ |
npm run backend:generate:all |
เช่นเดียวกัน สำหรับทุกไซต์ ไม่ deploy อะไร ส่ง --template-artifacts ไม่ได้ ดังนั้นไซต์ที่มี managed renderer release ที่ใช้งานอยู่จะถูกปฏิเสธที่นี่ ให้รัน npm run backend:generate สำหรับไซต์นั้นแยกต่างหากพร้อม --template-artifacts <dir> |
npm run template-build-service |
รัน service สำหรับ build และ preview managed template บน build host ทุก build และทุก preview รันใน container ใหม่ของ sandbox image ที่ตรึงด้วย digest จะไม่เริ่มทำงานเว้นแต่มี key สำหรับ build หรือ preview ยาวอย่างน้อย 32 ตัวอักษร, origin ใน TEMPLATE_SERVICE_AUDIENCE และค่าที่ถูกต้องของทุกการตั้งค่า TEMPLATE_SANDBOX_* และปฏิเสธการรันในฐานะ root ให้บริการ HTTP ธรรมดาที่ TEMPLATE_SERVICE_HOST:TEMPLATE_SERVICE_PORT (ค่าเริ่มต้น 127.0.0.1:8790) และทำทีละหนึ่ง operation admin เรียกเฉพาะ origin https:// (หรือ http:// บน loopback) ดังนั้น host ระยะไกลต้องมี TLS อยู่ด้านหน้า ไม่ถือ credential สำหรับ deploy ไม่ deploy อะไร ดู docs/MANAGED-TEMPLATES.md |
npm run template-sandbox:context -- --out <dir> --node-image <node@sha256:…> |
เขียน build context ของ sandbox image สำหรับ template --out ต้องเป็นไดเรกทอรีใหม่หรือว่าง และ --node-image ต้องระบุ image ด้วย digest อ่านเวอร์ชันของ npm, Wrangler, playwright-core และ axe-core จาก checkout นี้ ดังนั้นให้ติดตั้ง dependency ก่อน ไม่ build ไม่ pull และไม่ push อะไร |
npm run managed-deploy-service |
รัน managed renderer deployment service บน host ที่เชื่อถือได้ service นี้ถือ Cloudflare API token ที่ใช้อัปโหลด deploy และกำหนด route ให้ renderer Worker ของแต่ละไซต์ ส่วน admin Worker ไม่เคยถือ token นี้ service ยังอ่าน identity ของ renderer แต่ละตัวให้ admin ตรวจสอบด้วย จะไม่เริ่มทำงานหากการตั้งค่าที่จำเป็นขาดหรือไม่ถูกต้อง ดู docs/MANAGED-TEMPLATES.md |
npm run wire:github -- --repo <owner/name> |
push โปรเจกต์ที่สร้างขึ้นไปยัง GitHub และปิดผนึก secret ที่ build workflow ของมันอ่าน |
npm run backend:deliver -- --site <id> --repo <owner/name> --source <cms.db> --dest <dir> --db <target.db> |
ส่งมอบไซต์เป็น repository ของคุณเองและ deploy ที่นั่น --media ยังย้าย media ที่เผยแพร่แล้วไปยัง R2 ของคุณด้วย รับ --template-artifacts <dir> เหมือน backend:generate ไม่ deploy managed renderer |
curl -H "X-Site-Id: <id>" -b "<session>" <admin>/api/models/public-client.ts |
ดาวน์โหลด TypeScript client ที่มี type และไม่มี dependency สำหรับ public read API ของไซต์ |
Local rig:
| คำสั่ง | ทำอะไร |
|---|---|
npm run local:migrate |
apply schema กับฐานข้อมูล local ไม่ต้องใช้ credential |
npm run local:api |
admin Worker บน http://localhost:8787 |
npm run local:public |
public read Worker บน http://127.0.0.1:8788 |
npm run local:seed |
ไซต์ fixture บวก corpus ที่สมจริง idempotent |
npm run local:seed:fixture |
เฉพาะไซต์ fixture |
npm run local:seed:corpus |
เฉพาะ corpus |
npm run local:admin |
admin UI บน http://localhost:5173 กับ Worker บน local |
ผู้ร่วมพัฒนา:
| คำสั่ง | ทำอะไร |
|---|---|
npm run test:boot |
เริ่ม Worker ทั้งสองภายใต้ runtime ที่ pin ไว้ และล้มเหลวหากตัวใดปฏิเสธการ boot |
npm run test:e2e |
ชุดทดสอบเบราว์เซอร์แบบ end-to-end (Cypress) กับ dev server ที่มันเริ่มเอง E2E_REAL_BACKEND=1 เพิ่ม Workers จริง จากนั้น spec ของตัวแก้ไขแบบเต็มจอจะได้ Astro renderer ที่ถูกสร้างบน E2E_EDITOR_PORT ด้วย (ค่าเริ่มต้น 43189) การ build ครั้งแรกต้องใช้ npm registry spec ของ release ใน Scheduling ยังได้ปลั๊กอิน Scheduling บน E2E_PLUGIN_PORT ด้วย (ค่าเริ่มต้น 43190) |
npm run migrate:sync |
สร้าง backend/migrations-wrangler/ ใหม่จาก Prisma migration |
npm run migrate:check |
ล้มเหลวหาก mirror นั้นล้าสมัย |
npm run prisma:generate |
build schema.prisma ใหม่จาก fragment และสร้าง Prisma client ใหม่ |
npm run prisma:drift |
ล้มเหลวหาก schema.prisma ไม่อธิบายสิ่งที่ migration สร้างอีกต่อไป |
npm run tenant:schema |
สร้าง schema ที่ฐานข้อมูลรายไซต์ใหม่ใช้เริ่มต้นใหม่ |
npm run tenant:schema:check |
ล้มเหลวหาก schema นั้นล้าสมัย |
npm run docs:api |
สร้าง docs/PUBLIC-API.md ใหม่ |
npm run docs:plugins |
สร้างเอกสาร plugin protocol และ JSON Schema ใหม่ |
npm run contract:embed |
สร้าง ข้อกำหนดข้อมูลหน้า ที่ฝังไว้ใหม่หลังแก้ backend/src/lib/page-contract/ |
npm run submodules:sync |
initialise หรืออัปเดต submodule ใน packages/ |
npm run submodules:check |
ล้มเหลวเมื่อ pin หรือ worktree ของ submodule drift |
npm run lint |
lint backend และ script |
npm run typecheck:scripts |
ตรวจ type ของ scripts/ |
npm run test:scripts-offline |
รันการตรวจแบบออฟไลน์ของโค้ด deployment และ auth ที่ถูกสร้าง ด้วย type stripping ของ Node |
npm run guard-editor:check |
ตรวจ type ของแพ็กเกจ guard editor และสัญญากับ CMS |
npm run guard-editor:test |
รันเทสต์ของแพ็กเกจ guard editor และการตรวจสัญญา |
npm run test:guard-editor-contract |
build แกนของ guard editor และรันเฉพาะการตรวจสัญญา CI รันคำสั่งนี้ |
npm run acceptance -- plan |
แสดงเส้นทาง acceptance ของ release ไม่รันอะไร |
npm run acceptance -- run --account <id> --confirm-disposable |
รันเส้นทางนั้นกับบัญชี Cloudflare แบบใช้แล้วทิ้ง และบันทึก ledger สร้างทรัพยากรที่มีค่าใช้จ่ายและทิ้งไว้ |
npm run acceptance -- report --account <id> |
แสดง ledger นั้น |
npm run public:query-probe -- --confirm-disposable … |
ทดสอบ filter ของ public API กับ deployment แบบใช้แล้วทิ้ง แล้วคืนค่าสิ่งที่มันเปลี่ยน อย่าชี้มันไปที่ production |
การมีส่วนร่วม
หัวข้อที่มีชื่อว่า “การมีส่วนร่วม”ยินดีรับ pull request มีสองแนวปฏิบัติ:
packages/เป็น submodule — commit และ push ที่นั่นก่อน แล้วค่อยขยับ pointer- route ที่จำกัดขอบเขตตามไซต์ต้องผ่านชั้นข้อมูลที่จำกัดขอบเขตตามไซต์ ซึ่งเพิ่มไซต์ลงในทุก query การข้ามมันคือวิธีที่ข้อมูลของไซต์หนึ่งรั่วไปยังอีกไซต์
การรันตัวติดตั้งกับบัญชีที่ใช้ร่วมกัน
หัวข้อที่มีชื่อว่า “การรันตัวติดตั้งกับบัญชีที่ใช้ร่วมกัน”ชื่อทรัพยากรเริ่มต้น (dee-wan-cms-backend, dee-wan-cms-db และอื่น ๆ) ตายตัว ดังนั้นการติดตั้ง
สองชุดในบัญชี Cloudflare เดียวจะชนกันด้วยชื่อ
ตั้ง DEEWAN_RESOURCE_PREFIX เพื่อแยก namespace ให้ทุกสิ่งที่การรันจัดเตรียม:
DEEWAN_RESOURCE_PREFIX=test-a1b2 npm run setup # creates test-a1b2-dee-wan-cms-db, …prefix ต้องเป็นตัวอักษรพิมพ์เล็ก ตัวเลข และขีด ยาวไม่เกิน 24 ตัวอักษร teardown ไม่ได้ตัดสิน จากชื่อ: มันลบเฉพาะสิ่งที่ install record ระบุว่าการติดตั้งนี้สร้างขึ้น ดู เริ่มใหม่หรือรื้อถอน
ตั้งค่านี้สำหรับการติดตั้งใหม่ ไม่ใช่การติดตั้งที่มีอยู่ Wrangler หาฐานข้อมูล D1 จากชื่อใน
backend/wrangler.jsonc ดังนั้น prefix จะใช้ได้ก็ต่อเมื่อ setup เขียนชื่อที่มี prefix ลงใน
ไฟล์นั้นแล้ว การเปิดใช้กับการติดตั้งที่ config เก็บชื่อที่ไม่มี prefix จะทำให้ทุกคำสั่ง
ล้มเหลวด้วย Couldn't find a D1 DB with the name or binding '<prefix>-…' หากต้องการย้ายการติดตั้ง
ที่มีอยู่ไปใช้ prefix ให้รัน setup ใหม่
Smoke test ของ deployment
หัวข้อที่มีชื่อว่า “Smoke test ของ deployment”การตรวจสั้น ๆ กับ deployment ที่ live สำหรับหลังทุกการ deploy:
DEEWAN_SMOKE_PAGES=https://admin.example.com \DEEWAN_SMOKE_HOST=https://cms.example.com \npm run smoke --workspace=dee-wan-cms-backendแทนที่ทั้งสองที่อยู่ด้วย origin ของ admin UI และ admin API ของคุณเอง มันไม่ต้องใช้ session และตรวจ สองอย่าง:
- admin UI ให้บริการแอปสำหรับ deep link ไม่ใช่แค่
/—_routes.jsonที่เสียจะทำให้ deep link พังก่อน และไม่มีใครสังเกตขณะนำทางจากหน้าแรก - เมื่อเปิด Access
/api/*บน hostname สาธารณะอยู่หลัง Access เมื่อปิด Access (ค่า เริ่มต้น) API ได้รับการป้องกันด้วยการลงชื่อเข้าใช้แทน และการตรวจนี้ไม่นำมาใช้
เมื่อไม่ได้ระบุที่อยู่ มันจะข้ามแทนที่จะล้มเหลว
License
หัวข้อที่มีชื่อว่า “License”MIT Copyright (c) 2026 ข้อความฉบับสมบูรณ์อยู่ใน LICENSE
สร้างในประเทศไทย 🇹🇭 เพื่อ edge ทั่วโลก
ยังไม่เปิดตัว (pre-MVP) และยังไม่มีเวอร์ชันเสถียร
คอมมิตซอร์สโค้ด: fe23db481c422b40e317b92fc98116b4c0c26a87 (มีการแก้ไขที่ยังไม่คอมมิต)
วันที่สร้างเอกสาร (UTC): 2026-10-18T09:22:34.630Z
คอมมิตสำหรับอัปเกรด: ระบุไม่ได้: มีการแก้ไขที่ยังไม่คอมมิต. บันทึกการเปลี่ยนแปลง