AI-Native Website Setup — Quick Reference

Companion to ai-native-website-setup-playbook.md Use 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)

AccountURLWhat You Need
GitHubgithub.comRepo for code
Cloudflarecloudflare.comHosting + DNS + security
Brevobrevo.comTransactional email (free tier)
Cloudflare Turnstiledash.cloudflare.comCAPTCHA (free, privacy-respecting)
Cal.comcal.comScheduling (free tier)
Umamicloud.umami.isAnalytics (free tier, GDPR-friendly)

Credentials to Collect

CredentialWhere to Find
TURNSTILE_SITE_KEYCloudflare > Turnstile > Widget settings
TURNSTILE_SECRET_KEYSame (secret key)
BREVO_API_KEYBrevo > Settings > SMTP & API
BREVO_LIST_IDBrevo > Contacts > Lists (usually “2”)
CLOUDFLARE_ACCOUNT_IDCloudflare dashboard URL bar
CLOUDFLARE_API_TOKENCloudflare > Profile > API Tokens
UMAMI_WEBSITE_IDUmami > Settings > Websites

Umami Cloud URLs (Important)

Umami Cloud has two different base URLs — mixing them up causes 401 errors:

PurposeURLUsed For
Dashboardhttps://cloud.umami.isLogging in, managing websites, viewing reports
Tracking scripthttps://cloud.umami.is/script.jsBrowser-side analytics (in <script> tags, CSP headers, preconnect)
APIhttps://api.umami.is/v1Server-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)

PhaseSectionWhat Gets BuiltKey Files
1PrerequisitesAccounts, DNS, credentials.env, .dev.vars
2ScaffoldingAstro project, config, design tokensastro.config.mjs, tailwind.config.mjs, wrangler.toml
3ComponentsAll reusable UI components + layoutsBaseLayout, Nav, Footer, ContactForm, + 8 more
4API RoutesContact form, newsletter, middlewaresend-email.ts, newsletter-subscribe.ts, middleware.ts
5ContentBlog system, pages, verticals, resourcescontent.config.ts, blog pages, /for/*, PrintLayout
6SecurityHeaders, CSP, WAF, security.txt, SRI_headers, .well-known/security.txt
7TestingFull E2E test suite10+ spec files in tests/e2e/
8CI/CDDeploy, test, scheduled publish3 workflow files + dependabot
9AssetsImages, favicons, PDFsgenerate-pdfs.mjs, CREDITS.md
10DeployFirst deploy, custom domain, monitoringCloudflare Pages dashboard
11WP Migration(Optional) WordPress to Astro conversionwordpress-export-to-markdown
12QALighthouse, a11y, cross-browser, reviewerSenior Reviewer workflow
13Post-LaunchDNS verify, SEO submission, docsCLAUDE.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 dev

Critical 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:

  1. npm run build (must succeed)
  2. npx playwright test (must pass)
  3. Commit with descriptive message
  4. 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:

  • LocalBusiness or Organization schema (name, address, phone, URL, logo)
  • WebSite schema with SearchAction for sitelinks search box
  • Service schema for each service offered
  • FAQPage schema on FAQ/services pages
  • Test with: Google Rich Results Test

LLM Discoverability

Create two files in public/ for AI assistant discoverability:

FilePurposeContent
llms.txtQuick summary for LLMsBusiness name, description, page list with URLs, services, contact info
llms-full.txtExtended versionEverything 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_TOKEN and CLOUDFLARE_ACCOUNT_ID secrets
  • 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.

AccountEmailInfisical SourceZones
Personaldmitri@mrsunshine.me/cf-personal/selfinquire.com, collab-culture.com, co-nexus.co, creators-hub.co, regenerositysociety.com, zasage.me
Solanasismr.sunshine@solanasis.com/shared/solanasis.com, mrsunshine.me
Matchkeyzadmin@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 key

Use --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:

  1. Sitemap alias/sitemap.xml → /sitemap-index.xml (301)
  2. Changed paths — old WP paths → new Astro paths (301)
  3. Category archives/category/* → / (301)
  4. RSS feeds/feed/ → / (301)
  5. Individual post slugs — old post URLs → appropriate section page (301)
  6. WordPress infrastructure blocks/wp-admin/*, /wp-content/*, /wp-includes/*, /wp-json/*, /wp-login.php, /xmlrpc.php → 404

Key Patterns to Remember

PatternWhy
BOOKING_URL from constants.ts, never hardcodedSingle source of truth for booking link
data-cal-link + href={BOOKING_URL} on every CTACal.com modal + no-JS fallback
<picture> with WebP source + JPG fallbackPerformance + browser compatibility
escapeHtml() on all user input in emailsXSS prevention
MAX_LENGTHS validation on all API inputsInput boundary protection
export const prerender = false on API routesRequired for Cloudflare SSR
Turnstile test key in playwright.config.tsTests pass without real CAPTCHA
data.date <= new Date() for blog filteringFuture-dated posts hidden until publish date
Daily cron deploy for blog auto-publishFuture posts go live automatically
UMAMI_WEBSITE_ID is a build-time var, not a secretStatic sites bake it into HTML at build; use GitHub vars, not secrets
Global API Key for DNS ops, scoped token for PagesScoped tokens need explicit DNS:Read + DNS:Edit for domain binding
/sitemap.xml → /sitemap-index.xml redirectAstro generates sitemap-index.xml; tools expect sitemap.xml

Template Variables Quick Count

CategoryCount
Company identity6
Contact info5
Booking/scheduling3
Social media2
Brand colors10
Typography2
Infrastructure4
Content3
Structure (JSON)9
Total44

All variables defined in Section 0.1 of the main playbook.


Generated by Solanasis LLC.