logicspike/docs

Blog Engine

Publish-to-live — how a dashboard edit reaches a customer's website

Status: Superseded. Outbound dispatch (§5–§8 of the previous version of this doc) now lives in the shared Site Sync worker (apps/site-sync), not blog-service. This doc is a redirect + summary; see Site Sync's own docs for the full design. Updated: 2026-08-21

1. The problem (unchanged)

A customer installs @vlozi/blog into their own site and deploys it. If that build renders content ahead of time — generateStaticParams, output: "export", any static host — the content is frozen at build time. Editing a post in the dashboard changes nothing on the live site unless something tells the site to refresh or rebuild.

2. What changed

blog-service originally shipped its own private dispatcher for this (BlogRevalidator DO, lib/revalidate.ts, lib/revalidate-webhook.ts, and an /admin/integrations CRUD API + dashboard card). It was fully built and documented but never wired up for real customers — no tenant ever configured an integration through it.

It has since been deleted outright and replaced by Site Sync (apps/site-sync), a worker shared across every content-producing service (currently Blog and Collections; more can subscribe later). One dispatcher, one per-tenant debounce, one dashboard screen — instead of each service re-inventing the same webhook/deploy-hook machinery. The previous per-service design is what packages/site-sync-core and apps/site-sync now generalise.

3. How it works now

  • Trigger side (blog-service): notifySiteSync() and siteSyncMiddleware in src/lib/site-sync.ts. The middleware is mounted on /admin/* and /mcp/* in src/index.ts and fires after any successful (2xx, non-GET) write — so every admin REST call and every MCP mutation is covered without each handler having to remember to call it. The one call site that can't rely on the middleware is the scheduled-publish alarm in src/scheduler.ts: a DO alarm has no HTTP request in flight, so it calls notifySiteSync explicitly.
  • Dispatch side (site-sync): apps/site-sync owns the target registry (webhook / deploy_hook per tenant), the debounce DO (SiteRevalidator in src/revalidator.ts — a generalised port of the old BlogRevalidator), the outbound delivery + SSRF guard (now in packages/site-sync-core), and the composite content-version check that decides whether a deploy hook actually needs to fire.
  • Dashboard: configuration lives in one place — apps/seller-dashboard/src/app/dashboard/settings/website — rather than a per-module card. A workspace has one website, so the deploy hook is pasted once and a burst of edits across Blog and Collections collapses into a single rebuild.

The webhook-vs-deploy-hook split, the 60s/5min debounce, and the "deploy hooks are debounced, webhooks are inline" reasoning all carry over unchanged from the original design — only the ownership moved from blog-service to site-sync.

4. Content version (unchanged, still in blog-service)

GET /blog/public/version{ v: "<16 hex chars>" } (services/version.service.ts) is still blog-service's own primitive, and site-sync's composite version pulls it in as one of the sources a target can subscribe to. See that file's docstring for the digest design (published-only, count-aware, categories/tags digested rather than timestamped).

5. Live content (SDK 2.2.0) — unaffected

The browser-side "live content" mechanism (resolveLive() in packages/blog-sdk/src/server/live.ts) is a separate mechanism from outbound webhook/deploy-hook dispatch — it polls /blog/public/version from the client — and is untouched by this change. See the SDK package's own docs for its constraints (dynamic island entry, no VloziClient import, auth in the query string, etc.).

6. What's still open

  • Site Sync's own docs (not yet written as a standalone doc at the time of this edit) should become the canonical reference for §5–§8 of dispatch design, delivery log, and fire-site coverage — this file should stay a thin pointer rather than duplicating that content.
  • apps/blog-host remains the answer for no-code customers (Webflow, Carrd) who can't install an SDK at all.
Blog Engine