# 宪法 · Capacitor 7 + htmx + 服务器构建 + Capgo 热更新 + nginx HTTPS 分发

> 这是本项目不可动摇的技术宪法。任何后续业务迭代都**只改 htmx/网页模块**，
> 原生基座一旦稳定即冻结。若你（AI）失忆，读完本文即可恢复全部工作能力。

---

## 0. 宪法（不可动摇的前提）

1. **技术栈固定**，顺序与版本不可随意替换：
   - Capacitor **7.x**（不是 8，不是 Cordova）
   - htmx **2.x**，本地打包（`www/htmx.min.js`），不依赖 CDN
   - 构建机 + 分发机 = 香港 Linux 服务器 `xg.vlai.tech`（SSH 端口 `2331`）
   - 热更新 = `@capgo/capacitor-updater@^7`（self-hosted 最简协议）
   - 分发 = `nginx` + Let's Encrypt 证书（域名 `xg.vlai.tech`，80/443 已开放）
2. **分工铁律**：AI 写 htmx 模块 → 服务器构建/验证 → 人类只验收成品。
   验证环（构建+打包+发布）**全程在服务器侧闭环，不占用人类**。
3. **更新哲学**：日常改动只动 Web 模块，App 内点「检查更新→点击更新」即生效，
   **绝不要求普通用户重装 APK**。只有新增原生插件才需重打 APK。

---

## 1. 架构总览

```
┌──────────────────── 基座（原生壳，冻结） ────────────────────┐
│  Capacitor 7 Android 工程（/root/capacitor-htmx-hello/android） │
│  ├─ WebView (Chromium) 加载 www/ 网页                           │
│  ├─ 插件: LocalNotifications(基座原生能力)                      │
│  ├─ 插件: CapacitorUpdater(Capgo 热更新引擎)                   │
│  └─ 签名: debug 自签（内置），可装可测                          │
└─────────────────────────────────────────────────────────────┘
        ▲ 热更新下载 latest.zip        ▲ 拉取 /update(version)
        │                               │
┌───────┴──────── 服务器 xg.vlai.tech ───────────────────────┐
│  nginx (/var/www/apk)                                       │
│  ├─ /120-vehicle-terminal.apk   ← 基座安装包（仅大版本变时换）│
│  ├─ /update  → update.json {"version","url"}                │
│  └─ /app/latest.zip         ← Web 模块热更包（日常只动这个）  │
└─────────────────────────────────────────────────────────────┘
        ▲ 上传 www/                                           
┌───────┴──────── 本地（你/AI 写代码处） ────────────────────┐
│  capacitor-htmx-hello/www/  ← 唯一的日常编辑目录             │
│  ├─ index.html  (htmx 模块入口 + 更新/通知逻辑)              │
│  ├─ sw.js       (Service Worker，动态片段/拦截)              │
│  ├─ frag/*.html (静态片段)                                  │
│  ├─ htmx.min.js (本地库)                                    │
│  └─ manifest.webmanifest                                    │
└─────────────────────────────────────────────────────────────┘
```

**一句话**：日常你只碰 `www/` 里的网页；`android/` 原生工程由 `cap sync` 自动生成同步，别手改。

---

## 2. 本地开发 htmx 模块（写 + 测）

### 2.1 编辑位置
只改 `capacitor-htmx-hello/www/` 下的文件。最常改的是 `index.html`。

### 2.2 htmx 两种片段写法（范式已验证）
- **静态片段**（文件打包进 APK）：
  ```html
  <button hx-get="/frag/hello.html" hx-target="#out" hx-swap="innerHTML">加载</button>
  <div id="out"></div>
  ```
- **动态片段**（Service Worker 现生成，无真实服务器）：
  ```html
  <button hx-get="/api/frag/hello?name=无知的人" hx-target="#out">加载</button>
  ```
  由 `www/sw.js` 拦截 `/api/*` 请求并拼装 HTML 返回。

### 2.3 URL 铁律（违反即死循环，见 §5）
- **同域资源**（打包进 app 的片段、sw.js、htmx.min.js、manifest）→ 可用相对路径 `/xxx`，
  它们和 WebView 同源（`https://localhost`），加载正常。
- **跨域资源**（你的热更新服务器 `xg.vlai.tech`）→ **必须绝对 URL** `https://xg.vlai.tech/...`。
  否则 WebView 会把 `/update` 当成 `https://localhost/update` → 返回 HTML 404 → JSON 解析报错。

### 2.4 本地自测（零构建）
```bash
cd capacitor-htmx-hello/www
python3 -m http.server 8080
# 浏览器开 http://localhost:8080
# 点三个按钮：静态片段 / 动态片段(SW需localhost) / 原生通知(浏览器会提示"需在App内")
```
> 注意：Service Worker 和 Capgo 逻辑需 `localhost` 或 `https`，**不能用 `file://` 直接打开**。
> 原生通知、热更新按钮在纯浏览器里会提示"需在 App 内运行"——这是正常的（它们在基座原生 bridge 里）。

### 2.5 本地自测通过标准
三个按钮无 JS 报错；静态/动态片段正常渲染；控制台无红色错误。

---

## 3. 上传 + 打包 + 发布（服务器侧，AI 驱动）

### 3.1 连接服务器
```bash
ssh -p 2331 root@xg.vlai.tech     # 已配证书免密
```
工程在服务器路径：`/root/capacitor-htmx-hello/`；脚本在 `/root/finish.sh`、`/root/make_bundle.sh`。

### 3.2 只改了网页（最常见，90% 场景）→ 只出热更包
```bash
# 1) 把本地改好的 www 上传（示例传 index.html，可换成整个目录）
scp -P 2331 www/index.html root@xg.vlai.tech:/root/capacitor-htmx-hello/www/

# 2) 服务器生成热更包（版本号递增，如 1.0.6）
ssh -p 2331 root@xg.vlai.tech "bash /root/make_bundle.sh 1.0.6"
```
完成。人类 App 内点「检查更新」即可拉到 1.0.6。**无需重打 APK。**

### 3.3 动了原生（装了新插件）→ 重打 APK + 同版热更包
```bash
# 上传改动后，重跑 finish.sh（参数=版本号，建议与热更对齐）
ssh -p 2331 root@xg.vlai.tech "cd /root/capacitor-htmx-hello && bash /root/finish.sh 1.0.6"
```
`finish.sh` 内部顺序（已固化，勿改）：
1. `npx cap sync android`  ← **必须有**，把 www 同步进安卓资产，否则 APK 用旧网页
2. `./gradlew assembleDebug`  ← 出 `app-debug.apk`（注意：是 apk 不是 aab）
3. 拷贝 APK → `/var/www/apk/120-vehicle-terminal.apk`
4. 打包 `www` → `/var/www/apk/app/latest.zip` + 写 `update.json`
5. 写 nginx 站点（含 CORS + `/update` 路由）→ `nginx -t` → 重启 → `certbot` 续 HTTPS

### 3.4 版本号约定
- APK builtin 与热更包版本号保持一致（如都 1.0.6），方便人类核对。
- 热更包版本必须 **大于** 当前已发布版本，Capgo 才认。

---

## 4. 客户端验证（人类做，极简）

**日常热更新（不重装）：**
1. 打开 App → ④「检查更新」→ 应显示 `当前: X / 最新: 1.0.6`
2. 点绿色「点击更新」→ 自动下载→reload
3. 再点检查更新 → `已是最新 ✓`（若 make_bundle 注入了水印，页面顶部会出现版本标记）

**必须重装 APK 的情形（罕见）：**
- 基座内置网页本身有 bug（修不了自己）→ 卸载 App 重装最新 APK。
- 覆盖安装后若残留坏 bundle 报错 → 进 App 点「重置到内置版」按钮自救，
  或 `设置→应用→清除数据` 后重开。

下载地址（恒定不变）：**https://xg.vlai.tech/120-vehicle-terminal.apk**

---

## 5. 已知天坑（血泪，已全踩过）

| 坑 | 现象 | 解法 |
|---|---|---|
| **相对 URL 死循环** | 检查更新报 `Unexpected token '<'...` | 所有指向服务器的 URL 用绝对 `https://xg.vlai.tech/...`，见 §2.3 |
| **漏 `cap sync`** | APK 里还是旧网页，改了 www 无效 | `finish.sh` 已内置 `npx cap sync android`，重打必跑 |
| **Capacitor 7 要 JDK 21** | Gradle 报 `invalid source release: 21` | 服务器 `JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64` |
| **Capacitor 7 要 Node 20+** | 服务器 Node 18 跑不动 | 服务器已升 Node 20 |
| **服务器内存不足** | Gradle 守护被 OOM 杀，日志断在 "Starting a Gradle Daemon" | 已建 2GB swap + `gradle.properties` 限堆 `-Xmx512m` |
| **`cap build` 出 aab 不是 apk** | 手机装不了 | 用 `./gradlew assembleDebug` 出 `app-debug.apk` |
| **官方插件版本错配** | `@capacitor/xxx@8` 要 core≥8，与 7 冲突 | 装插件时显式 `npm i @capacitor/xxx@^7` |
| **`pkill -f "go.sh"` 自杀** | 模式串匹配自身命令行 → exit 255 | 按 PID 过滤排除 `$$` 再 kill |

---

## 6. 服务器环境速查

- **公网 IP**：45.197.150.244（= `xg.vlai.tech` 解析地址，Let's Encrypt 可签）
- **系统**：Ubuntu 24.04，arch x86_64
- **工具链**：JDK 21（`/usr/lib/jvm/java-21-openjdk-amd64`）、Node 20、npm、unzip
- **Android SDK**：`/opt/android-sdk`（cmdline-tools/latest + platform-tools + platforms;android-35 + build-tools;35.0.0）
- **swap**：2GB `/swapfile`（fstab 已挂载）
- **nginx**：站点 `/etc/nginx/sites-available/apk`，根 `/var/www/apk`，certbot 证书自动续期
- **证书邮箱占位**：`admin@vlai.tech`（Let's Encrypt 不校验，仅到期提醒）

---

## 7. 接新基座原生能力（插件，需重打 APK）

示例（以 LocalNotifications 已接为模板）：
```bash
# 1) 装与 Capacitor 7 对齐的插件版本
ssh -p 2331 root@xg.vlai.tech "cd /root/capacitor-htmx-hello && npm i @capacitor/相机@^7"

# 2) 在 www/index.html 里用 window.Capacitor.Plugins.Xxx 调用（同 §2.2 ③ 写法）

# 3) 重打 APK（finish.sh 会 cap sync + 构建 + 发布，版本号递增）
ssh -p 2331 root@xg.vlai.tech "cd /root/capacitor-htmx-hello && bash /root/finish.sh 1.0.7"
```
> 插件列表参考：Camera / Geolocation / Filesystem / Device / PushNotifications(需 GMS，国内不通)
> / LocalNotifications / 社区：SQLite、Biometric、Bluetooth LE、NFC 等。

---

## 8. 命令速查表

```bash
# 本地预览
cd www && python3 -m http.server 8080        # http://localhost:8080

# 上传改动
scp -P 2331 www/index.html root@xg.vlai.tech:/root/capacitor-htmx-hello/www/

# 仅热更（日常）
ssh -p 2331 root@xg.vlai.tech "bash /root/make_bundle.sh 1.0.N"

# 重打 APK（动了原生）
ssh -p 2331 root@xg.vlai.tech "cd /root/capacitor-htmx-hello && bash /root/finish.sh 1.0.N"

# 验证
curl -s https://xg.vlai.tech/update            # 应返回 {"version":"1.0.N","url":"..."}
curl -sI https://xg.vlai.tech/120-vehicle-terminal.apk | grep -i content-length
```

---
*固化日期：2026-08-31 · 当前已验证版本：APK builtin 1.0.5，热更链路 1.0.5 实测通过。*
