# Online access (phone or another computer)

The learning station, lecture HTML, and catalogs ship as **one static tree**. After a merge to `main`, GitHub Actions builds `_site/` and publishes it to **Cloudflare Pages** (the Git repository may stay private). Later edits to a lecture or a lab land on the same URL. You do not need ports 7200 / 7300 / 7400 on the public site.

**Recommended URL (Cloudflare; a private repo can still serve a public site):**

**https://kaiyuan-xiangmu-jiexi-zixi.pages.dev/**

English catalog: **https://kaiyuan-xiangmu-jiexi-zixi.pages.dev/en/**

(If the first deploy finds the name taken, Cloudflare appends a suffix. Trust the URL in the Actions log.)

Fallback: GitHub Pages `https://mikayiyang.github.io/kaiyuan-xiangmu-jiexi-zixi/` (the free plan requires a **public** repository).

The site root redirects to the Chinese catalog. Interactive stations live on the same origin:

| Local port | Public path |
|---|---|
| `:7300` Claude Code v1 | `/learn/claude-v1/` |
| `:7301` Claude Code v2 | `/learn/claude-v2/` |
| `:7200` OpenManus × Suna | `/learn/manus/` |
| `:7200/build-guide.html` | `/learn/manus/build-guide.html` |
| `:7397` Build-an-agent guide | `/learn/agent-guide/` |
| `:7380` DeepSeek Harness (if that station is merged) | `/learn/dsh/` |
| `:7400/….html` lectures (including Easel) | same filename at the site root |
| English lectures | `/en/` |

Source catalogs still write `127.0.0.1` ports so local multi-process preview keeps working. **Only the build product `_site/`** rewrites those URLs to relative paths. Do not hand-edit the `AUTO-CATALOG` region in the Chinese catalog.

The build runs in GitHub Actions. By default it force-pushes `_site/` to the **`site`** branch. Cloudflare should **host** that branch; it should not compile from `main` (that environment is a poor fit for Python plus four Vite apps).

---

## Which hosting option

| Option | Domain | Can the repo stay private? | Do you need a server? |
|---|---|---|---|
| **A. Cloudflare Pages on the `site` branch (recommended)** | `*.pages.dev` | Yes; the site itself is public | No |
| **A2. Wrangler direct upload** | same | Yes | No; the token must be allowed to manage Pages |
| **B. GitHub Pages** | `mikayiyang.github.io/kaiyuan-xiangmu-jiexi-zixi/` | Free plan needs **Public** | No |
| **C. Your own small VPS** | IP or your domain | Yes | Yes; rsync `_site/` |

`github.io` does not point at your machine and does not point at Cloudflare. They are independent.

---

## A. Cloudflare Pages via Git (stable; no API token required)

Wrangler direct upload has returned **error 7003** even when the Account ID length was correct and the secret reached Actions. That usually means **the token lacks Pages permission, or the token and the account are not the same Cloudflare account**—not a mistyped ID.

So the pipeline is: on merge to `main`, push the static tree to the **`site`** branch. You connect Git in Cloudflare once.

### 1. Merge the PR so Actions can push `site`

When Actions → **Deploy site** is green, the repository should show branch `site`:

https://github.com/mikayiyang/kaiyuan-xiangmu-jiexi-zixi/tree/site

### 2. Attach that branch in Cloudflare

1. Open [Workers & Pages](https://dash.cloudflare.com/?to=/:account/workers-and-pages).
2. In the 2026 dashboard, **Create** opens **Workers**, not Pages. Use the small link **Looking to deploy Pages? Get started**, or open [Create Pages](https://dash.cloudflare.com/?to=/:account/workers-and-pages/create/pages) directly. Do **not** click the large Connect-to-GitHub box on the Workers screen.
3. Import an existing Git repository. Authorize GitHub. Select `kaiyuan-xiangmu-jiexi-zixi` (private is fine).
4. Settings:
   - Production branch: **`site`** (not `main`)
   - Framework preset: **None**
   - Build command: **empty**
   - Build output directory: **`/`**
5. Save / Deploy.

After that, every merge to `main` overwrites `site`, and Cloudflare publishes. The URL remains `*.pages.dev`.

### The red “Cloudflare Pages — Building” check on a pull request

If GitHub **build** (Actions · Deploy site) is green, you can merge. The Cloudflare red X is a **Git preview deploy**: Cloudflare checks out the PR’s source branch, looks for `_site/` (gitignored, not on that branch), and reports Build failed. **That is not “the English station failed to build,” and it does not block publishing.**

What actually ships: merge to `main` → Actions pushes the **`site`** branch → Cloudflare hosts `site`.

To make the red X go away (optional):

1. Cloudflare → this Pages project → **Settings → Builds & deployments**
2. Turn **Preview deployments** off, or include only branch **`site`**
3. Keep production branch **`site`**, empty build command, output `/`

`wrangler.toml` in this repo no longer sets `pages_build_output_dir = "_site"`, so Cloudflare will not keep looking for that folder on PRs.

---

## A2. Wrangler direct upload (optional)

If the token’s permissions are correct, the same workflow still attempts `wrangler pages deploy`. Failure does not block the `site` branch.

Create the token from the **Edit Cloudflare Workers** template (it includes Pages). Do not grant only one custom line:

1. [Account API tokens](https://dash.cloudflare.com/?to=/:account/api-tokens) → Create Token → **Edit Cloudflare Workers** → Use template.
2. Account Resources: the **same** account.
3. Copy the **Account ID** from the Workers & Pages overview (right-hand side). Do not copy a Zone ID under a domain.
4. Repository [Repository secrets](https://github.com/mikayiyang/kaiyuan-xiangmu-jiexi-zixi/settings/secrets/actions):
   - `CLOUDFLARE_API_TOKEN`
   - `CLOUDFLARE_ACCOUNT_ID`

### Local one-shot upload (optional)

```bash
export CLOUDFLARE_API_TOKEN='…'
export CLOUDFLARE_ACCOUNT_ID='…'
./scripts/deploy-cloudflare.sh
```

---

## B. GitHub Pages (optional fallback; the current workflow does not push it)

This repository is **private**. GitHub’s free plan **does not serve public Pages from a private repo**. Actions currently pushes the **`site` branch for Cloudflare**, not a `gh-pages` branch for github.io.

If the repo later becomes Public and you want github.io:

1. GitHub repo → **Settings → General → Danger Zone → Change repository visibility → Public**.
2. Run `python3 scripts/build-site.py`, then place `_site/` on the branch / official Pages workflow GitHub requires.
3. **Settings → Pages** as in GitHub’s docs.

A private repo with GitHub Pro / Team can serve Pages only to people who can read the repo. Day-to-day study should use `pages.dev` above.

---

## C. Mirror the same tree on a small VPS

Useful if you already have a public IP or a domain. Independent of Cloudflare.

```bash
python3 scripts/build-site.py
rsync -a --delete _site/ user@your-server:/var/www/learn/
```

Nginx example:

```nginx
server {
    listen 80;
    server_name _;
    root /var/www/learn;
    index 总目录.html index.html;
    location / {
        try_files $uri $uri/ /总目录.html;
    }
}
```

Chinese filenames need a UTF-8 locale on the server.

---

## Preview the same tree locally

```bash
python3 scripts/build-site.py          # emit _site/
python3 -m http.server 7400 --directory _site --bind 127.0.0.1
# open ../总目录.html
# English: ./
```

`./start-html-previews.sh` assembles `_site/` by default and points **7400** at that unified tree. Skip assembly with `UNIFIED=0 ./start-html-previews.sh`.

---

## How later edits reach the public site

Edit Markdown / a learning station as usual → `python3 build-html.py` (if you touched a Markdown file that script indexes) → `python3 scripts/build-en-html.py` (if you touched English lectures) → `python3 update-catalog.py` → commit and **merge to `main`**. Actions rebuilds `_site` and publishes. You do not need 7200 / 7300 in order to read the public site.
