# DynoStatic community reference

An Astro static build plus a Cloudflare Worker, using the same renderer for freshly published and built posts. This example is configurable source, not an activated website. Read the installed [community guide](../../docs/community-publishing.md) first.

## Configure and bootstrap

1. Copy this directory into the new website repository. Register your website origin and enable account verification mail in DynoStatic.
2. Run `npm ci`. Set `DYNOSTATIC_URL`, `DYNOSTATIC_SITE_ID`, `SITE_ORIGIN` and `COMMENTS_WIDGET_ID`. All four are public configuration. Use HTTPS for both origins.
3. Create a website Automation token with `workspace:read`, `workspace:write` and `site:publish`. Keep it in ignored `.secrets/.dynostatic-api` locally or `DYNOSTATIC_BUILD_TOKEN` in CI. Ignore `.local/` as well. Run `node setup.mjs` privately to provision Deals/Discussions and publish Comments through the installed APIs. Set `COMMENTS_WIDGET_ID` to the returned public ID. Existing drafts, paused widgets and customized schemas are preserved for review; rerun the same script to resume an interrupted operation. Alternatively create the boards and Comments in the owner interface. CI build-only credentials need only `site:publish`. Keep Cloudflare deployment credentials only in CI. Never use an administrative token for visitor requests.
4. Change the name in `wrangler.jsonc`. Keep `run_worker_first: true`. Give this Worker the website's custom domain; remove any alternate static/Pages delivery route for these pages.
5. Make the first due build claim through the Automation API. Set `COMMUNITY_BUILD_ID` to the returned ID and run `node scripts/publish.mjs` with deployment credentials. Alternatively dispatch the included GitHub workflow with that ID. The build copies installation assets and published media, builds Astro, deploys the Worker, and confirms its production manifest. It renews its lease while working.
6. Copy `.github/workflows/community-publish.yml` to the website repository's workflow directory. Configure its `production` environment variables/secrets. The example expects this directory's package at the repository root; set `defaults.run.working-directory` and the cache path when using a subdirectory.
7. Configure `wrangler.dispatcher.jsonc` with your CMS/site and GitHub repository/workflow. Add `DYNOSTATIC_BUILD_TOKEN` and `GITHUB_DISPATCH_TOKEN` as dispatcher secrets. The latter needs Actions write permission for that repository. Deploy with `wrangler deploy --config wrangler.dispatcher.jsonc`. It has no public route and runs every minute.

Browser account, submission and comment actions call the CMS physical gateways directly with registered-Origin CORS. This preserves native visitor IP/rate-limit behavior across Cloudflare zones. The public Worker handles page delivery.

The dispatcher and public site are **separate Workers**. The public site imports `generated/site.json`, containing only public projections/configuration and the unmodified contributor handoff bootstrap. The preparation script never writes build credentials there. Generated files and local environment files are ignored.

The first build may be empty. New posts are immediately available dynamically once CMS publication completes. The next scheduled claim builds them. A failed build leaves current public content available dynamically. Lists/search/rankings and interactions remain live. Current status is inserted into an exact static post at request time.

## Delivery safeguards

- All paths run through the Worker. Only known CSS/JS/font/icon paths bypass content checks. Unknown HTML never falls through to static assets.
- Dynamic and static posts share URLs, markup and the existing comments/replies/votes engine. Reports use existing form tickets and Turnstile.
- Visibility evidence expires at its original absolute deadline, at most 60 seconds after issuance. Offline origin + expired evidence returns 503. Hidden posts return 404 after existing evidence expires.
- Selected imported images become private uploads, then published CMS media. Builds verify their SHA-256 before copying; guarded community media routes check the current publication.
- Do not add cache rules overriding `private, no-store`, HTML service-worker caches, direct public bucket links or alternate static domains.
- Full builds are bounded to 10,000 posts. Extend the adapter with partitioned archives before exceeding that bound. Full posts remain live while a build is unavailable.

Cloudflare's [`run_worker_first` routing](https://developers.cloudflare.com/workers/static-assets/routing/worker-script/) ensures the Worker executes before asset delivery. Astro generates captured post routes with [`getStaticPaths`](https://docs.astro.build/en/reference/routing-reference/).
