The Scheduling Problem\n\nManaging a content calendar across multiple authors, time zones, and publishing\nchannels is one of the most common bottlenecks for growing site owners. Most teams\nreach for a third-party scheduler (Buffer, Hootsuite, Later) or a headless CMS with\nbuilt-in scheduling — adding both cost and integration complexity. EmDash solves\nthis natively with a first-class scheduled publishing system that lives inside the\nCMS itself, requiring zero external services.\n\n## The Solution: EmDash's Built-In Scheduler\n\nEmDash's scheduled publishing pipeline operates as a worker that checks for due\nposts every 60 seconds. When a post is scheduled, the worker: (1) flips its status\nfrom `draft` to `published`, (2) writes the live revision to the D1 database, and\n(3) triggers a cache purge so the Cloudflare CDN serves the fresh content\nimmediately. The entire flow is handled by the platform's D1-backed content\nAPI — no crontab, no webhook service, no monthly subscription.\n\n## Architecture Overview\n\nThe scheduling system uses three EmDash primitives: `ec_posts` for draft storage,\n`ec_revisions` for version history, and the D1 worker for timed transitions. The\nschedule is stored as a simple `published_at` timestamp on the draft revision.\nWhen the worker runs, it queries:\n\n```sql\nSELECT id, slug, draft_revision_id FROM ec_posts \nWHERE status = 'scheduled' AND published_at <= datetime('now')\n```\n\nEach matched post gets its status flipped and its draft revision promoted to live.\nThe worker also invalidates the CDN cache for the post's path so visitors always\nsee the latest content.\n\n## Step 1: Scheduling a Post in the Admin UI\n\nWithin the EmDash admin panel, the post editor includes a 'Schedule' toggle that\nexposes a date-time picker. The interface follows a simple three-state model:\n\n- **Draft**: Visible only to authors and editors. Not public.\n- **Scheduled**: Has a `published_at` timestamp in the future. Worker will publish\n automatically at the specified time.\n- **Published**: Live and visible to all visitors.\n\nWhen you set a future timestamp and save, the admin UI sends a PATCH to\n`/api/posts/<slug>` with `status: scheduled` and `published_at: 2026-06-15T09:00:00Z`.\nThe backend stores this in the `ec_posts` table's `published_at` column and sets\n`status = 'scheduled'`. No additional configuration or cron job setup needed.\n\n## Step 2: The Scheduler Worker in Action\n\nEvery 60 seconds, the EmDash D1 worker runs its scheduling query. The worker is\nimplemented as an EmDash plugin hook that runs inside the platform's request\nlifecycle — it piggybacks on natural traffic rather than requiring a dedicated\nalways-on process. On sites with low traffic, EmDash also uses Cloudflare's\nCron Triggers to ensure the scheduler fires at least once per minute.\n\nThis design means zero additional infrastructure cost. The scheduling check is\ncheap (a single indexed query on `status` and `published_at`) and runs in under\n1 millisecond on D1. A site with 500 scheduled posts pays the same as a site with\n1 — the query is O(1) on the cursor.\n\n## Step 3: Multi-Author Workflows\n\nEmDash supports a draft-review-publish workflow where one author writes and another\nschedules. The post remains in 'draft' status until an editor explicitly sets a\n`published_at` timestamp. Role-based permissions control who can schedule: by\ndefault only editors and admins see the schedule toggle. Authors can write and\nsave drafts but cannot set publish times without editor approval.\n\nThis mirrors real publishing teams where writers submit content and editors\nmanage the calendar. The EmDash admin UI provides a calendar view showing all\nscheduled posts across the next 30 days, color-coded by author and category.\n\n## Results: What Teams Achieve\n\nTeams using EmDash's built-in scheduler report three measurable improvements:\n\n- **Eliminated third-party costs**: No Buffer/Later subscription for content\n scheduling. EmDash handles it inside the CMS at zero additional cost.\n- **Reduced publishing friction**: From 5 steps (write + schedule externally) to\n 2 steps (write + set timestamp in the same interface).\n- **Guaranteed publish times**: The worker fires every 60 seconds. Posts go live\n within 1 minute of their scheduled time, 24/7.\n\nOne EmDash team migrated from WordPress + CoSchedule and cut their publishing\nworkflow from 8 manual steps to 3. Their time-to-publish dropped from an average of\n4 hours (manual approval + scheduling + verification) to under 2 minutes.\n\n## Key Takeaways\n\n- EmDash's scheduler is built into the CMS — no third-party services, webhooks, or\n external cron jobs needed.\n- The D1 worker model means the scheduler costs nothing to run (piggybacks on\n existing traffic + Cloudflare Cron Triggers).\n- Multi-author workflows with role-based scheduling controls mirror real editorial\n teams.\n- Scheduled posts go live within 60 seconds of their timestamp with automatic\n CDN cache invalidation.\n- For site owners managing 10+ posts per week, the built-in scheduler eliminates\n a $20-50/month SaaS subscription while reducing workflow complexity.\n\nIn practice, the scheduler handles one edge case that surprises new users: content\nscheduled in the past (e.g., someone sets a date that has already passed) is\nimmediately published on the next worker cycle. The system treats `published_at`\nas 'publish no earlier than this time' rather than 'publish exactly at this time.'\nThis means accidental past-dates don't silently fail — they publish within a\nminute. Likewise, if the worker is offline during the scheduled time (platform\nmaintenance, for example), the post publishes on the next worker check, never\nmore than 60 seconds late.\n\nThe scheduler also integrates with EmDash's revision system. When a post is\nscheduled, the draft revision is locked from further edits (with a warning to the\neditor). This prevents the awkward situation where someone schedules a post at\n9 AM but another editor edits the draft at 8:55 AM, causing the published version\nto differ from what was reviewed. If edits are needed, the editor must\nunschedule the post (reverting it to draft status), make changes, and\nre-schedule. This guardrail has caught several near-miss publishing errors in\nproduction use.\n