Sveltia CMS
Sveltia CMS is a fully client-side CMS that edits markdown and JSON files directly in GitHub. No server-side code, no adapter changes — the Astro site stays fully static. The admin UI lives at /admin on the production domain.
How it works
Section titled “How it works”public/admin/index.htmlloads the Sveltia CMS script from unpkgpublic/admin/config.ymltells it which files to manage and what fields each has- Editors log in via GitHub OAuth (handled by a separate Cloudflare Worker)
- Edits are committed directly to the GitHub repo — Cloudflare Pages redeploys automatically
What’s managed via CMS
Section titled “What’s managed via CMS”All editable content lives in src/data/*.json and src/content/blog/. The .astro pages import from these files.
| File | What’s editable |
|---|---|
src/data/pricing.json |
Website plans, SEO packages, SEO audit price |
src/data/faqs.json |
FAQs for homepage, web design, SEO, hosting pages |
src/data/about.json |
Team members, stats, how-we-work section |
src/data/homepage.json |
Clients list, process steps |
src/data/comparison.json |
Comparison table rows |
src/content/blog/ |
Blog posts including FAQs per post for Google rich results |
Things that stay hardcoded in .astro (contain inline SVG strings — no widget type for these): services cards, who-we-help grid, values section.
juju-template ships with both files pre-configured:
| File | Purpose |
|---|---|
public/admin/index.html |
Loads Sveltia CMS script |
public/admin/config.yml |
CMS collection and field definitions |
Per-client setup
Section titled “Per-client setup”Every new client project needs these four things configured:
1. Update public/admin/config.yml
Section titled “1. Update public/admin/config.yml”Change the two backend fields at the top:
backend: name: github repo: ctrl07/<client-repo-name> # ← change to client's GitHub repo branch: main base_url: https://sveltia-cms-auth.kurlekarsuyog.workers.dev2. Create a GitHub OAuth App
Section titled “2. Create a GitHub OAuth App”Go to github.com/settings/developers → OAuth Apps → New OAuth App:
| Field | Value |
|---|---|
| Application name | <Client Name> CMS |
| Homepage URL | https://<client-domain> |
| Authorization callback URL | https://sveltia-cms-auth.kurlekarsuyog.workers.dev/callback |
Copy the Client ID and generate a Client Secret.
3. Update the auth worker
Section titled “3. Update the auth worker”In Cloudflare dashboard → Workers → sveltia-cms-auth → Settings → Variables:
| Variable | Value |
|---|---|
GITHUB_CLIENT_ID |
from step 2 |
GITHUB_CLIENT_SECRET |
from step 2 |
ALLOWED_DOMAINS |
add <client-domain> (comma-separate if multiple) |
The same Worker can serve multiple client sites — just extend ALLOWED_DOMAINS.
4. Add collaborator to the GitHub repo
Section titled “4. Add collaborator to the GitHub repo”Only GitHub accounts with write access to the repo can log in. Go to repo Settings → Collaborators → add the client’s GitHub username.
Accessing the CMS
Section titled “Accessing the CMS”Visit https://<client-domain>/admin → click Login with GitHub → authorise the OAuth app.
_headers gotcha
Section titled “_headers gotcha”Cloudflare Pages merges all matching _headers rules — same header names are comma-joined, not overridden. The global /* CSP will be appended to any /admin/* CSP, making the combined value invalid.
Fix: use ! HeaderName to negate the global rule before setting your own:
/* Content-Security-Policy: default-src 'self'; ...
/admin/* ! Content-Security-Policy Content-Security-Policy: default-src * blob: data: 'unsafe-inline' 'unsafe-eval'; frame-ancestors 'none'This is already in juju-template’s public/_headers. Don’t remove it.
Editorial workflow
Section titled “Editorial workflow”publish_mode: editorial_workflow is enabled in config.yml. Blog posts go through three stages before reaching the live site:
| Stage | What it means |
|---|---|
| Draft | Work in progress — stored in a git branch, invisible to the site |
| In Review | Ready for feedback — still in a branch |
| Ready | Approved — merging this branch triggers a Cloudflare Pages rebuild |
Nothing appears on the live site until a “Ready” post is merged to main.
How edits work
Section titled “How edits work”- Editor changes a field and clicks Save
- Sveltia CMS commits the updated file to GitHub
- Cloudflare Pages detects the commit and rebuilds (2–3 minutes)
- Change is live on the site
For Draft and In Review posts, the commit goes to a separate branch — nothing changes on the live site until the post is Published (merged to main).
Adding a new CMS-managed field
Section titled “Adding a new CMS-managed field”- Add the field to the relevant
src/data/*.jsonfile - Add the corresponding widget to
public/admin/config.yml - Import and use the new field in the relevant
.astrofile - Commit and push