ปลั๊กอิน Scheduling
นี่คือปลั๊กอินแบบ remote service มันตั้งเวลาให้ version ที่ถูก pin หนึ่งตัวถูกเผยแพร่ หรือให้ version ที่เผยแพร่แล้วและถูก pin หนึ่งตัวถูกยกเลิกการเผยแพร่ มันยังรัน release ที่มีชื่อ: กลุ่มรายการเผยแพร่และยกเลิกการเผยแพร่ข้ามโมเดลและภาษา ซึ่งเริ่มดำเนินการในเวลาที่ตั้งไว้หรือทันที มันดำเนินการเปลี่ยนแปลงแต่ละครั้งผ่าน plugin protocol v1 ของ Dee Wan มันมี Cloudflare Worker ของตัวเอง, ฐานข้อมูล D1 ของตัวเอง, cron trigger ของตัวเอง และ UI สำหรับจัดการของตัวเอง ไม่มีโค้ดส่วนใดของมันรันอยู่ภายใน Dee Wan
อินเทอร์เฟซของปลั๊กอิน Scheduling ยังเป็นภาษาอังกฤษ
id ของ manifest คือ dev.dee-wan.scheduling ซึ่งตั้งไว้เป็น PLUGIN_ID ใน src/app.ts และไม่เปลี่ยนระหว่าง release: id ของปลั๊กอินที่ติดตั้งแล้วเปลี่ยนไม่ได้ และ release ที่มี id ต่างออกไปจะถูกปฏิเสธด้วย manifest_identity_changed fork ที่คุณ deploy เป็นปลั๊กอินอีกตัวต้องมี id แบบ reverse-domain ของตัวเอง
ไดเรกทอรีนี้พร้อมเป็น root ของ repository ของตัวเอง คือ https://github.com/dee-wan-cms/dee-wan-scheduling.git จนกว่าจะย้ายจริง มันอยู่ใน repository ของ Dee Wan ที่ plugins/scheduling ขั้นตอนอยู่ในหัวข้อสุดท้าย “การย้ายไปยัง repository ของตัวเอง”
เอกสาร: การทดสอบปลั๊กอิน ตั้งค่าปลั๊กอินนี้ไว้ข้าง Dee Wan ในเครื่อง จากนั้น Scheduling ตั้งแต่ต้นจนจบ จะพาไล่ดูการติดตั้ง การเผยแพร่ตามกำหนดเวลา และความล้มเหลวแต่ละแบบ ฝั่ง core ดู การเขียนปลั๊กอิน, Protocol v1, ความปลอดภัยของปลั๊กอิน และ การทดสอบปลั๊กอิน
ระบบบันทึกข้อมูลความเป็นเจ้าของกำหนดการที่นำเข้าก่อนส่งคำขอ หากคำตอบสูญหาย การยกเลิกจะอ้างอิง
การมอบสิทธิ์เดิม รายการ เวอร์ชันที่บันทึก เวลา และการเปลี่ยนสถานะ พารามิเตอร์ schedule_id ของ
cancel-draft ไม่จำเป็นต้องส่ง หากไม่ส่ง ระบบจะยกเลิกคำขอที่ยังไม่ทราบผล บันทึกการยกเลิกที่เก็บไว้
จะป้องกันไม่ให้คำขอที่มาช้าสร้างกำหนดการ กำหนดการที่สร้างสำเร็จแล้วยังคงอยู่เพื่อให้เลิกทำการนำเข้าแยกต่างหากได้
ความเข้ากันได้
หัวข้อที่มีชื่อว่า “ความเข้ากันได้”| ปลั๊กอิน | Manifest | Dee Wan protocol |
|---|---|---|
| 0.1.0 | v1 | v1 |
| Route | ใคร | ทำอะไร |
|---|---|---|
GET /dee-wan/manifest.json |
admin ของ Dee Wan | Manifest v1 โดยใช้ origin จาก PUBLIC_ORIGIN |
GET /assets/scheduling.css |
เบราว์เซอร์ | stylesheet ของ UI สำหรับจัดการ |
POST /admin/activation-codes |
ผู้ดูแลระบบ (operator) พร้อม Bearer ADMIN_SECRET |
ออกรหัสใช้ครั้งเดียว มีอายุ 15 นาที body {} ออกรหัส activate {"installation_id":"..."} ออกรหัส rotate สำหรับ installation (การติดตั้งหนึ่งชุด) นั้นเท่านั้น ตอบ 201 พร้อม {"code", "purpose", "installation_id", "expires_at"}: purpose เป็น activate หรือ rotate, installation_id เป็น null สำหรับรหัส activate และ expires_at เป็นมิลลิวินาทีนับจาก epoch |
POST /dee-wan/activate |
core ของ Dee Wan | activate สร้าง installation และปฏิเสธ installation ที่มีอยู่แล้ว rotate แทนที่ token แต่ละรหัสใช้ได้ครั้งเดียว |
POST /dee-wan/operations/schedule-status |
core ของ Dee Wan | การดำเนินการ schedule-status รับข้อมูลคำขอเรียกใช้ที่รับเฉพาะคีย์ที่กำหนด แลกรหัสด้วย token ของ installation อ่านรายการที่ผูกไว้ แล้วตอบกำหนดการที่รอ รอลองใหม่ และกำลังทำงานของรายการนั้นเป็นแถว อ่านอย่างเดียว คำขอที่มีคีย์อื่นนอกเหนือจากที่กำหนดได้ 400 installation ที่ไม่รู้จักได้ 404 รหัสที่ core ไม่ยอมแลก การดำเนินการอื่น หรือรายการที่อ่านไม่ได้ จะตอบ status: "refused" |
POST /dee-wan/operations/schedule-column |
core ของ Dee Wan | คอลัมน์ในรายการเนื้อหา schedule-column รับข้อมูลคำขอเรียกใช้ที่รับเฉพาะคีย์ที่กำหนด แลกรหัสของมัน และตอบบล็อก cells หนึ่งบล็อก คือป้ายสีสำหรับแต่ละรายการที่ระบุซึ่งมีกำหนดการที่รออยู่ รอลองใหม่ หรือกำลังรัน (อันที่ใกล้ที่สุด เช่น Publish 2026-09-20 09:00 โทน warning เมื่อรอลองใหม่ หรือรัน) อ่านเฉพาะกำหนดการของ installation นี้และไม่เขียนอะไร รายการที่ไม่มีกำหนดการที่ยังใช้งานอยู่ไม่มีเซลล์ รหัสที่ core ไม่แลกให้ การดำเนินการอื่น รายการที่ผูกไว้ หรืออินพุตที่ไม่ใช่รายการของรหัสรายการ จะได้คำตอบ status: "refused" |
POST /dee-wan/operations/schedule-draft |
core ของ Dee Wan | การดำเนินการ schedule-draft แลกรหัส รับ input แบบปิด { locale, transition, due_at, timezone, version_id } (due_at เป็นนาทีเต็มแบบ UTC, timezone เป็นชื่อ IANA, version_id คือเวอร์ชันฉบับร่างที่บันทึกไว้ให้ตรึง) อ่านรายการที่ผูกไว้ผ่าน delegation_id ของข้อมูลผูก แล้วสร้างกำหนดการเผยแพร่แบบตรึงเวอร์ชันเหมือนฟอร์ม โดยตรึงที่ version_id พอดี โดยเก็บ delegation นั้นและอีเมลของผู้เรียก คำขอเดิมซ้ำจะตอบกำหนดการที่สร้างไว้แล้ว การปฏิเสธตอบ status: "refused" ตามชื่อ: invalid_input, invalid_instant, unknown_timezone, past_time, entry_unreadable, requester_unauthorized, locale_unavailable, transition_not_allowed, nothing_to_pin, version_moved, draft_changed (ฉบับร่างปัจจุบันของรายการไม่ใช่ version_id), already_scheduled, execution_in_progress ไม่แทนที่กำหนดการอื่นที่ยังทำงานอยู่ |
POST /dee-wan/operations/releases |
core ของ Dee Wan | การดำเนินการระดับไซต์ releases แลกรหัสและอ่านขอบเขตของ delegation_id ของข้อมูลผูก release_id ว่าง: ทุก release เป็นแถวและ releases.json เมื่อมี release_id: รายการของ release นั้นที่ผู้เรียกอ่านได้ พร้อมความพร้อมหรือผลลัพธ์ เป็นแถวและ release.json (บันทึกผลรีลีส) อ่านอย่างเดียว |
POST /dee-wan/operations/release-edit |
core ของ Dee Wan | การดำเนินการระดับไซต์ release-edit: action เป็น create (name), rename (release_id, name), add / add_future (release_id, instance_id, kind, locale และ transition ที่ไม่บังคับ) หรือ remove (release_id, instance_id, kind, locale) ตอบ release แบบเดียวกับ releases การปฏิเสธตอบ status: "refused" ตามชื่อ ตามที่อธิบายในส่วน Release ด้านล่าง |
POST /dee-wan/operations/release-run |
core ของ Dee Wan | การดำเนินการระดับไซต์ release-run เป็นแบบทำลาย: action เป็น schedule (release_id, due_at เป็นนาทีเต็มแบบ UTC, timezone เป็นชื่อ IANA), cancel, run_now หรือ retry delegation ของผู้เรียกจะกลายเป็น delegation ที่ release ใช้ทำงาน run_now และ retry เริ่มรายการแรก ๆ ทันทีและตอบ release |
POST /dee-wan/operations/timeline-preview |
ระบบอัตโนมัติของ core Dee Wan | อ่านแผนรีลีสสะสมสำหรับ release_id ภายใต้ delegation ปัจจุบัน ต้องตั้งเวลา มิฉะนั้นเป็น release_time_required การเปลี่ยนที่ทับกันในเวลาเดียวกันเป็น release_time_ambiguous เรียกตรงผ่าน management API, CLI หรือ MCP ไม่ได้ |
GET /installations/:id?dee_wan_launch=dwl_... |
เบราว์เซอร์ จาก Dee Wan | แลกรหัส ตั้ง session และ redirect ด้วย 303 ไปยังหน้าเดิมโดยไม่มีรหัส การ launch แบบ manage ที่มี dee_wan_view=calendar หรือ dee_wan_view=releases จะ redirect ไปที่ view นั้นแทน |
GET /installations/:id |
Session | การ launch จากเนื้อหาแสดงเนื้อหา ฟอร์มตั้งเวลา และรายการตั้งเวลาของเนื้อหานั้น การ launch แบบ manage แสดง agenda |
GET /installations/:id?month=&zone=&model=&lang=&state= |
Session แบบ manage | agenda: หนึ่งเดือนในรูปแบบรายการ จัดกลุ่มตามวัน |
GET /installations/:id/calendar?month=&zone=&model=&lang=&state= |
Session แบบ manage | ปฏิทิน: หนึ่งเดือนในรูปแบบตาราง พร้อมจำนวนต่อวัน |
GET /installations/:id/calendar/:day?zone=&model=&lang=&state= |
Session แบบ manage | หนึ่งวัน (YYYY-MM-DD): รายการตั้งเวลาของวันนั้นเรียงตามเวลาที่ถึงกำหนด แล้วตาม id |
GET /installations/:id/schedules/:scheduleId |
Session | รายการตั้งเวลาหนึ่งรายการ พร้อมตัวอย่างเนื้อหาที่อ่านผ่าน delegation ของ session |
POST /installations/:id/schedules |
Session และ CSRF token | สร้างรายการตั้งเวลา |
POST /installations/:id/schedules/:scheduleId/reschedule |
Session และ CSRF token | เลื่อนรายการตั้งเวลาที่อยู่ในสถานะ pending หรือ retrying ไปยังเวลาใหม่ |
POST /installations/:id/schedules/:scheduleId/cancel |
Session และ CSRF token | ยกเลิกรายการตั้งเวลาที่อยู่ในสถานะ pending หรือ retrying |
GET /installations/:id/releases |
Session แบบ manage | ทุก release เรียงใหม่สุดก่อน และฟอร์มสร้าง release |
POST /installations/:id/releases |
Session แบบ manage และ CSRF token | สร้าง release (name ยาว 1 ถึง 80 ตัวอักษร) |
GET /installations/:id/releases/:releaseId |
Session แบบ manage | release หนึ่งรายการ: เวลาที่ทำงาน ความคืบหน้า รายการพร้อมความพร้อม หรือบันทึกผลรีลีส |
POST /installations/:id/releases/:releaseId/rename |
Session แบบ manage และ CSRF token | เปลี่ยนชื่อ release |
POST /installations/:id/releases/:releaseId/schedule |
Session แบบ manage และ CSRF token | ตั้งหรือเลื่อนเวลา (local, timezone, fold) ของ release ที่เป็น draft หรือ scheduled |
POST /installations/:id/releases/:releaseId/run |
Session แบบ manage และ CSRF token | รัน release ที่เป็น draft หรือ scheduled ทันที |
POST /installations/:id/releases/:releaseId/cancel |
Session แบบ manage และ CSRF token | ยกเลิกการตั้งเวลาของ release ที่ตั้งเวลาไว้ หรือหยุด release ที่กำลังทำงาน |
POST /installations/:id/releases/:releaseId/retry |
Session แบบ manage และ CSRF token | รันรายการที่ล้มเหลวและถูกยกเลิกของ release ที่จบแล้วอีกครั้ง |
POST /installations/:id/releases/:releaseId/items/:itemId/remove |
Session และ CSRF token | ลบรายการขณะที่ release ยังไม่เริ่ม session จากเนื้อหาลบได้เฉพาะรายการของ entry ของตนเอง |
POST /installations/:id/release-items |
Session จากเนื้อหาและ CSRF token | เพิ่ม entry ของ session ลงใน release (release) หรือ release ใหม่ (new_release) พร้อม transition แบบ kind:to และ locale ที่ไม่บังคับ version_mode: ordinary (ค่าเริ่มต้น) / future (เผยแพร่เท่านั้น) |
POST /admin/installations/:id/delete-data |
ผู้ดูแลระบบ พร้อม Bearer ADMIN_SECRET |
ลบข้อมูลปลั๊กอินทั้งหมดของ installation นั้น รวมถึง release และตอบ {"deleted": true} ตอบ 404 not_found หากปลั๊กอินไม่มี installation นั้น ตอบ 409 execution_in_progress ขณะที่รายการตั้งเวลาหรือรายการของ release หนึ่งของมันกำลังทำงาน |
scheduled() รัน runner ของรายการตั้งเวลาหนึ่ง tick แล้วรัน release หนึ่ง tick
การพัฒนา
หัวข้อที่มีชื่อว่า “การพัฒนา”ใช้ Node 24 และเวอร์ชัน npm ที่รีโพซิทอรี Dee Wan กำหนด เริ่มจากรากของรีโพซิทอรี:
ตัวติดตั้งที่อนุมัติของรีโพซิทอรีหลักติดตั้งเครื่องมือที่ใช้ร่วมกัน ให้ build packages/plugin-conformance ก่อนรันปลั๊กอิน เพราะ dependency ในเครื่อง file:../../packages/plugin-conformance ใช้แพ็กเกจที่ build แล้ว ตัวติดตั้งหลักไม่ได้ติดตั้งปลั๊กอินในไดเรกทอรีย่อยนี้แยกต่างหาก หากยังไม่มีลิงก์ไปยังแพ็กเกจทดสอบในเครื่อง ให้สร้างด้วยคำสั่งด้านล่างจากรากของรีโพซิทอรี หากมีลิงก์ที่ถูกต้องอยู่แล้ว ให้ใช้ลิงก์เดิม อย่าเขียนทับไฟล์หรือไดเรกทอรีอื่น หากใช้รีโพซิทอรีปลั๊กอินแยกต่างหาก ให้เปลี่ยน dependency นี้เป็นเวอร์ชันที่เผยแพร่ใน npm แล้วจึงใช้ npm install แต่ขณะนี้ยังไม่มีเวอร์ชันที่เผยแพร่
ลิงก์นี้ชี้ dependency แบบ file: ที่ประกาศไว้ไปยัง packages/plugin-conformance ใน checkout นี้:
mkdir -p plugins/scheduling/node_modules/@dee-wanln -s ../../../../packages/plugin-conformance plugins/scheduling/node_modules/@dee-wan/plugin-conformancenode scripts/install-dependencies.mjs # from the Dee Wan checkout rootnpm --prefix packages/plugin-conformance run buildcd plugins/schedulingnpm run typechecknpm testnpm run dev # wrangler dev on port 8788, with --test-scheduledการติดตั้ง
หัวข้อที่มีชื่อว่า “การติดตั้ง”- Deploy Worker (ดูด้านล่าง) และตั้งค่า
PUBLIC_ORIGIN - สร้างรหัส activation:
หน้าต่างเทอร์มินัล curl -X POST -H "Authorization: Bearer $ADMIN_SECRET" https://scheduling.example/admin/activation-codes - ใน Dee Wan ไปที่ การตั้งค่า → ปลั๊กอิน แล้วติดตั้งจาก
https://scheduling.example/dee-wan/manifest.jsonด้วยรหัสนั้น มอบ capability และโมเดลให้workflow:localeจำเป็นเฉพาะเมื่อต้องการตั้งเวลาทีละภาษา หากไม่มี ทุกรายการตั้งเวลาจะย้ายทั้ง translation group - หากต้องการ rotate token ให้สร้างรหัสด้วย
{"installation_id":"<id>"}แล้วส่งให้ action rotate ใน Dee Wan
การ์ดใน Dee Wan
หัวข้อที่มีชื่อว่า “การ์ดใน Dee Wan”manifest ประกาศ ui_extensions สี่รายการ ทั้งหมดเป็นข้อมูล Dee Wan วาดการ์ดแต่ละใบเอง และเปิด Scheduling ผ่าน delegated launch ตามปกติ
schedule-card(entry_sidebar) และpage-schedule(page_sidebar): การ์ด Schedule ข้างรายการหรือหน้าที่โมเดลอยู่ใน grant การ์ดนี้เปิด content actionschedulecalendar-row(settings_row): การ์ด Calendar ในแถว Scheduling ที่ การตั้งค่า → ปลั๊กอิน การ์ดนี้เปิด manage viewcalendarจึงแทนที่ปุ่ม ปฏิทิน ธรรมดาในตำแหน่งนั้นreleases-row(settings_row): การ์ด Releases ในแถวเดียวกัน การ์ดนี้เปิด manage viewreleases
Scheduling ไม่ได้ประกาศ field editor
การดำเนินการครอบคลุมสถานะกำหนดการ ป้ายในรายการเนื้อหา รีลีส และระบบอัตโนมัติของ core โดยไม่ได้ประกาศนโยบาย
schedule-column(scope: "page",audience: "column",cell: "badge",requires: ["content:read"], ผลลัพธ์cells) Dee Wan เพิ่มคอลัมน์ Scheduled ในรายการเนื้อหาของทุกโมเดลที่ได้รับสิทธิ์ core ระบุแถวของหน้านั้นที่ผู้ใช้อ่านได้ ไม่ใช่ค่าของแถว และการดำเนินการนี้ตอบป้ายสีให้แต่ละรายการที่มีกำหนดการที่ยังใช้งานอยู่ มันไม่สร้างการมอบสิทธิ์ และไม่ถูกแสดงรายการเป็นการดำเนินการทั่วไปschedule-status(audience: "interactive",requires: ["content:read"], ผลลัพธ์rows,list_action: true) Dee Wan แสดงไว้ข้างรายการของโมเดลที่ได้รับ สิทธิ์ ผู้ใช้เรียกใช้ที่นั่นแล้วเห็นกำหนดการที่รออยู่ของรายการ ในรายการเนื้อหามันยังเป็นรายการ การทำงานของปลั๊กอิน สำหรับแถวที่ผู้ใช้เลือก และรันหนึ่งครั้งต่อแถว เอเจนต์เรียกใช้ผ่าน API การจัดการหรือ MCPschedule-draft(audience: "automation",requires: ["content:read", "workflow:read", "workflow:publish", "workflow:locale"], ผลลัพธ์rowsและjson, เป็นแบบทำลาย) มีเพียงตัววางแผนเนื้อหาของ Dee Wan ที่เรียกใช้ ในนามเจ้าของแผนเพื่อตั้งเวลา draft เวอร์ชันที่บันทึกไว้พอดี (version_id) ถ้าฉบับร่างปัจจุบันของรายการเป็นเวอร์ชันอื่น มันจะปฏิเสธด้วยdraft_changedและไม่ตั้งเวลาใด ๆ มันไม่เคยเป็นการดำเนินการของผู้แก้ไข, API การจัดการ, CLI หรือ MCP และเส้นทางเรียกใช้เหล่านั้นปฏิเสธมัน บล็อกschedule.jsonในผลลัพธ์คือข้อมูลอ้างอิงที่ Dee Wan เก็บ:{ schedule_id, status, locale, transition, due_at, timezone, local_datetime, pinned_version_id }กำหนดการเก็บdelegation_idของการดำเนินการ Dee Wan จึงอ่านสิทธิ์ปัจจุบันของเจ้าของอีกครั้งตอนทำงาน เหมือนกำหนดการที่สร้างจากฟอร์มtimeline-preview(scope: "site",audience: "automation",requires: ["content:read", "workflow:read", "workflow:release"], ผลjson): ตัวอย่างสะสมถึงrelease_idสำหรับ core เท่านั้น ภายใต้ delegation ปัจจุบัน ไม่เขียนข้อมูลreleases,release-editและrelease-run(scope: "site",audience: "interactive", ผลลัพธ์rowsและjson;release-runเป็นแบบทำลายและต้องมีworkflow:publishและworkflow:releaseด้วย) ทั้งหมดคือหน้า Releases ในรูปการดำเนินการ แอดมิน, API การจัดการ, CLI และ MCP ทั้งในเครื่องและระยะไกลจึงใช้กฎเดียวกัน Dee Wan เสนอการดำเนินการระดับไซต์ให้ผู้ที่มีsite:pluginsและผูก manage delegation ของผู้เรียกบนโมเดลที่ได้รับสิทธิ์ซึ่งผู้เรียกอ่านได้ Scheduling อ่านขอบเขตของ delegation นั้นทุกครั้งที่เรียก การดำเนินการหนึ่งอย่างต่อการเปลี่ยนแปลงหนึ่งประเภท พร้อม inputactionทำให้ manifest อยู่ในขีดจำกัดจำนวนการดำเนินการ
Wrangler
หัวข้อที่มีชื่อว่า “Wrangler”คัดลอก wrangler.example.jsonc ไปเป็น wrangler.jsonc สำหรับการ deploy ให้แทนที่ database_id ที่เป็น placeholder ด้วย id ที่ wrangler d1 create พิมพ์ออกมา การพัฒนาในเครื่องใช้ placeholder เดิมได้
- Binding:
PLUGIN_DB(D1) - Cron:
* * * * * - ตัวแปร:
PUBLIC_ORIGIN,ENVIRONMENT,DEE_WAN_DEV_ORIGINS,MAX_ATTEMPTS(5),MAX_LATENESS_MS(900000),LEASE_MS(60000),MAX_RETRY_AFTER_MS(300000) - Secret:
ADMIN_SECRET(อย่างน้อย 16 ตัวอักษร),TOKEN_KEY(base64 ของ 32 ไบต์แบบสุ่ม,openssl rand -base64 32)
npx wrangler d1 create dee-wan-schedulingnpx wrangler d1 migrations apply dee-wan-scheduling --remote # --local for devnpx wrangler secret put ADMIN_SECRETnpx wrangler secret put TOKEN_KEYnpm run deployให้ apply ไฟล์ใหม่ใน migrations/ ด้วยคำสั่ง migrations apply เดียวกันก่อน deploy release ที่ต้องใช้ไฟล์เหล่านั้น
การทำ TOKEN_KEY หายจะทำให้ token ของ installation ที่เก็บไว้อ่านไม่ได้ รายการตั้งเวลาจะถูกปฏิเสธด้วย token_unreadable และต้อง rotate ทุก installation
การพัฒนาในเครื่องกับ Dee Wan ในเครื่อง
หัวข้อที่มีชื่อว่า “การพัฒนาในเครื่องกับ Dee Wan ในเครื่อง”การตั้งค่า ทั้งสอง service, ค่าตั้งของแต่ละตัว และคำสั่ง อยู่ใน การทดสอบปลั๊กอิน ไม่ต้องใช้บัญชี Cloudflare
cookie ของ UI สำหรับจัดการใช้ prefix __Host- และ attribute Secure ดังนั้นเบราว์เซอร์ต้องใช้ HTTPS หรือ localhost base URL ของ Dee Wan ที่เป็น HTTP จะถูกยอมรับก็ต่อเมื่อ ENVIRONMENT=development และ origin ของมันอยู่ใน DEE_WAN_DEV_ORIGINS แบบตรงตัวเท่านั้น มิฉะนั้น base URL ต้องใช้ HTTPS และต้องไม่มี credential, ไม่มี query และไม่มี fragment
ความหมายของการตั้งเวลา
หัวข้อที่มีชื่อว่า “ความหมายของการตั้งเวลา”- รายการตั้งเวลาสร้างได้จากการ launch เนื้อหาเท่านั้น (action
Schedule) ปลั๊กอินอ่านเนื้อหาด้วย delegation และ(kind, to)ที่เลือกต้องอยู่ในworkflow.transitionsที่ได้รับ delegate - ภาษา: เมื่อ installation มี
workflow:localeและเนื้อหามีมากกว่าหนึ่งภาษา ฟอร์มจะให้เลือกAll languagesหรือภาษาเดียว เนื้อหาที่มีภาษาเดียวจะไม่มีตัวเลือกนี้ การเลือกAll languagesจะย้ายทั้ง translation group ภาษาเดียวย้ายเฉพาะภาษานั้น:(kind, to)ที่เลือกต้องอยู่ใน transition ของภาษานั้นในworkflow.localesและคำสั่งจะส่งlocaleภาษาที่ Dee Wan ไม่ได้แสดงไว้จะถูกปฏิเสธด้วยlocale_unavailable - การ pin: การเผยแพร่ pin
current_version_idการยกเลิกการเผยแพร่ pinpublished_version_idและทั้งสองแบบยัง pinworkflow.revisionด้วย การยกเลิกการเผยแพร่ภาษาเดียว pinpublished_version_idของภาษานั้นเอง การเผยแพร่ภาษาเดียว pincurrent_version_idของกลุ่ม เพราะ version เดียวมีทุกภาษา revision เป็นของกลุ่มเสมอ รายการตั้งเวลาถูกเก็บโดยผูกกับ instance หลัก โดยตั้งlocaleสำหรับภาษาเดียว และเว้นว่างสำหรับทั้งกลุ่ม - มีรายการตั้งเวลาที่ยังไม่สิ้นสุด (
pending|retrying|running) ได้ไม่เกินหนึ่งรายการต่อ installation, รายการเนื้อหา, kind และภาษา รายการของทั้งกลุ่มกับรายการของภาษาเดียวสำหรับรายการเนื้อหาและ kind เดียวกันก็ขัดกันด้วย เพราะกลุ่มรวมภาษานั้นอยู่ รายการตั้งเวลาใหม่จะแทนที่ (supersede) ทุกรายการ live ที่ขัดกันซึ่งอยู่ในสถานะ pending หรือ retrying ภายใน batch เดียว ดังนั้นรายการของทั้งกลุ่มจะแทนที่รายการรายภาษาของ kind นั้น และรายการของภาษาเดียวจะแทนที่รายการของทั้งกลุ่มของ kind นั้น รายการของภาษาต่างกันรออยู่ด้วยกันได้ หากรายการที่ขัดกันกำลัง running การสร้างจะล้มเหลวด้วยexecution_in_progress - การตั้งเวลาใหม่ (reschedule) จะสร้างแถวใหม่พร้อม revision ใหม่และ idempotency key ใหม่ revision นับต่อ installation, รายการเนื้อหา และ kind รวมทุกภาษา
- idempotency key คือ
sched:<installation_id>:<schedule_id>:r<revision>ค่านี้คงเดิมในทุกการ retry - ยกเลิกได้เฉพาะรายการตั้งเวลาที่อยู่ในสถานะ pending หรือ retrying การยกเลิกรายการที่กำลัง running จะคืน
execution_in_progressรายการที่เสร็จแล้วยกเลิกไม่ได้ การยกเลิกไม่เคยเรียก Dee Wan และไม่เคยย้อนกลับ transition - ในเวลาที่ดำเนินการ core จะตรวจอำนาจของบุคคลนั้น, การ pin และ revision อีกครั้ง
- การ launch แบบ manage เปิด agenda หรือเปิดปฏิทินเมื่อ Dee Wan ขอ: รายการตั้งเวลาของโมเดลที่ delegation เข้าถึงได้ ซึ่งดูตัวอย่างได้ และเลื่อนเวลาหรือยกเลิกได้เฉพาะรายการที่บุคคลนั้นเปลี่ยนได้ แต่สร้างรายการตั้งเวลาไม่ได้
สถานะ: pending, retrying, running, completed, refused, cancelled, superseded
Release
หัวข้อที่มีชื่อว่า “Release”เปิด Publication dependencies จากหน้าเนื้อหาหรือหน้า Releases ของ Scheduling แล้ว Review publication set จะเริ่มจากเวอร์ชันที่บันทึกไว้ที่เลือก และติดตามความสัมพันธ์ทั่วไป ความสัมพันธ์เฉพาะภาษา ความสัมพันธ์ในคอมโพเนนต์ และลิงก์ shared section ของภาษานั้น แต่ละขั้นอ่านได้ไม่เกิน 8 รายการ จำกัดการตรวจไว้ที่ 500 รายการที่เข้าถึงและ 100 รายการที่มองเห็น ลิงก์ที่อ่านไม่ได้หรือถูกจำกัดจะไม่แสดง ID หรือชื่อ และทำให้การตรวจไม่สมบูรณ์ เลือกเพิ่มรายการที่ทราบและเผยแพร่ได้สูงสุด 25 รายการจากการตรวจที่สมบูรณ์หรือไม่สมบูรณ์ได้ หน้ายืนยันจะแสดงรายการที่เลือกทั้งหมด และระบบตรวจสอบแต่ละเวอร์ชันอีกครั้งก่อนเพิ่ม เวอร์ชันเก่าที่เผยแพร่ไม่ได้แล้วจะไม่ถูกแทนด้วยเวอร์ชันใหม่ หากตรวจสอบความพร้อมไม่ได้ชั่วคราว ให้กด Save and continue review เพื่อตรวจรายการที่เหลือต่อ หรือเปิดหน้าตรวจทานอีกครั้งเพื่อลองตรวจใหม่ก่อนยืนยัน
รีลีสเผยแพร่หรือเลิกเผยแพร่ได้ไม่เกิน 25 รายการด้วยคำสั่ง CMS เดียว รายการมาจากหลายโมเดลและหลายภาษาในเว็บไซต์เดียวกันได้ แต่ละรายการระบุเนื้อหา ภาษาเดียวหรือทั้งกลุ่มคำแปล ชนิด (publish หรือ unpublish) และสถานะปลายทาง
- เปิดการ์ด Releases ใน การตั้งค่า → ปลั๊กอิน หรือ ชุดเผยแพร่ บนแดชบอร์ด เป็นการ launch แบบ manage ด้วย
view: releasesซึ่งต้องอ่านโมเดลที่ได้รับสิทธิ์ได้ ไม่ต้องมีsite:pluginsส่วน operation ระดับเว็บไซต์ยังต้องมีsite:pluginsเพิ่มเนื้อหาด้วย Add to release บนการ์ด Schedule - การเปลี่ยนสถานะต้องยังใช้ได้สำหรับบุคคลนั้นผ่าน delegation เลือกหลายภาษาที่ต่างกันของกลุ่มคำแปลเดียวกันได้ แต่ภาษาเดียวกันซ้ำ หรือทั้งกลุ่มทับกับภาษาใดภาษาหนึ่ง จะถูกปฏิเสธด้วย
already_in_releaseจำกัด 25 รายการ (release_full) - แต่ละรายการแสดงชื่อ ภาษา โมเดล การเปลี่ยนแปลง และความพร้อมปัจจุบัน รายการที่อ่านไม่ได้แสดงเพียงจำนวน โดยไม่เปิดเผยชื่อหรือเหตุผล ปุ่ม Run now และ Retry unfinished items ปิดเมื่อมีรายการติดขัด หากตรวจไม่ได้ ผลคือไม่ทราบ ไม่ใช่ถูกบล็อก และยังไม่เริ่มทำงาน
- สถานะคือ
draft,scheduled,running,done,failed,unknownและcancelledโดยFailedหมายถึง CMS ปฏิเสธคำสั่งและไม่มีการเปลี่ยนการเผยแพร่ใดสำเร็จ ส่วนOutcome unknownหมายถึงคำตอบยังยืนยันไม่ได้ว่าคำสั่งสำเร็จหรือไม่ ตัวรันเก็บผลที่ได้รับและไม่เดาว่ารายการใดสำเร็จ - เพิ่มหรือลบรายการได้เฉพาะ
draftและscheduledวัน เวลา และเขตเวลาใช้กฎเดียวกับรายการตั้งเวลา รีลีสทำงานแทนผู้ที่ตั้งเวลา เริ่ม หรือสั่งลองใหม่ ระบบหลักตรวจสิทธิ์ปัจจุบันอีกครั้งก่อน commit - รายการแบบปกติยังไม่ตรึงเวอร์ชันตอนเพิ่ม ก่อนส่ง ตัวรันเก็บฉบับร่างปกติล่าสุดสำหรับเผยแพร่ (
expected_current_version_id) เวอร์ชันที่เผยแพร่อยู่สำหรับเลิกเผยแพร่ (expected_published_version_id) และรีวิชัน workflow ส่วนเวอร์ชันอนาคตแบบอิสระใช้สาขาของตัวเองตามที่อธิบายด้านล่าง ทั้งชุดส่งไปยัง/releases/commitโดยต้องได้รับworkflow:releaseและสิทธิ์ของแต่ละการเปลี่ยนแปลง - ระบบหลักตรวจสถานะสุดท้ายทั้งชุด รวมถึงความสัมพันธ์ภายในรีลีส ส่วนที่ใช้ร่วมกันและหน้าที่ใช้งานส่วนนั้นเผยแพร่พร้อมกันได้โดยไม่ขึ้นกับลำดับรายการ หลายภาษาของกลุ่มคำแปลเดียวกันเปลี่ยนพร้อมกัน หากสิทธิ์ เวอร์ชัน workflow ภาษา ความสัมพันธ์ หรือจำนวนคำสั่ง SQL ไม่ผ่าน จะไม่มีการเปลี่ยนแปลง ระบบไม่แบ่งคำสั่งที่ใหญ่เกินขีดจำกัดเป็นหลาย commit
- Run now ตรวจทั้งรีลีสแล้วส่งคำสั่งเดียว tick ตรวจรีลีสที่ถึงกำหนดครั้งละหนึ่งชุด หากติดขัดจะยังเป็น
scheduledเก็บblocked_atและบันทึก Blocked attempts โดยไม่เริ่มใหม่เอง ให้แก้หรือนำรายการออกแล้วกด Run now หรือตั้งเวลาใหม่เพื่อล้างเครื่องหมาย - หากชุดรายการเปลี่ยนระหว่างตรวจ การเริ่มหรือลองใหม่จะถูกปฏิเสธด้วย
release_changedและไม่ส่งคำสั่ง ส่วนการตั้งเวลาจะตรวจชุดใหม่ใน tick ถัดไป - การยกเลิกเวลาทำให้กลับเป็น
draftการหยุดป้องกันงานที่ยังไม่ส่ง แต่ย้อนคำสั่งแบบอะตอมมิกที่ส่งไปแล้วไม่ได้ ต้องกู้ผลของคำสั่งนั้นให้ได้ - คีย์ idempotency ของทั้งคำสั่งคือ
rel:<release_id>:a<attempt>เมื่อคำตอบสูญหาย เป็นข้อผิดพลาดชั่วคราว หรือเชื่อถือไม่ได้ ตัวรันคงค่าที่ตรึงทั้งหมดและส่งคำสั่งเดิมด้วยคีย์เดิม เมื่อครบจำนวนลองใหม่อัตโนมัติและยังไม่ทราบผล จะแสดงOutcome unknownการลองใหม่ต้องกู้ผลคำสั่งเดิมก่อน เมื่อได้รับการปฏิเสธแน่ชัดจึงเริ่มความพยายามใหม่ด้วยเวอร์ชันล่าสุดหลังตรวจความพร้อม ไม่ส่งการเผยแพร่ที่สำเร็จแล้วเป็นคำสั่งใหม่ - บันทึกผลเก็บผลรีลีส เวอร์ชันที่เผยแพร่ของแต่ละรายการ รหัสล่าสุด และเวลาจบ operation
releasesให้ดาวน์โหลดเป็นrelease.jsonการส่งแจ้งเตือนและการทำ redirect อัตโนมัติเกิดหลัง commit และไม่ย้อน commit นั้น
เวอร์ชันอนาคตแบบอิสระ
หัวข้อที่มีชื่อว่า “เวอร์ชันอนาคตแบบอิสระ”ใน Add to release ตัวเลือก Version → Latest ordinary draft คงพฤติกรรมปกติ สำหรับการเผยแพร่ เลือก Version → Independent future version เพื่อสร้างเวอร์ชันแยกสำหรับรีลีสนี้ ใช้เวอร์ชันอนาคตกับการเลิกเผยแพร่ไม่ได้ (future_requires_publish) operation release-edit ใช้ action: add_future พร้อม kind: publish ส่วน action: add ใช้ฉบับร่างปกติ หน้าของปลั๊กอินยังใช้ป้ายภาษาอังกฤษ
ใน Dee Wan เปิด เวอร์ชันในอนาคต ของรายการ แล้วเลือกเวอร์ชันของรีลีสนั้น แก้ฟิลด์ หรือส่วนและข้อมูลของหน้าที่ประกอบจากส่วนต่าง ๆ แล้วกด บันทึก ประวัติเวอร์ชันในอนาคต แสดงเวอร์ชันที่บันทึกไว้ของสาขานี้ ซึ่งแก้ย้อนหลังไม่ได้ รีลีสอื่นมีสาขาของรายการเดียวกันได้ การแก้ไขหรือเผยแพร่สาขาไม่เปลี่ยนฉบับร่างปกติ เมื่อเริ่มทำงาน core จะตรึงรีวิชันและเวอร์ชันที่เลือก หลังจากนั้นแก้สาขานี้ไม่ได้ การลองใหม่กู้คำสั่งและเวอร์ชันที่บันทึกไว้ ไม่เปลี่ยนไปใช้ฉบับร่างปกติที่ใหม่กว่า
ตั้งวัน เวลา และเขตเวลาของรีลีสก่อน ดูตัวอย่างถึงรุ่นเผยแพร่นี้ มิฉะนั้นระบบปฏิเสธด้วย release_time_required ตัวอย่างเริ่มจากเนื้อหาที่เผยแพร่แล้ว ใช้การเผยแพร่และเลิกเผยแพร่จากรีลีสก่อนหน้า แล้วจึงใช้รีลีสที่เลือก โดยยังตรวจสิทธิ์อ่านปัจจุบันและไม่เปลี่ยนการเผยแพร่หรือแคชสาธารณะ รีลีสที่เวลาเท่ากันเรียงตามรหัสรีลีสที่คงที่ แต่การเปลี่ยนรายการและภาษาเดียวกันในเวลาเดียวกันถูกปฏิเสธด้วย release_time_ambiguous ให้ตั้งเวลาต่างกัน สำหรับหน้าที่ประกอบจากส่วนต่าง ๆ ให้ใช้ตัวอย่างในตัวแก้ไขเวอร์ชันอนาคตของหน้า
core อ่านแผนนี้ผ่าน operation อัตโนมัติ timeline-preview พร้อม release_id ซึ่งอ่านอย่างเดียว ไม่ใช่ operation ที่เรียกตรงผ่าน management API, CLI หรือ MCP ก่อนเผยแพร่ยังตรวจสิทธิ์ที่มอบหมายปัจจุบัน ฟิลด์และงานที่จำเป็น workflow ความสัมพันธ์ และสื่อที่ตรึงไว้ในเวอร์ชันอนาคตนั้น ระบบปฏิเสธการแก้สาขาที่ตรึงไว้หรือการดูตัวอย่างเป้าหมายที่ใช้ไม่ได้ โดยไม่ใช้ฉบับร่างปกติแทน
ปฏิทินและ agenda
หัวข้อที่มีชื่อว่า “ปฏิทินและ agenda”ปฏิทินการเผยแพร่ของทั้งไซต์ อ่านเฉพาะรายการตั้งเวลาที่ปลั๊กอินนี้เก็บไว้ Dee Wan ไม่เก็บสำเนาและไม่รัน scheduler
- ใคร: ทุกคนที่อ่านโมเดลที่ให้ Scheduling ไว้ได้อย่างน้อยหนึ่งโมเดล รวมถึงอ่านได้เฉพาะรายการของตัวเอง ปฏิทิน บน แดชบอร์ด ในรายการ เนื้อหา หรือการ์ด Calendar ในแถวของ Scheduling ในส่วน การตั้งค่า → ปลั๊กอิน คือการ launch แบบ manage ที่มี
view: calendarไม่ต้องมีsite:pluginsจัดการ ใน การตั้งค่า → ปลั๊กอิน คือการ launch แบบ manage ธรรมดา ยังต้องมีsite:pluginsและเปิดที่ agenda manifest ประกาศmanage_views: ["calendar", "releases"]และ Dee Wan เพิ่มdee_wan_view=calendarใน URL ของ launch คำใบ้นี้ไม่ได้ให้สิทธิ์ใดๆ ปลั๊กอินอ่านค่านี้หลังแลกรหัส manage สำเร็จแล้วเท่านั้น การ launch จากเนื้อหาไม่มีปฏิทินหรือ agenda และตอบ 403 ที่นั่น - ขอบเขต: ก่อนทุกหน้าและทุกการเปลี่ยนแปลง ปลั๊กอินถาม Dee Wan
GET /api/plugin/v1/delegations/<id>ทุกมุมมอง ตัวนับ ตัวกรอง ข้อความแจ้ง และหน้ารายการตั้งเวลา แสดงเฉพาะรายการตั้งเวลาของโมเดลที่อยู่ในคำตอบนั้น รายการอื่นตอบnot_foundผู้ที่เข้าถึงโมเดลใดไม่ได้เลยจะเห็นNo content you can see is scheduled here.Scheduling เก็บรายการตั้งเวลาเอง Dee Wan ไม่เก็บสำเนา - รายการของตัวเอง: โมเดลที่ระบุ
entries: "checked"คือโมเดลที่บุคคลนั้นอ่านหรือแก้ไขได้เฉพาะรายการของตัวเอง (read:own,update:own) สำหรับโมเดลนั้น ปลั๊กอินถาม Dee WanGET /api/plugin/v1/delegations/<id>/entriesครั้งละไม่เกิน 100 id ของรายการ ในทุกหน้าและทุกการเปลี่ยนแปลง ปลั๊กอินแสดง นับ และเสนอตัวกรองเฉพาะรายการที่ Dee Wan ระบุ และเสนอ Reschedule หรือ Cancel เฉพาะชนิดที่ระบุไว้กับรายการนั้น รายการตั้งเวลาอื่นตอบnot_foundผู้ที่ไม่มีรายการตั้งเวลาของตัวเองจะเห็นปฏิทินว่าง Scheduling ไม่เก็บข้อมูลเจ้าของ มุมมองไล่ตรวจทุกรายการของโมเดลแบบนี้ในช่วงของตนทีละหน้า และถามแต่ละรายการเพียงครั้งเดียว ไม่ว่ารายการนั้นจะมีการตั้งเวลากี่รายการ จำนวน รายการ และตัวกรองทั้งหมดมาจากชุดที่ตรวจแล้วชุดเดียวกันนี้ ช่วงที่มีรายการแบบนี้เกิน 4,000 รายการ (เกินกว่าที่คำขอหนึ่งครั้งบน Workers Free จะถามได้) จะถูกปฏิเสธทั้งช่วง:This range is too large to check with Dee Wan at once. Nothing is shown. Open a single day.ตัวกรองโมเดลและภาษาของโมเดลแบบนี้มาจากรายการที่ตรวจแล้วในช่วงของมุมมองนั้น - ถูกนำออก: เมื่อ Dee Wan ตอบคำขอนั้นด้วย 401
plugin_unauthorized(installation ถูก uninstall ถูกปิด หรือ token ถูกเพิกถอน) ทุกหน้าตอบ 200 และแสดงThis installation was removed from Dee Wan or turned off there. Its schedules no longer run.ไม่แสดงรายการตั้งเวลา ตัวนับ หรือการกระทำใด ๆ เมื่อไม่มีขอบเขต ปลั๊กอินไม่รู้ว่าผู้ใช้เห็นโมเดลใดได้ จึงไม่แสดงเลย Cancel หรือ Reschedule ที่ส่งมาก็ไม่เปลี่ยนอะไร - Dee Wan ใช้งานไม่ได้: ไม่มีคำตอบ ได้ 5xx หรือ 429
rate_limitedหน้าจะตอบ 403 พร้อมDee Wan is not available right now. Nothing changed. Try again in a minute.และไม่แสดงรายการตั้งเวลา - ใครเปลี่ยนอะไรได้: Reschedule และ Cancel แสดงเฉพาะเมื่อชนิดของรายการ (
publishหรือunpublish) อยู่ในรายการของโมเดลนั้น Dee Wan ใส่ชนิดนั้นเมื่อ installation มีworkflow:publishหรือworkflow:unpublishบุคคลนั้นแก้ไขรายการได้ (รายการใดก็ได้ของโมเดล หรือภายใต้update:ownเฉพาะรายการของตัวเอง) และ workflow ของโมเดลมีเส้นทางชนิดนั้นที่บุคคลนั้นมีสิทธิ์ ผู้ที่ไม่มีสิ่งเหล่านี้ดูได้อย่างเดียวและหน้าจะบอกไว้ Reschedule หรือ Cancel ที่ส่งมาอยู่ดีจะตอบnot_permittedและไม่เปลี่ยนอะไร การเลื่อนเวลายังอ่านเนื้อหาซ้ำตามด้านล่าง - มุมมอง: Calendar เป็นตารางรายเดือน เริ่มที่วันจันทร์ พร้อมจำนวนต่อวัน วันที่มีรายการตั้งเวลาลิงก์ไปยังวันนั้น Agenda เป็นเดือนเดียวกันในรูปแบบรายการ จัดกลุ่มตามวัน Day แสดงรายการตั้งเวลาของวันหนึ่งเรียงตามเวลาที่ถึงกำหนด แล้วตาม id
- ที่อยู่: เดือนและตัวกรองทั้งหมดอยู่ใน query ดังนั้นทุกมุมมองเป็นลิงก์ GET ธรรมดา และฟอร์มตัวกรองทำงานได้โดยไม่ต้องใช้ JavaScript เดือนก่อนหน้าและเดือนถัดไปคงตัวกรองไว้ ลิงก์ระหว่าง Calendar กับ Agenda และลิงก์ของแต่ละวันก็คงไว้เช่นกัน
month:YYYY-MMค่าเริ่มต้นคือเดือนปัจจุบันใน timezone ที่เลือก ค่าที่ใช้ไม่ได้จะกลับไปใช้ค่าเริ่มต้นzone: timezone แบบ IANA ที่ใช้อ่านวัน ค่าเริ่มต้นUTCแต่ละแถวอยู่ในวันท้องถิ่นของเวลาที่ถึงกำหนดใน timezone นั้น ขอบเขตของเดือนและวันคือเที่ยงคืนท้องถิ่นของ timezone นั้น รวมถึงช่วงเปลี่ยนเวลาและในที่ที่เที่ยงคืนถูกข้ามไป timezone ที่ไม่รู้จักจะถูกปฏิเสธโดยระบุชื่อ ด้วย 400 พร้อมลิงก์ไปยังมุมมองเดียวกันในUTCmodel: id ของ model รายการมีเฉพาะ model ที่ installation นี้มีรายการตั้งเวลาและ delegation เข้าถึงได้ แสดงด้วย slug ที่บันทึกไว้ตอนสร้างรายการตั้งเวลาlang: ภาษา รายการมีเฉพาะภาษาที่ installation นี้มีรายการตั้งเวลาแบบภาษาเดียวบนโมเดลที่ delegation เข้าถึงได้ รายการตั้งเวลาของทั้งกลุ่มย้ายทุกภาษา จึงตรงกับตัวกรองภาษาทุกค่าstate:current(ค่าเริ่มต้น: pending, retrying, running, completed, refused),live(pending, retrying, running),allหรือสถานะเดียว รายการที่ completed และ refused แสดงรหัสและข้อความของผลลัพธ์- ขอบเขต: แต่ละมุมมองอ่านหนึ่งเดือนหรือหนึ่งวัน ด้วยช่วงของ
due_atที่ใช้ indexschedule_agenda (installation_id, due_at, id)ปฏิทินนับจำนวนต่อวันใน query เดียวนั้น agenda และมุมมองวันแสดงสูงสุด 200 แถว จากนั้นมีข้อความให้กรองให้แคบลง มุมมองไม่เขียนข้อมูลใดๆ - ชื่อ: รายการตั้งเวลาแต่ละรายการแสดงชื่อเรื่องของรายการเนื้อหาที่บันทึกไว้ตอนสร้าง หรือ slug หากรายการนั้นไม่มีชื่อเรื่อง รายการตั้งเวลาของภาษาเดียวแสดงชื่อภาษาเป็นภาษาของ UI เมื่อ timezone ที่ใช้ดูต่างจาก timezone ของรายการตั้งเวลาเอง เวลาจะแสดงใน timezone ที่ใช้ดูด้วย
- ตัวอย่าง:
Openของรายการตั้งเวลาอ่านเนื้อหาจาก Dee Wan ด้วย delegation ของ session แสดงชื่อเรื่อง model ภาษา และสถานะปัจจุบัน และบอกว่า version ที่ pin และ revision ของ workflow ยังตรงอยู่หรือไม่ สำหรับรายการของภาษาเดียว ภาษา สถานะ และการ pin เป็นของภาษานั้นเอง หาก Dee Wan ไม่แสดงภาษานั้นแล้ว ตัวอย่างจะแสดงlocale_unavailableหาก Dee Wan ปฏิเสธการอ่าน หน้านั้นจะบอกเหตุผลBackกลับไปยังมุมมองที่เปิดมา - เลื่อนเวลา: เวลาท้องถิ่นและ timezone ใหม่สำหรับรายการตั้งเวลาที่อยู่ในสถานะ pending หรือ retrying การ pin, ชนิด, เป้าหมาย และภาษาคงเดิม ปลั๊กอินจะอ่านเนื้อหาใหม่ผ่าน delegation ของ session ก่อน: บุคคลนั้นต้องยังได้รับ transition นั้น สำหรับภาษานั้นหากรายการมีภาษา และ version ที่ pin กับ revision ต้องยังเป็นปัจจุบัน มิฉะนั้นจะปฏิเสธด้วย
locale_unavailable,transition_not_allowed,scheduled_target_staleหรือworkflow_conflictและไม่เปลี่ยนอะไร การเลื่อนเวลาจะเพิ่มแถวใหม่ที่มี revision ถัดไปและทำเครื่องหมายแถวเดิมเป็นsupersededจึงได้ idempotency key ใหม่ แถวใหม่ใช้ delegation ของบุคคลที่เลื่อนเวลา รายการที่กำลัง running ตอบexecution_in_progressและรายการที่เสร็จแล้วเลื่อนไม่ได้ - ยกเลิก: เฉพาะรายการที่อยู่ในสถานะ pending หรือ retrying ตามความหมายของการตั้งเวลา ไม่เคยเรียก Dee Wan เมื่อยกเลิกจากมุมมองใด จะกลับไปยังมุมมองนั้นพร้อมข้อความแจ้ง ที่อยู่
returnยอมรับเฉพาะมุมมองของ installation นี้ และ query ของมันจะถูกอ่านใหม่ ไม่ได้ส่งกลับตามที่รับมา
แผง Workflow ของ Dee Wan ลิงก์มาที่นี่ เมื่อการย้าย workflow ครั้งล่าสุดของรายการทำโดยปลั๊กอินนี้ แผงจะแสดง View schedule ซึ่งเปิดหน้าของปลั๊กอินนี้สำหรับรายการนั้นผ่าน content action Schedule
แต่ละรายการตั้งเวลาเก็บ due_at แบบ UTC, timezone ของ IANA, เวลาท้องถิ่นตามนาฬิกา และ fold การเปลี่ยนกฎของ timezone จะไม่เขียน due_at ใหม่ การคำนวณใช้เพียง Intl.DateTimeFormat
| อินพุต | ผลลัพธ์ |
|---|---|
2026-07-01T09:00 America/New_York |
2026-07-01 13:00 UTC |
2026-03-29T02:30 Europe/Berlin |
ปฏิเสธด้วย nonexistent_local_time (นาฬิกากระโดดจาก 02:00→03:00) |
2026-10-25T02:30 Europe/Berlin ไม่มี fold |
ปฏิเสธด้วย ambiguous_local_time |
เหมือนกัน, fold earlier |
2026-10-25 00:30 UTC (CEST) |
เหมือนกัน, fold later |
2026-10-25 01:30 UTC (CET) |
2026-07-01T09:00 Mars/Base |
ปฏิเสธด้วย unknown_timezone |
2025-12-31T23:59 UTC ที่ผ่านไปแล้ว |
ปฏิเสธด้วย past_time |
หน้ายืนยันและรายการแสดงเวลาท้องถิ่นพร้อม zone และเวลา UTC เมื่อ zone เป็น UTC เวลาจะแสดงครั้งเดียว
แต่ละรอบ cron รับรายการที่ถึงกำหนดได้สูงสุด 20 แถวโดยสลับ installation การ claim แบบ compare-and-set เปลี่ยนสถานะและ lease token ที่อ่านไว้ เพิ่ม attempt_count และกำหนด token ใหม่พร้อม lease_until = now + LEASE_MS หลังถอดรหัส token ตัวส่งจะตรวจอีกครั้งว่าตนยังถือ lease อยู่ ยังไม่เกินจำนวนครั้งและระยะเวลาสูงสุด และเหลือเวลาพอให้คำขอทำงานจนครบ timeout ผู้ครองเก่าไม่ส่งและไม่จบแถวของผู้ครองใหม่ การกู้คืนอาจส่ง key และ body เดิมซ้ำ timeout ไม่ได้ยืนยันว่าการทำงานระยะไกลหยุดแล้ว idempotency ของ core จำกัดผลที่เกิด ไม่ได้สัญญาว่าจะมี HTTP request ครั้งเดียว
| คำตอบของ Dee Wan | ผลลัพธ์ของปลั๊กอิน |
|---|---|
200 transition_applied / idempotent_replay |
completed |
400 invalid_request |
refused ไม่ retry |
401 plugin_unauthorized |
refused ไม่ retry |
403 capability_refused / requester_unauthorized |
refused ไม่ retry |
404 content_not_found |
refused ไม่ retry |
409 scheduled_target_stale / workflow_conflict / dependent_content / idempotency_key_reused |
refused ไม่ retry |
422 transition_unavailable / transition_refused |
refused ไม่ retry |
| มี outcome แต่ status/code/retry ไม่ตรงหรือฟิลด์ผิดรูปแบบ body ไม่มี outcome บน status อื่น redirect | refused, untrusted_response |
429 rate_limited |
retrying ใช้ Retry-After ที่ถูกต้องและไม่เกินเพดาน มิฉะนั้นใช้ exponential backoff พร้อม jitter |
503 temporary_failure |
retrying ใช้ Retry-After ที่ถูกต้องและไม่เกินเพดาน มิฉะนั้นใช้ exponential backoff พร้อม jitter |
| 429/500/502/503/504 ที่ไม่มี outcome เครือข่ายล้มเหลวหรือ timeout (10 s) | retrying ใช้ Retry-After ภายในเพดานเมื่อมี มิฉะนั้นใช้ exponential backoff พร้อม jitter |
เกิน MAX_ATTEMPTS, เกิน due_at + MAX_LATENESS_MS หรือ Retry-After > MAX_RETRY_AFTER_MS |
refused retry_exhausted ไม่ส่งอะไรอีก |
ตรวจ structured outcome ก่อนใช้กฎสำรองตาม status Retry-After รับวินาทีที่เป็นจำนวนเต็มไม่ติดลบหรือวันที่ HTTP รูปแบบมาตรฐาน (IMF-fixdate) วันที่ที่ผ่านมาแล้วหมายถึงศูนย์ ค่าผิดรูปแบบให้ใช้ backoff ค่าเกิน MAX_RETRY_AFTER_MS หรือเกินเพดานจำนวนครั้งหรืออายุจะได้ retry_exhausted ค่า LEASE_MS ต่ำสุดคือ 11 วินาทีซึ่งยาวกว่า timeout คำขอ 10 วินาที หากเวลา lease ไม่พอจะไม่ส่ง ถือว่าสำเร็จเฉพาะ transition_applied หรือ idempotent_replay
retry_exhausted หลัง network ล้มเหลวหมายความว่าไม่ทราบผลลัพธ์ ดังนั้นให้ตรวจเนื้อหาใน Dee Wan รายการตั้งเวลาจะไม่ถูกส่งช้ากว่าขีดจำกัดความล่าช้าเลย รวมถึงตอนรับช่วง lease ของงานที่ขัดข้องด้วย
ความพยายามแต่ละครั้งถูกบันทึกไว้ใน schedule_attempt (attempt, เวลาเริ่ม, เวลาเสร็จ, code, HTTP status) นี่คือบันทึกเชิงปฏิบัติการสำหรับผู้ใช้ ไม่ใช่ telemetry
ข้อมูล, การเก็บรักษา, การถอนการติดตั้ง
หัวข้อที่มีชื่อว่า “ข้อมูล, การเก็บรักษา, การถอนการติดตั้ง”- ข้อมูลที่เก็บ: installation (id, site id, base URL ของ Dee Wan และ token ที่เข้ารหัสด้วย AES-GCM) รหัส activation ที่ hash แล้ว, session ที่ hash แล้ว (30 นาที) พร้อม CSRF token, รายการตั้งเวลา และความพยายามแต่ละครั้ง รวมถึง release พร้อมรายการและบันทึกผลรีลีส ไม่มีการเก็บ snapshot ของเนื้อหาและไม่มีการเก็บ session ผู้ใช้ของ Dee Wan
- รหัส launch และ token ดิบไม่เคยถูก log หรือเก็บในรูปดิบ
- การถอนการติดตั้งปลั๊กอินใน Dee Wan จะเพิกถอน token ข้อมูลปลั๊กอินยังคงอยู่ รายการตั้งเวลาที่เหลือจะถูกปฏิเสธด้วย
plugin_unauthorizedเมื่อถึงกำหนด จากนั้นหน้าของปลั๊กอินจะแจ้งว่า installation ถูกนำออกแล้ว และไม่แสดงรายการตั้งเวลา - หากต้องการลบข้อมูลปลั๊กอิน ผู้ดูแลระบบเรียก
POST /admin/installations/:id/delete-dataพร้อมBearer ADMIN_SECRETการเรียกจะถูกปฏิเสธด้วย 409execution_in_progressขณะที่มีรายการตั้งเวลากำลัง running ไม่ได้สร้างกลไกล้างข้อมูลตามระยะเวลาเก็บรักษาแบบอัตโนมัติไว้
การทดสอบ
หัวข้อที่มีชื่อว่า “การทดสอบ”npm test # vitest, from this directorynpm run typechecknpm run test:cross-service # this plugin and a live Dee Wan, both under wrangler dev; two to three minutesnpm test รวม test/conformance.test.ts ซึ่งรันกรณีของ protocol v1 จาก @dee-wan/plugin-conformance กับปลั๊กอินนี้: ตาราง outcome, สถานะ, flag ของ retry, capability และรูปแบบของ secret เทียบกับ schema ที่เผยแพร่, manifest เทียบกับ manifest schema ที่เผยแพร่, การจำแนกคำตอบ, activation, การแลกรหัส launch และการส่งคำสั่งผ่าน runner จริงกับ core ปลอมของแพ็กเกจ test/helpers/d1.ts คือ D1 shim ที่ใช้ better-sqlite3 และ apply ทุกไฟล์ใน migrations/
test/docs.test.ts รันตาราง Runner และ Time ข้างต้นผ่าน classify และ resolveLocalTime ดังนั้นเมื่อข้อมูลในตารางล้าสมัย การทดสอบจะล้มเหลว
test:cross-service รัน test/cross-service/cross-service.test.mjs มันเริ่ม admin Worker ของ Dee Wan และปลั๊กอินนี้ภายใต้ wrangler dev บนเครื่อง local ติดตั้งปลั๊กอินผ่าน Dee Wan และรันการเผยแพร่และการยกเลิกการเผยแพร่ตามกำหนดเวลา รวมถึงการปฏิเสธ ผ่าน protocol v1 Dee Wan เป็น checkout ภายนอก: ตั้ง DEE_WAN_CORE_DIR เป็น repository ของ Dee Wan ที่ติดตั้ง dependency แล้ว (node scripts/install-dependencies.mjs), build แพ็กเกจแล้ว (npm run build:packages) และสร้าง Prisma client แล้ว (npm --workspace backend run prisma:generate) ภายใน repository ของ Dee Wan ไม่ต้องตั้งตัวแปรนี้ การรันข้ามเซอร์วิสแบบอัตโนมัติ แสดงรายการสิ่งที่มันยืนยัน
.github/workflows/ci.yml คือ CI ของปลั๊กอินนี้เองสำหรับ repository ของมันเอง: ติดตั้ง, typecheck, npm test แล้วรันข้ามเซอร์วิสกับ checkout ของ Dee Wan ที่ vars.DEE_WAN_CORE_REF (ค่าเริ่มต้น main) GitHub ไม่รันมันขณะที่ไดเรกทอรีนี้อยู่ใน repository ของ Dee Wan และ CI ของ Dee Wan ไม่รันปลั๊กอินนี้
การย้ายไปยัง repository ของตัวเอง
หัวข้อที่มีชื่อว่า “การย้ายไปยัง repository ของตัวเอง”การย้ายต้องได้รับอำนาจอย่างชัดเจน: การสร้าง dee-wan-cms/dee-wan-scheduling, การ push ไปยังมัน และการเผยแพร่ @dee-wan/plugin-conformance เป็นการกระทำภายนอก เมื่อได้รับอำนาจแล้ว จาก root ของ repository ของ Dee Wan:
# 1. Publish the conformance package (needs npm publish rights for the @dee-wan scope).node scripts/install-dependencies.mjsnpm --prefix packages/plugin-conformance run buildcd packages/plugin-conformancenpm testnpm publish --access publiccd ../..
# 2. Split this directory with its history into a branch.git subtree split --prefix=plugins/scheduling -b scheduling-split
# 3. Create the empty repository dee-wan-cms/dee-wan-scheduling on GitHub, then push the branch as main.git push https://github.com/dee-wan-cms/dee-wan-scheduling.git scheduling-split:main
# 4. In a clone of the new repository: depend on the published package and commit a lockfile.git clone https://github.com/dee-wan-cms/dee-wan-scheduling.gitcd dee-wan-schedulingnpm pkg set devDependencies.@dee-wan/plugin-conformance=^0.1.0npm installnpm run typechecknpm testgit add package.json package-lock.jsongit commit -m "Depend on the published @dee-wan/plugin-conformance"git pushจากนั้นใน repository นั้น: หาก dee-wan-cms/dee-wan เป็น private ให้เพิ่ม secret DEE_WAN_CORE_TOKEN ที่อ่านได้อย่างเดียว และตั้งตัวแปร DEE_WAN_CORE_REF เป็น ref ของ Dee Wan ที่จะทดสอบด้วยหากต้องการ ลิงก์ใน README นี้และใน docs/end-to-end.md ที่ชี้ไปยัง ../../docs/plugins/ ต้องเปลี่ยนเป็นลิงก์ไปยังเอกสาร Dee Wan ที่เผยแพร่แล้ว
การลบ plugins/scheduling ออกจาก repository ของ Dee Wan เป็นการเปลี่ยนแปลงแยกต่างหากที่นั่น ซึ่งจะนำ README นี้และ docs/end-to-end.md ออกจากเว็บไซต์เอกสารของ Dee Wan ด้วย (docs-site/allowlist.mjs และคำแปล ru และ th) และชี้ docs/plugins/*.md ไปยัง repository ใหม่
ยังไม่เปิดตัว (pre-MVP) และยังไม่มีเวอร์ชันเสถียร
คอมมิตซอร์สโค้ด: e207e63239a627fbd2ae9c414ef7c6eb19fcfe5a (มีการแก้ไขที่ยังไม่คอมมิต)
วันที่สร้างเอกสาร (UTC): 2026-10-21T09:28:24.214Z
คอมมิตสำหรับอัปเกรด: ระบุไม่ได้: มีการแก้ไขที่ยังไม่คอมมิต. บันทึกการเปลี่ยนแปลง