Documentation Site Setup
This guide documents how this documentation site was set up, including the tech stack choices and configuration steps.
Tech Stack
Section titled “Tech Stack”| Component | Technology | Purpose |
|---|---|---|
| Framework | Astro + Starlight | Static site generator optimized for documentation |
| CMS | Decap CMS | Git-based headless CMS with web UI |
| Hosting | Cloudflare Pages | Free static hosting with auto-deploy |
| Auth | Cloudflare Worker | OAuth proxy for GitHub authentication |
| Storage | GitHub | Version control and content storage |
Why This Stack?
Section titled “Why This Stack?”Astro + Starlight
Section titled “Astro + Starlight”- Purpose-built for documentation sites
- Fast static output with excellent SEO
- Built-in search, navigation, and dark mode
- MDX support for interactive components
Decap CMS (formerly Netlify CMS)
Section titled “Decap CMS (formerly Netlify CMS)”- Free and open source - No per-user pricing
- Git-based - Content stored in GitHub, not a separate database
- Web UI - Edit content without touching code
- No vendor lock-in - Content is just Markdown files
Cloudflare Pages
Section titled “Cloudflare Pages”- Free tier - Unlimited sites, generous bandwidth
- Auto-deploy - Push to GitHub, site updates automatically
- Fast global CDN - Built into Cloudflare’s network
- Custom domains - Easy SSL and DNS integration
Why Not Other Options?
Section titled “Why Not Other Options?”- Netlify: Would work, but we’re already using Cloudflare for DNS
- Vercel: Great for Next.js, but Cloudflare is simpler for static sites
- Contentful/Sanity: Overkill for docs, and have user/content limits on free tiers
Setup Steps
Section titled “Setup Steps”1. Create the Astro Project
Section titled “1. Create the Astro Project”npm create astro@latest jb-cloud-docs -- --template starlightcd jb-cloud-docsnpm install2. Configure Astro (astro.config.mjs)
Section titled “2. Configure Astro (astro.config.mjs)”import { defineConfig } from 'astro/config';import starlight from '@astrojs/starlight';
export default defineConfig({ site: 'https://docs.jbcloud.app', integrations: [ starlight({ title: 'JB Cloud Docs', sidebar: [ { label: 'xCloud', autogenerate: { directory: 'xcloud' }, }, { label: 'Cloudflare', autogenerate: { directory: 'cloudflare' }, }, // Add more sections as needed ], }), ],});3. Set Up Decap CMS
Section titled “3. Set Up Decap CMS”Create public/admin/index.html:
<!doctype html><html><head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="robots" content="noindex" /> <title>Content Manager</title></head><body> <script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script></body></html>Create public/admin/config.yml:
backend: name: github repo: YOUR_USERNAME/YOUR_REPO branch: main base_url: https://github-oauth.YOUR_SUBDOMAIN.workers.dev auth_endpoint: /auth
media_folder: "public/images"public_folder: "/images"
collections: - name: "xcloud" label: "xCloud" folder: "src/content/docs/xcloud" create: true slug: "{{slug}}" fields: - { label: "Title", name: "title", widget: "string" } - { label: "Description", name: "description", widget: "string" } - { label: "Sort Order", name: "sidebar", widget: "object", fields: [{ label: "Order", name: "order", widget: "number", default: 0 }] } - { label: "Body", name: "body", widget: "markdown" }4. Create GitHub OAuth App
Section titled “4. Create GitHub OAuth App”- Go to GitHub → Settings → Developer settings → OAuth Apps
- Click New OAuth App
- Fill in:
- Application name: Your Docs CMS
- Homepage URL:
https://your-docs-site.com - Callback URL:
https://github-oauth.YOUR_SUBDOMAIN.workers.dev/callback
- Save the Client ID and Client Secret
5. Create Cloudflare Worker for OAuth
Section titled “5. Create Cloudflare Worker for OAuth”Cloudflare Pages doesn’t have built-in OAuth like Netlify, so we need a Worker to handle GitHub authentication.
- Go to Cloudflare → Workers & Pages → Create Worker
- Name it
github-oauth - Deploy, then edit with this code:
export default { async fetch(request, env) { const url = new URL(request.url);
if (url.pathname === '/auth') { const authUrl = `https://github.com/login/oauth/authorize?client_id=${env.CLIENT_ID}&scope=repo,user`; return Response.redirect(authUrl, 302); }
if (url.pathname === '/callback') { const code = url.searchParams.get('code');
if (!code) { return new Response('Missing code parameter', { status: 400 }); }
const response = await fetch('https://github.com/login/oauth/access_token', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ client_id: env.CLIENT_ID, client_secret: env.CLIENT_SECRET, code: code }) });
const data = await response.json();
if (data.error) { return new Response(`Error: ${data.error_description}`, { status: 400 }); }
const token = data.access_token;
const html = `<!DOCTYPE html><html><head><title>Authorizing...</title></head><body><script>(function() { function receiveMessage(e) { window.opener.postMessage( 'authorization:github:success:{"token":"${token}","provider":"github"}', e.origin ); window.removeEventListener("message", receiveMessage, false); } window.addEventListener("message", receiveMessage, false); window.opener.postMessage("authorizing:github", "*");})();</script></body></html>`;
return new Response(html, { headers: { 'Content-Type': 'text/html' } }); }
return new Response('Not found', { status: 404 }); }};- Add environment variables in Worker Settings → Variables:
CLIENT_ID= Your GitHub OAuth Client IDCLIENT_SECRET= Your GitHub OAuth Client Secret (encrypt this)
6. Deploy to Cloudflare Pages
Section titled “6. Deploy to Cloudflare Pages”- Push your code to GitHub
- Go to Cloudflare → Workers & Pages → Create → Pages
- Connect to your GitHub repo
- Configure build settings:
- Framework: Astro
- Build command:
npm run build - Output directory:
dist
- Deploy
7. Add Custom Domain
Section titled “7. Add Custom Domain”- In Cloudflare Pages, go to Custom domains
- Add your domain (e.g.,
docs.jbcloud.app) - Cloudflare handles DNS and SSL automatically
Adding Content via CMS
Section titled “Adding Content via CMS”- Go to
https://your-site.com/admin - Login with GitHub
- Select a collection
- Click New to create a document
- Fill in the fields and write your content
- Click Publish
Changes are committed to GitHub and auto-deployed.
Adding Content via Code
Section titled “Adding Content via Code”# Create a new doctouch src/content/docs/xcloud/new-guide.md
# Edit with your preferred editor# Then commit and pushgit add -Agit commit -m "Add new guide"git pushDocument Frontmatter
Section titled “Document Frontmatter”Every doc needs frontmatter:
---title: Your Page Titledescription: Brief description for SEO and previews.sidebar: order: 1 # Controls sort order in navigation---
Your content here...Troubleshooting
Section titled “Troubleshooting”OAuth Login Fails
Section titled “OAuth Login Fails”- Check that the GitHub OAuth callback URL matches your Worker URL exactly
- Verify environment variables are set in the Worker
- Try a different browser (Safari can be strict with popups)
Build Fails on Cloudflare
Section titled “Build Fails on Cloudflare”- Check Node.js version - add
NODE_VERSION=18in environment variables if needed - Review build logs for specific errors
CMS Changes Not Appearing
Section titled “CMS Changes Not Appearing”- Cloudflare Pages deploys take 1-2 minutes
- Check the deployment status in Cloudflare dashboard
- Hard refresh the site (Cmd+Shift+R)
Using Claude Code for Setup
Section titled “Using Claude Code for Setup”This entire documentation site was set up with the help of Claude Code, Anthropic’s CLI tool for AI-assisted development. Here’s how Claude Code streamlined the process.
What Claude Code Did
Section titled “What Claude Code Did”- Scaffolded the project - Created the Astro Starlight project with proper configuration
- Wrote configuration files - Generated
astro.config.mjs, Decap CMS config, and Worker code - Created initial documentation - Wrote the first docs based on our conversation
- Set up GitHub repo - Initialized git, created the repo, and pushed code
- Debugged OAuth issues - Fixed the Worker code when Safari had popup restrictions
- Generated this guide - Meta-documented the entire setup process
How to Use Claude Code for Similar Projects
Section titled “How to Use Claude Code for Similar Projects”Install Claude Code:
npm install -g @anthropic-ai/claude-codeStart a session in your project directory:
cd ~/Sites/my-projectclaudeExample Prompts
Section titled “Example Prompts”Starting a docs site:
Create a documentation site using Astro Starlight with sectionsfor xCloud, Cloudflare, Supabase, and Vercel. Set up Decap CMSfor web-based editing and deploy to Cloudflare Pages.Adding documentation:
Add documentation for how to update Docker apps on xCloud via SSH.Include the issue with Docker permissions and the Command Runner workaround.Debugging issues:
The OAuth login shows this error in the console: [paste error].What's wrong and how do I fix it?What Claude Code Has Access To
Section titled “What Claude Code Has Access To”When running on your machine, Claude Code can:
- Read and write files in your project
- Run terminal commands (npm, git, etc.)
- Create GitHub repos via
ghCLI - Check configurations and suggest fixes
It does NOT have direct access to:
- Cloud provider dashboards (Cloudflare, AWS, etc.)
- Your browser or GUI applications
- Services requiring OAuth (unless MCP servers are configured)
Tips for Working with Claude Code
Section titled “Tips for Working with Claude Code”-
Be specific - “Add a guide for updating OpenWebUI on xCloud” is better than “add some docs”
-
Share context - Paste error messages, screenshots, or relevant config snippets
-
Iterate - If something doesn’t work, share the error and Claude Code will debug
-
Let it handle boilerplate - Config files, Worker code, and repetitive setup tasks are perfect for AI assistance
-
Review before committing - Always check generated code makes sense for your use case
The Setup Conversation Flow
Section titled “The Setup Conversation Flow”Here’s roughly how the conversation went to create this site:
- “Create a docs site for my cloud processes” → Claude Code suggested the tech stack options
- “Use Decap CMS, host on Cloudflare Pages” → Created the project and configuration
- “Set up the GitHub repo” → Initialized and pushed to GitHub
- “Deploy failed, wrong username” → Fixed the config
- “OAuth isn’t working” → Created the Cloudflare Worker
- “Still getting errors” → Debugged Safari popup issues
- “Document how we set this up” → Generated this guide
Total time: ~30 minutes from idea to fully deployed docs site with CMS.
When to Use Claude Code vs Manual Setup
Section titled “When to Use Claude Code vs Manual Setup”Use Claude Code when:
- Setting up new projects with multiple config files
- Writing boilerplate code (Workers, configs, etc.)
- Debugging errors you’re unfamiliar with
- Generating documentation from conversations
- Repetitive git operations
Do manually when:
- Configuring cloud dashboards (Cloudflare, GitHub OAuth apps)
- Sensitive operations (adding secrets, production deployments)
- You want to understand each step deeply
- The task requires visual/GUI interaction