AI-Native Website Setup — Quick Reference
Companion to
ai-native-website-setup-playbook.mdUse this to prep before starting a new client site build.
Pre-Build Checklist (Gather Before Starting)
Client Must Provide
- Company name + legal entity name
- Domain name (purchased and ready)
- Tagline / one-line description
- Primary contact email
- Phone number
- Physical location (city, state)
- Brand colors (primary, accent, background at minimum; ideally full palette)
- Font choice (Google Fonts name)
- Logo files (horizontal, PNG + SVG)
- Headshots for team members (500x500 min)
- Social media links (LinkedIn, X/Twitter)
- Service descriptions (3-8 services)
- FAQ content (6-15 questions)
- Legal disclaimer text (if regulated industry)
- Cal.com (or other scheduler) booking link
- Content/copy for key pages (or a brief to write from)
Accounts to Create (Section 1)
| Account | URL | What You Need |
|---|---|---|
| GitHub | github.com | Repo for code |
| Cloudflare | cloudflare.com | Hosting + DNS + security |
| Brevo | brevo.com | Transactional email (free tier) |
| Cloudflare Turnstile | dash.cloudflare.com | CAPTCHA (free, privacy-respecting) |
| Cal.com | cal.com | Scheduling (free tier) |
| Umami | cloud.umami.is | Analytics (free tier, GDPR-friendly) |
Credentials to Collect
| Credential | Where to Find |
|---|---|
TURNSTILE_SITE_KEY | Cloudflare > Turnstile > Widget settings |
TURNSTILE_SECRET_KEY | Same (secret key) |
BREVO_API_KEY | Brevo > Settings > SMTP & API |
BREVO_LIST_ID | Brevo > Contacts > Lists (usually “2”) |
CLOUDFLARE_ACCOUNT_ID | Cloudflare dashboard URL bar |
CLOUDFLARE_API_TOKEN | Cloudflare > Profile > API Tokens |
UMAMI_WEBSITE_ID | Umami > Settings > Websites |
Umami Cloud URLs (Important)
Umami Cloud has two different base URLs — mixing them up causes 401 errors:
| Purpose | URL | Used For |
|---|---|---|
| Dashboard | https://cloud.umami.is | Logging in, managing websites, viewing reports |
| Tracking script | https://cloud.umami.is/script.js | Browser-side analytics (in <script> tags, CSP headers, preconnect) |
| API | https://api.umami.is/v1 | Server-side API calls (managing websites, fetching stats programmatically) |
Auth header for API calls: x-umami-api-key: <token> (NOT Authorization: Bearer)
Self-hosted is different: Self-hosted Umami uses Authorization: Bearer <jwt> and https://your-domain/api
Build Phases (13 Sections)
| Phase | Section | What Gets Built | Key Files |
|---|---|---|---|
| 1 | Prerequisites | Accounts, DNS, credentials | .env, .dev.vars |
| 2 | Scaffolding | Astro project, config, design tokens | astro.config.mjs, tailwind.config.mjs, wrangler.toml |
| 3 | Components | All reusable UI components + layouts | BaseLayout, Nav, Footer, ContactForm, + 8 more |
| 4 | API Routes | Contact form, newsletter, middleware | send-email.ts, newsletter-subscribe.ts, middleware.ts |
| 5 | Content | Blog system, pages, verticals, resources | content.config.ts, blog pages, /for/*, PrintLayout |
| 6 | Security | Headers, CSP, WAF, security.txt, SRI | _headers, .well-known/security.txt |
| 7 | Testing | Full E2E test suite | 10+ spec files in tests/e2e/ |
| 8 | CI/CD | Deploy, test, scheduled publish | 3 workflow files + dependabot |
| 9 | Assets | Images, favicons, PDFs | generate-pdfs.mjs, CREDITS.md |
| 10 | Deploy | First deploy, custom domain, monitoring | Cloudflare Pages dashboard |
| 11 | WP Migration | (Optional) WordPress to Astro conversion | wordpress-export-to-markdown |
| 12 | QA | Lighthouse, a11y, cross-browser, reviewer | Senior Reviewer workflow |
| 13 | Post-Launch | DNS verify, SEO submission, docs | CLAUDE.md, .env.example |
Run This First (After Section 1 is Complete)
# 1. Scaffold
mkdir project-name && cd project-name
npm create astro@latest . -- --template minimal --typescript strict --install --git
# 2. Install dependencies
npm install @astrojs/cloudflare @astrojs/tailwind @astrojs/sitemap @astrojs/rss tailwindcss @tailwindcss/typography lucide-astro sharp @fontsource/inter
npm install -D @playwright/test typescript
# 3. Install test browsers
npx playwright install chromium
# 4. Copy .dev.vars from template and fill in credentials
# 5. Start dev server
npm run devCritical Files (Must Exist Before Deploy)
src/lib/constants.ts # Site-wide constants (NEVER hardcode URLs)
src/lib/api-helpers.ts # Shared validation + security utilities
src/layouts/BaseLayout.astro # Base layout with meta tags, OG, analytics
src/components/Nav.astro # Sticky nav with mobile hamburger
src/components/Footer.astro # Footer with newsletter + email obfuscation
src/components/ContactForm.astro # Contact form with honeypot + Turnstile
public/_headers # Security headers (CSP, HSTS, etc.)
wrangler.toml # Cloudflare config with public vars
playwright.config.ts # Test config with build+preview webServer
.github/workflows/deploy.yml # Push-to-main auto-deploy
.dev.vars # Local secrets (NEVER commit)
Quality Gates
After every major section:
npm run build(must succeed)npx playwright test(must pass)- Commit with descriptive message
- Senior Reviewer audit (for final deploy)
Target: 90+ on all four Lighthouse categories (Performance, Accessibility, Best Practices, SEO)
SEO & LLM Optimization (Must-Have for Every Site)
Structured Data (JSON-LD)
Every site should include JSON-LD structured data in BaseLayout.astro:
LocalBusinessorOrganizationschema (name, address, phone, URL, logo)WebSiteschema withSearchActionfor sitelinks search boxServiceschema for each service offeredFAQPageschema on FAQ/services pages- Test with: Google Rich Results Test
LLM Discoverability
Create two files in public/ for AI assistant discoverability:
| File | Purpose | Content |
|---|---|---|
llms.txt | Quick summary for LLMs | Business name, description, page list with URLs, services, contact info |
llms-full.txt | Extended version | Everything in llms.txt + full service descriptions, testimonials, detailed content |
Link them: add Optional section in llms.txt pointing to llms-full.txt.
robots.txt AI Crawler Blocks
Use a dynamic robots.txt (e.g., src/pages/robots.txt.ts) to block AI training crawlers while allowing search engines:
User-agent: GPTBot
Disallow: /
User-agent: ChatGPT-User
Disallow: /
User-agent: Google-Extended
Disallow: /
User-agent: CCBot
Disallow: /
User-agent: anthropic-ai
Disallow: /
Sitemap Gotcha (Astro)
Astro’s @astrojs/sitemap generates sitemap-index.xml, not sitemap.xml. Google Search Console and most tools expect /sitemap.xml. Fix with a redirect in public/_redirects:
/sitemap.xml /sitemap-index.xml 301
Dual Deploy Pattern (Staging + Production)
For sites that need a staging environment, use two CF Pages projects with a single workflow:
# .github/workflows/deploy.yml
- name: Deploy to staging
run: npx wrangler pages deploy dist/ --project-name=mysite-staging --branch="$DEPLOY_BRANCH"
- name: Deploy to production
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: npx wrangler pages deploy dist/ --project-name=mysite --branch=main- Staging deploys on every push (including PRs)
- Production only deploys on push to
main - Both use the same
CLOUDFLARE_API_TOKENandCLOUDFLARE_ACCOUNT_IDsecrets - Build-time env vars (like
UMAMI_WEBSITE_ID,SITE_URL) go in GitHub Actions vars (not secrets)
Multi-Account Cloudflare Setup
Solanasis manages 3 separate CF accounts. Credentials are in Infisical with shared folder imports.
| Account | Infisical Source | Zones | |
|---|---|---|---|
| Personal | dmitri@mrsunshine.me | /cf-personal/ | selfinquire.com, collab-culture.com, co-nexus.co, creators-hub.co, regenerositysociety.com, zasage.me |
| Solanasis | mr.sunshine@solanasis.com | /shared/ | solanasis.com, mrsunshine.me |
| Matchkeyz | admin@matchkeyz.com | /matchkeyz/ | matchkeyz.io |
Onboarding a New Domain (Personal Account)
python3 ~/\_my/_solanasis/infisical/link_cf_account.py <folder-name>
# e.g.: link_cf_account.py co-nexus-site
# Creates Infisical folder, adds /shared/ + /cf-personal/ imports, verifies CF keyUse --check-only for dry run. Use --cf-account solanasis for Solanasis domains.
See also: cf-pages-cutover-playbook.md for the full cutover procedure when migrating a domain to CF Pages.
WordPress Migration Redirects
When migrating from WordPress to Astro/CF Pages, create public/_redirects with:
- Sitemap alias —
/sitemap.xml → /sitemap-index.xml(301) - Changed paths — old WP paths → new Astro paths (301)
- Category archives —
/category/* → /(301) - RSS feeds —
/feed/ → /(301) - Individual post slugs — old post URLs → appropriate section page (301)
- WordPress infrastructure blocks —
/wp-admin/*,/wp-content/*,/wp-includes/*,/wp-json/*,/wp-login.php,/xmlrpc.php→ 404
Key Patterns to Remember
| Pattern | Why |
|---|---|
BOOKING_URL from constants.ts, never hardcoded | Single source of truth for booking link |
data-cal-link + href={BOOKING_URL} on every CTA | Cal.com modal + no-JS fallback |
<picture> with WebP source + JPG fallback | Performance + browser compatibility |
escapeHtml() on all user input in emails | XSS prevention |
MAX_LENGTHS validation on all API inputs | Input boundary protection |
export const prerender = false on API routes | Required for Cloudflare SSR |
| Turnstile test key in playwright.config.ts | Tests pass without real CAPTCHA |
data.date <= new Date() for blog filtering | Future-dated posts hidden until publish date |
| Daily cron deploy for blog auto-publish | Future posts go live automatically |
UMAMI_WEBSITE_ID is a build-time var, not a secret | Static sites bake it into HTML at build; use GitHub vars, not secrets |
| Global API Key for DNS ops, scoped token for Pages | Scoped tokens need explicit DNS:Read + DNS:Edit for domain binding |
/sitemap.xml → /sitemap-index.xml redirect | Astro generates sitemap-index.xml; tools expect sitemap.xml |
Template Variables Quick Count
| Category | Count |
|---|---|
| Company identity | 6 |
| Contact info | 5 |
| Booking/scheduling | 3 |
| Social media | 2 |
| Brand colors | 10 |
| Typography | 2 |
| Infrastructure | 4 |
| Content | 3 |
| Structure (JSON) | 9 |
| Total | 44 |
All variables defined in Section 0.1 of the main playbook.
Generated by Solanasis LLC.