Deployed shape
Browser (ai.cannularobotics.com)
↓ Cloudflare Access (Google SSO, @cannularobotics.com) [pending]
Astro static site + Cloudflare Pages Functions
↓ /api/chat → cr-ai-proxy (Worker @ cr-proxy.cannularobotics.com)
↓ /api/search → cr-retrieval (Worker @ cr-retrieval.cannularobotics.com)
↓ /api/admin/ingest → cr-retrieval (admin trigger; token-gated)
cr-ai-proxy
↓ service binding to cr-retrieval (context for chat)
↓ Cloudflare AI Gateway (cr-ai-gateway) — auto-fallback to direct on 401
→ Anthropic API (Claude Opus 4.7, Zero Data Retention)
cr-retrieval
↓ Cloudflare Workers AI (BGE-large embeddings, 1024-dim)
↓ Cloudflare Vectorize (cr-notion / cr-granola / cr-drive)
↓ Cloudflare KV (sync state per source)
↓ Notion REST API (token auth)
↓ Google Drive v3 (user OAuth refresh token; no service account)
Everything CR — account, domain, gateway, proxy, secrets — lives in a single Cloudflare account separate from any other tenant.
Why this shape
- CF Access at the edge. No login screen we maintain. No session DB.
- One proxy, one gateway. Cost caps, rate limits, and audit trails live in one place. The model can change without touching the site.
- Static frontend. Pages are pre-rendered HTML. There is no server-side state to corrupt or scale.
- Service binding between proxy and retrieval. Internal traffic never leaves the Cloudflare network and doesn’t require a public Worker surface.
- One Vectorize index per source. We can scope queries, audit what was returned, and rebuild any single index without touching the others.
Data isolation
The CR Cloudflare account is independent of any other tenant. Anthropic billing is on a separate CR org with Zero Data Retention enabled — your prompts and completions are not retained for training. Embeddings are produced inside Cloudflare via Workers AI, so source text never leaves Cloudflare for embedding.