# DNS — point `kbatch.ugrad.ai` at Cloudflare Pages (not GitHub)

## Problem

| URL | Status |
|-----|--------|
| Preview deploy | `https://06711109.ugrad-kbatch.pages.dev` · branch `fix-push-test.…` — **live** |
| Production Pages | `https://ugrad-kbatch.pages.dev` — needs a **production** deploy |
| Custom domain | `https://kbatch.ugrad.ai` — **404** while CNAME still targets **GitHub** |

## Record to set (Cloudflare DNS for zone `ugrad.ai`)

| Field | Value |
|-------|--------|
| **Type** | **CNAME** |
| **Name** | `kbatch` |
| **Target** | **`ugrad-kbatch.pages.dev`** |
| **Proxy** | Proxied (orange cloud) |
| **TTL** | Auto |

### Do **not** use

| Target | Why |
|--------|-----|
| `qbitos.github.io` | GitHub Pages — causes “Site not found” / wrong origin |
| `06711109.ugrad-kbatch.pages.dev` | One-off preview hash — changes every deploy |

### Optional regional CNAMEs (same project, scalable later)

| Name | Target | Host |
|------|--------|------|
| `kbatch-us` | `ugrad-kbatch.pages.dev` | `kbatch-us.ugrad.ai` |
| `kbatch-eu` | `ugrad-kbatch.pages.dev` | `kbatch-eu.ugrad.ai` |

Same Pages project; region is detected in-app via hostname (`js/version.js`).

---

## R2 data host — `data.ugrad.ai`

Bucket: **`ugrad-kbatch-data`**  
Object prefix: **`kbatch/`** (so packs live at `kbatch/analyzed/r.json`)  
SPA meta: `https://data.ugrad.ai/kbatch/` → fetches `…/kbatch/analyzed/a.json`

### Preferred (zone `ugrad.ai` already on Cloudflare)

Do **not** hand-roll a random CNAME to `r2.dev`.

1. Dashboard → **R2** → **ugrad-kbatch-data** → **Settings**  
2. **Custom Domains** → **Add** → enter **`data.ugrad.ai`**  
3. **Connect Domain** — Cloudflare adds/updates DNS for you  
4. Wait until status is **Active**

| Field | Value |
|-------|--------|
| **Name** | `data` |
| **Type** | **CNAME** (Cloudflare-managed when you Connect Domain) |
| **Target** | Auto-set by R2 Custom Domains (not something you invent) |
| **Proxy** | Proxied (orange cloud) |
| **Public URL** | `https://data.ugrad.ai/kbatch/analyzed/r.json` |

### If you must set DNS manually

Only after **Connect Domain** shows a target in **Manage DNS**:

| Field | Value |
|-------|--------|
| **Type** | **CNAME** |
| **Name** | `data` |
| **Target** | The hostname R2 shows when connecting the domain (often a `*.r2.cloudflarestorage.com` / account-specific host) |
| **Proxy** | **Proxied** |

Do **not** CNAME `data` → a `*.r2.dev` public development URL for production ([unsupported](https://developers.cloudflare.com/r2/buckets/public-buckets/)).

### After upload

```bash
# objects: kbatch/analyzed/{a-z}.json  kbatch/words/…  kbatch/word-index.json
./scripts/upload-r2.sh

curl -I https://data.ugrad.ai/kbatch/analyzed/r.json
# expect 200 when custom domain Active + object uploaded

curl -I https://data.ugrad.ai/kbatch/index.json
# catalog (R2 never lists directories — bare /kbatch/ is often still 404)
```

**Why `https://data.ugrad.ai/kbatch/` can 404 while files work:**  
R2 public buckets **do not directory-list**. Only **exact object keys** resolve. Use:

| URL | Expected |
|-----|----------|
| `/kbatch/analyzed/r.json` | **200** object |
| `/kbatch/index.json` | **200** catalog |
| `/kbatch/index.html` | **200** landing (if uploaded) |
| `/kbatch/` | often **404** (no auto-index unless Workers rewrite) |

SPA already has:

```html
<meta name="kbatch-data-base" content="https://data.ugrad.ai/kbatch/" />
```

Loader falls back to `./data/analyzed/` if remote 404 (local dev).

---

## Recommended path (easiest)

Because `ugrad.ai` is already on Cloudflare:

1. Deploy **production** (see below) so `ugrad-kbatch.pages.dev` is not “Deployment Not Found”.
2. Dashboard → **Workers & Pages** → **ugrad-kbatch** → **Custom domains** → add **`kbatch.ugrad.ai`**.
3. Cloudflare **rewrites** the CNAME to the Pages host automatically (replacing `qbitos.github.io`).

Manual DNS edit works too — use the table above.

---

## Production deploy (so `*.pages.dev` root works)

```bash
export CLOUDFLARE_API_TOKEN=…

cd /Users/qbit/Projects/KBatch-dictionary

# Production (serves https://ugrad-kbatch.pages.dev)
npm run deploy:prod

# Or explicit:
npx wrangler pages deploy . \
  --project-name=ugrad-kbatch \
  --branch=main \
  --commit-dirty=true
```

In Pages project settings, set **Production branch** to **`main`** (not `KBatch-dictionary` or `fix/push-test`).

Preview / branch deploys keep working as:

`https://<branch>.ugrad-kbatch.pages.dev`

---

## Product identity (unique name + versioning)

| Field | Value |
|-------|--------|
| **productId** | `ugrad.kbatch.shadow` |
| **productSlug / CF project** | `ugrad-kbatch` |
| **version** | `version.json` → `1.1.0` (semver) |
| **region** | `global` \| `us` \| `eu` \| `preview` |
| **buildId** | `1.1.0+global.YYYYMMDDHHMMSS` |

Files: `version.json`, `js/version.js`, runtime `kbatchDict.corpus.identity()`.

---

## Verify after DNS

```bash
# Should show CNAME → ugrad-kbatch.pages.dev (or CF Pages target)
dig +short CNAME kbatch.ugrad.ai

curl -sI https://kbatch.ugrad.ai/ | head -5
curl -sI https://kbatch.ugrad.ai/shadow | head -5
curl -s https://kbatch.ugrad.ai/version.json
```

Expect: `200`, HTML with Shadow Live, and `version.json` with `productId`.
