ข้ามไปยังเนื้อหา
Dee Wan 1.0 ยังอยู่ระหว่างพัฒนาและยังไม่เปิดตัว (pre-MVP) — ดู ขอบเขตผลิตภัณฑ์ 1.0

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

Dee Wan CMS — ตราตัวอักษร Dee Wan บนแบนเนอร์ลายไทย

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 ว่าอะไรครอบคลุมและอะไรไม่ครอบคลุม

เริ่มที่นี่:

  • ตัวสร้าง 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 schema
frontend/ SvelteKit admin UI
packages/ submodules: schema-parser, prisma-guard, prisma-rbac, prisma-generator-express, eav-to-prisma,
cache, prisma-query-builder-ui. In this repository: page-contract, plugin-conformance
plugins/ remote plugins built against protocol v1 (Scheduling)
scripts/ install, deploy, migrate, health, teardown

สิ่งนี้รันผลิตภัณฑ์ทั้งหมดกับไฟล์ D1 บน local ในเครื่องของคุณ: ไม่ต้องมีบัญชี ไม่ต้องมี API token ไม่ต้องมี DNS คุณต้องมี Node และ npm ตามที่ระบุในสิ่งที่ต้องมีก่อน

Terminal window
git clone --recurse-submodules https://github.com/dee-wan-cms/dee-wan.git
cd dee-wan
node scripts/install-dependencies.mjs # root and backend dependencies
node scripts/install-dependencies.mjs frontend # admin UI dependencies
npm run local:migrate # apply the schema to the local database
npm 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 ไว้หนึ่งรายการ แล้วเผยแพร่

หากต้องการอ่านสิ่งที่คุณเผยแพร่แบบที่เว็บไซต์อ่าน:

Terminal window
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/article

public Worker หาไซต์จาก header Host และจากสิ่งนั้นเท่านั้น ดังนั้น request ที่ไม่มี header นี้ จะตอบ 404 — กฎเดียวกับที่ deployment ใช้

นำเข้าและส่งออกเนื้อหาได้ที่ การตั้งค่า → ย้ายข้อมูล ลิงก์ ส่งมอบแบ็กเอนด์แบบแยก บน dashboard เปิด การตั้งค่า → ซอร์สโค้ดและการเผยแพร่ เพื่อเชื่อมต่อ repository และจัดการ deployment การสร้างโปรเจกต์เป็นอีกขั้นตอนหนึ่ง ส่วน deployment ต้องมีบัญชี Cloudflare

rig นี้ใช้ backend/wrangler.dev.jsonc ซึ่งถูก track ไว้ ไม่มี credential หรือ account id และ ไม่แตะ 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 ของการติดตั้งเอง

Terminal window
git clone --recurse-submodules https://github.com/dee-wan-cms/dee-wan.git
cd dee-wan
node scripts/install-dependencies.mjs
node scripts/install-dependencies.mjs frontend
npm run setup # provisions everything, builds and deploys the admin UI and both Workers
npm run health # checks the deployment answers

setup สร้างฐานข้อมูล 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 แยกต่างหาก ซึ่งตั้งค่าด้วย backend/wrangler.public.jsonc

npm run setup เขียนไฟล์นั้นให้คุณ เมื่อบัญชี zone และ database id ลงตัวแล้ว และไม่เขียนทับไฟล์ที่มีอยู่ หากหาค่าใดค่าหนึ่งไม่ได้ setup จะบอกโดยระบุ ชื่อแทนการเดา นั่นคือกรณีที่คุณต้องเตรียมไฟล์ด้วยมือ:

Terminal window
cp backend/wrangler.public.example.jsonc backend/wrangler.public.jsonc
# edit backend/wrangler.public.jsonc — account id, D1 id, route
npm run deploy

deploy ปฏิเสธที่จะรันเมื่อไม่มีไฟล์นั้น เพราะการติดตั้งที่ไม่มี 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

setup ต้องใช้ Cloudflare API token มันจะถามหาหากยังไม่ได้ตั้งไว้ และแสดงรายการ สิทธิ์ที่แน่นอนพร้อมเหตุผลของแต่ละสิทธิ์ การติดตั้ง Dee Wan ระบุว่าสิทธิ์ใดขึ้นอยู่กับตัวเลือกของคุณ เช่น domain ของคุณเองหรือ Access npm run doctor แสดงรายการเดียวกัน

Terminal window
export CLOUDFLARE_API_TOKEN=… # optional — skips the prompt
export CLOUDFLARE_ACCOUNT_ID=… # optional — skips the account picker

setup เองไม่ต้องใช้ตัวแปร 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)

secret ไม่ถูกเก็บใน wrangler.jsonc หรือในฐานข้อมูลเลย ตั้งค่าจากไดเรกทอรี backend/:

Terminal window
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)

Terminal window
npm run deploy # admin UI (Pages), admin Worker, and the public read Worker
npm run health # post-deploy checks; with Access on, also checks the perimeter

deploy 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

การติดตั้งใหม่ไม่ต้องใช้สิ่งนี้เลย — 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 ฉบับเต็ม

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 link ตอนจบการติดตั้งใหม่ เปิดลิงก์แล้วเลือกวิธีที่ตั้งค่าไว้ ได้แก่ รหัสผ่าน, magic link, Google หรือ GitHub ทุกวิธีต้องยืนยันที่อยู่หลัง normalize จาก BOOTSTRAP_ADMIN_EMAIL ให้ตรงกัน หน้ารับสิทธิ์เปลี่ยนที่อยู่นี้ไม่ได้ หลังเข้าสู่ระบบ เจ้าของบัญชีสามารถเปลี่ยนอีเมลได้ที่ หน้า ความปลอดภัยของบัญชี โดยยืนยันที่อยู่ใหม่ก่อน

หากลิงก์หมดอายุโดยไม่ได้ใช้ ให้รันตัวติดตั้งอีกครั้ง (npm run setup หรือ npm run install:cms -- resume) มันจะออกลิงก์ใหม่ตราบที่ยังไม่มีใคร claim การติดตั้ง สำหรับการติดตั้งที่ยังไม่มีผู้รับสิทธิ์ ให้แทนลิงก์ที่สูญหายหรือหมดอายุอย่างชัดเจน:

Terminal window
npm run claim:link -- --remote --bootstrap --email owner@example.com

หากไม่มี --bootstrap คำสั่งจะคืนบัญชี active superadmin เพียงคนเดียวให้เจ้าของ และปฏิเสธเมื่อ ไม่มีบัญชีดังกล่าว ดู สร้างและเปลี่ยนผู้ดูแลระบบคนแรก

superadmin สร้างลิงก์จากรายการ ผู้ใช้ เมื่อตั้งค่าอีเมลไว้ (RESEND_API_KEY และ MAIL_FROM) ลิงก์จะถูกส่งทางอีเมลด้วย ไม่ว่าแบบใด ลิงก์จะแสดงครั้งเดียวให้ superadmin ส่งต่อ ด้วยวิธีใดก็ได้

นี่คือกรณีเดียวที่ไม่มีใครอื่นแก้ได้ จึงต้องใช้ credential ของ deployment:

Terminal window
npm run claim:link -- --remote --email locked-out@example.com

มันปฏิเสธเว้นแต่ที่อยู่นั้นเป็น superadmin ที่ active เพียงคนเดียว หากมีสองคน อีกคน ควรออกลิงก์จากรายการ ผู้ใช้ แทน

ผู้ใช้ที่เข้าสู่ระบบทุกคนเปิด ความปลอดภัยของบัญชี จากเมนูตัวตนได้ เพื่อเปลี่ยนภาษาของหน้าผู้ดูแล ยกเลิกการเชื่อมต่อ Google หรือ GitHub ของตนเอง และจัดการพาสคีย์ของตนเอง ดู ความปลอดภัยของบัญชี

Terminal window
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 check
npm run lint # lint the backend and scripts
npm 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 ให้ทุกสิ่งที่การรันจัดเตรียม:

Terminal window
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 ใหม่

การตรวจสั้น ๆ กับ deployment ที่ live สำหรับหลังทุกการ deploy:

Terminal window
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 ได้รับการป้องกันด้วยการลงชื่อเข้าใช้แทน และการตรวจนี้ไม่นำมาใช้

เมื่อไม่ได้ระบุที่อยู่ มันจะข้ามแทนที่จะล้มเหลว

MIT Copyright (c) 2026 ข้อความฉบับสมบูรณ์อยู่ใน LICENSE

สร้างในประเทศไทย 🇹🇭 เพื่อ edge ทั่วโลก


ยังไม่เปิดตัว (pre-MVP) และยังไม่มีเวอร์ชันเสถียร
คอมมิตซอร์สโค้ด: fe23db481c422b40e317b92fc98116b4c0c26a87 (มีการแก้ไขที่ยังไม่คอมมิต)
วันที่สร้างเอกสาร (UTC): 2026-10-18T09:22:34.630Z
คอมมิตสำหรับอัปเกรด: ระบุไม่ได้: มีการแก้ไขที่ยังไม่คอมมิต. บันทึกการเปลี่ยนแปลง