docs: CI/CD 方案 HTML 阅读版 + 登记 docs/index.html(#30)

深色家族风 HTML(cicd-design.html),真相源仍是 superpowers/specs 的 .md。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-07-05 22:06:25 +08:00
parent f30097172a
commit fe9a3a6cdb
2 changed files with 175 additions and 0 deletions
+170
View File
@@ -0,0 +1,170 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pangolin CI/CD 全流程 · 设计方案(#30)</title>
<style>
:root{
--bg:#0f1117; --panel:#171a22; --panel2:#1d2129; --fg:#e6e8ee; --fg2:#a8afbd;
--accent:#e0884f; --accent2:#5fb0c9; --ok:#5ec27a; --bad:#e06a6a; --warn:#e0b84f;
--border:#272c36; --mono:"SF Mono",ui-monospace,Menlo,Consolas,monospace;
--sans:-apple-system,"PingFang SC","Helvetica Neue",Arial,sans-serif;
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--fg);font-family:var(--sans);line-height:1.7;font-size:15px}
.wrap{max-width:960px;margin:0 auto;padding:48px 24px 96px}
h1{font-size:30px;line-height:1.3;margin:0 0 8px;letter-spacing:-.01em}
.sub{color:var(--fg2);font-size:15px;margin:0 0 32px}
h2{font-size:21px;margin:44px 0 14px;padding-bottom:8px;border-bottom:1px solid var(--border)}
h3{font-size:16px;margin:26px 0 8px;color:var(--accent2)}
p{margin:10px 0}
code{font-family:var(--mono);font-size:.88em;background:var(--panel2);padding:1px 6px;border-radius:5px;color:#f0d9c4}
pre{background:#0a0c11;border:1px solid var(--border);border-radius:10px;padding:14px 16px;overflow-x:auto;font-family:var(--mono);font-size:13px;line-height:1.55;color:#cdd3df}
.tag{display:inline-block;font-size:12px;font-weight:600;padding:2px 9px;border-radius:999px;vertical-align:middle}
.tag.ok{background:rgba(94,194,122,.16);color:var(--ok)}
.tag.warn{background:rgba(224,184,79,.16);color:var(--warn)}
.tag.bad{background:rgba(224,106,106,.16);color:var(--bad)}
.tag.info{background:rgba(95,176,201,.16);color:var(--accent2)}
.card{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:18px 20px;margin:16px 0}
.card h3{margin-top:0;color:var(--fg)}
table{width:100%;border-collapse:collapse;margin:16px 0;font-size:14px}
th,td{text-align:left;padding:9px 12px;border-bottom:1px solid var(--border);vertical-align:top}
th{color:var(--fg2);font-weight:600;font-size:13px}
td code{font-size:.85em}
ul,ol{padding-left:22px;margin:10px 0}
li{margin:5px 0}
.lead{background:linear-gradient(180deg,rgba(224,136,79,.10),transparent);border:1px solid var(--border);border-radius:12px;padding:18px 20px;margin:0 0 8px}
.small{color:var(--fg2);font-size:13px}
a{color:var(--accent2)}
.back{display:inline-block;margin-bottom:24px;font-size:13px}
b{color:#fff}
</style>
</head>
<body>
<div class="wrap">
<a class="back" href="index.html">← 文档索引</a>
<h1>Pangolin CI/CD 全流程 · 设计方案</h1>
<p class="sub">#30 · 2026-07-05 · <span class="tag warn">设计定稿待审</span> · 范围 A~F(排除 iOS、备份#26、TLS#25)· 真相源 <code>docs/superpowers/specs/2026-07-05-cicd-design.md</code></p>
<div class="lead">
<b>目标:</b>tag 触发的 <b>编译 → 测试 → 发版(Gitea release)→ 部署</b> 全自动。参考 jiu 的
<code>.gitea/workflows</code> + <code>scripts/ci/*.sh</code> 结构,适配 pangolin 的部署目标(pangolin1 /
pangolin.yanmeiai.com)与多端产物。现状:仅 <code>ci.yml</code> 校验无部署,服务端手动部署、官网未部署、下载死链。
</div>
<h2>1. 范围</h2>
<table>
<tr><th>子块</th><th>内容</th></tr>
<tr><td><b>A 基座</b></td><td><code>scripts/ci/*</code>env/provision/test/release/notify/lib-forgejo+ checks 保留</td></tr>
<tr><td><b>B 官网</b></td><td>Astro 构建 → 部署 <code>pangolin.yanmeiai.com</code></td></tr>
<tr><td><b>C 服务端</b></td><td>交叉编译 server/agent/migrate → release → ssh pangolin1(备份→migrate→换二进制→重启→健康检查)</td></tr>
<tr><td><b>D Android</b></td><td>apkarm64release keystore 签名)→ release 资产</td></tr>
<tr><td><b>E macOS</b></td><td>公证 dmgDeveloper ID + notarytool)→ release 资产</td></tr>
<tr><td><b>F Windows</b></td><td>exe/installerInno Setup)→ release 资产</td></tr>
</table>
<p class="small"><b>排除:</b>iOS(G,未来)、SQLite 备份/容灾(#26)、控制面 TLS(#25)。</p>
<h2>2. 已锁定决策</h2>
<table>
<tr><th>维度</th><th>决定</th><th>理由</th></tr>
<tr><td>runner</td><td>nas=官网+服务端(容器化)· mac=Android+macOS · windows=Windows</td><td>nas 常在线且 Astro/Go 轻量(非 Flutter Web);mac/windows 做必须它们的活</td></tr>
<tr><td>触发</td><td>tag <code>site-v*</code> / <code>server-v*</code> / <code>client-v*</code> + <code>manual.yml</code> 手动派发</td><td>同 jiu,发版即部署,可手动重放</td></tr>
<tr><td>macOS 签名</td><td>mac 自动 Developer ID 签名 + notarytool 公证 + staple</td><td>凭据入 secret(见 §6</td></tr>
<tr><td>Android 签名</td><td>正式 release keystore</td><td>app 级专属签名身份</td></tr>
<tr><td>下载链接</td><td>官网 href 指向 Gitea release 稳定资产 URL</td><td>发版即更新,见 §5</td></tr>
<tr><td>镜像</td><td>goproxy.cn / flutter-io.cn</td><td>国内网络</td></tr>
</table>
<h2>3. 架构</h2>
<h3>3.1 共享基座 <code>scripts/ci/</code>(镜像 jiu</h3>
<ul>
<li><code>_env.sh</code> —— 公共环境(镜像源、路径、版本号解析 <code>${tag#prefix-v}</code></li>
<li><code>lib-forgejo.sh</code> —— release 建/查 + 资产上传(用 <code>FORGEJO_TOKEN</code></li>
<li><code>provision-mac.sh</code> —— mac 幂等装 flutter / xcode-select / gomobile / NDK+JDK17</li>
<li><code>test.sh</code><code>notify.sh</code><code>compile-*.sh</code><code>deploy-*.sh</code><code>release-*.sh</code></li>
</ul>
<p class="small">每个 <code>compile-*</code> 封装该端已验证的构建命令(Android 走 <code>build-libbox.sh android</code> +
<code>flutter build apk --split-per-abi</code>macOS 走 Developer ID 签名 + <code>notarytool submit --wait</code> +
<code>stapler</code>)。工作流只调脚本,逻辑在脚本里、便于本地复现。</p>
<h3>3.2 工作流 <code>.gitea/workflows/</code></h3>
<table>
<tr><th>工作流</th><th>触发</th><th>runner</th><th>步骤</th></tr>
<tr><td><code>checks.yml</code>(现 ci.yml</td><td>push 分支</td><td>nas</td><td>保留:shellcheck / openapi / redline / flutter analyze+test / go test</td></tr>
<tr><td><code>deploy-site.yml</code></td><td><code>site-v*</code></td><td>nas</td><td><code>node:20</code> 构建 Astro(注入 SITE_URL)→ <code>deploy-site.sh</code></td></tr>
<tr><td><code>deploy-server.yml</code></td><td><code>server-v*</code></td><td>nas</td><td><code>golang:1.25</code> 交叉编译 → test → release → <code>deploy-server.sh</code></td></tr>
<tr><td><code>build-android.yml</code></td><td><code>client-v*</code></td><td>mac</td><td>provision → <code>compile-android.sh</code>(签名 apk)→ release</td></tr>
<tr><td><code>build-macos.yml</code></td><td><code>client-v*</code></td><td>mac</td><td>provision → <code>compile-macos.sh</code>(签名+公证 dmg)→ release</td></tr>
<tr><td><code>build-windows.yml</code></td><td><code>client-v*</code></td><td>windows</td><td><code>compile-windows.sh</code>exe/installer)→ release</td></tr>
</table>
<h3>3.3 服务端部署(固化 F3/F4 手动那套,带回滚)</h3>
<div class="card">
<ol>
<li>scp <code>pangolin-{server,agent,migrate}</code> 到 pangolin1 <code>/tmp</code></li>
<li><code>systemctl stop pangolin-server</code></li>
<li><code>wal_checkpoint(TRUNCATE)</code><code>cp</code> 备份 <code>pangolin.db.bak-pre-&lt;tag&gt;</code></li>
<li><code>pangolin-migrate up</code>pangolin 用户);<b>失败即恢复备份 + 重启旧 server + 退出非零</b></li>
<li><code>install</code> 新二进制到 <code>/usr/local/bin</code>(旧的备份为 <code>.bak-&lt;tag&gt;</code></li>
<li><code>systemctl start</code> + <code>/healthz</code> 健康检查;agent 随连接自恢复</li>
</ol>
</div>
<h2>4. 官网部署</h2>
<p>Astro <code>npm ci && npm run build</code><code>SITE_URL=https://pangolin.yanmeiai.com</code>)→ <code>dist/</code>
rsync 到服务器 web 根 → nginx/Caddy 静态托管。<b>DNS</b>CF 加记录
<code>pangolin.yanmeiai.com</code> → 服务器(首次部署时做,记 baize)。</p>
<h2>5. 下载链接闭环(30A</h2>
<p><code>web/website/src/config/site.ts</code><code>downloads:{ android, macos, windows }</code>,值为 Gitea release
稳定 latest 资产 URLForgejo 支持 <code>…/releases/latest/download/&lt;asset&gt;</code> 则直用;否则构建期用
<code>FORGEJO_TOKEN</code> 查最新 <code>client-v*</code> 版本烘焙进 href)。<code>Download.astro</code> 各平台按钮读
<code>SITE.downloads.&lt;platform&gt;</code>。客户端发版后官网重部署即刷新(或 build-* 完成触发 deploy-site)。</p>
<h2>6. 密钥与作用域(solo / wangjia</h2>
<table>
<tr><th>Secret</th><th>作用域</th><th>说明</th></tr>
<tr><td><code>FORGEJO_TOKEN</code></td><td>账户级</td><td>建 releasejiu 复用</td></tr>
<tr><td><code>DEVELOPER_ID_P12</code> / <code>P12_PASSWORD</code> / <code>ASC_KEY_P8</code> / <code>ASC_KEY_ID</code> / <code>ASC_ISSUER_ID</code></td><td>账户级</td><td>Apple 账号级签名+公证,所有 app 共用,续期改一处</td></tr>
<tr><td><code>DEPLOY_SSH_KEY</code></td><td>pangolin 仓库级</td><td>授权到 pangolin1,最小权限</td></tr>
<tr><td><code>RELEASE_KEYSTORE</code> / <code>KEYSTORE_PASSWORD</code> / <code>KEY_ALIAS</code> / <code>KEY_PASSWORD</code></td><td>pangolin 仓库级</td><td>Android app 级专属签名,绝不共享</td></tr>
</table>
<p class="small">工作流用 <code>secrets.XXX</code> 引用,账户级/仓库级对写法透明。macOS 另需主 app + PacketTunnel
sysext 两个 <code>.provisionprofile</code>base64 存 secret,签名期落盘嵌入)。</p>
<h2>7. 实现顺序</h2>
<p>范围虽 A~F,按风险/依赖递增落地,每阶段独立可发、独立验收:</p>
<ol>
<li><b>A 基座</b> + <code>checks</code> 迁移(抽 <code>scripts/ci</code> 骨架)</li>
<li><b>B 官网</b>(最简,验证 release/deploy 骨架)</li>
<li><b>C 服务端</b>(固化手动部署)</li>
<li><b>D Android</b>(解锁下载链接;需 keystore 就绪 + gradle 接签名)</li>
<li><b>E macOS</b>(最复杂:证书 + 2 描述文件 + 公证)</li>
<li><b>F Windows</b>windows runner + Inno Setup</li>
</ol>
<h2>8. 验证</h2>
<ul>
<li>每条流水线先 <code>workflow_dispatch</code> 手动跑通、核对产物/部署,再依赖 tag。</li>
<li>服务端:<code>server-v*</code> → migrate 版本 + <code>/healthz</code> + 行数守恒(同 F3 核对)。</li>
<li>官网:<code>site-v*</code> → 站点可访问 + canonical 正确 + redline 扫描。</li>
<li>客户端:release 资产可下载安装(Android 侧载 / macOS <code>spctl</code> / Windows 安装)。</li>
<li>下载链接:官网按钮落到最新 release 资产。</li>
</ul>
<h2>9. 风险与缓解</h2>
<table>
<tr><th>风险</th><th>缓解</th></tr>
<tr><td>nas 内存(3.8G)构建 OOM</td><td>容器化单 job、Astro/Go 轻量;必要时该端移 mac</td></tr>
<tr><td>migrate 在生产出错</td><td>部署前备份 + 失败自动回滚(§3.3),已在 F3/F4 手动验证</td></tr>
<tr><td>Android keystore 丢失</td><td>存 Bitwarden(文件+密码);终身签名身份</td></tr>
<tr><td>macOS 公证凭据泄露</td><td>账户级 secret,不落盘;<code>.p8</code>/<code>.p12</code> 用完即删临时文件</td></tr>
<tr><td>发版后下载链接不刷新</td><td>build-* 成功触发 deploy-site 重烘焙,或用 latest-download 稳定 URL</td></tr>
</table>
<h2>10. 不在本方案</h2>
<p class="small">iOS 流水线(G)、SQLite 备份/容灾(#26)、TLS#25)、上架 Play、Windows 代码签名(先不签)。</p>
</div>
</body>
</html>
+5
View File
@@ -44,6 +44,11 @@
</div>
<h2>设计方案 / Specs</h2>
<a class="doc" href="cicd-design.html">
<div class="t">CI/CD 全流程(tag 触发编译/发版/部署)<span class="tag html">HTML</span></div>
<div class="d">#30。参考 jiu 的 scripts/ci + .gitea/workflowstag 触发(site-v*/server-v*/client-v*)→ 编译 → 测试 → Gitea release → 部署。runner 混合(nas=官网+服务端容器化 / mac=Android+macOS / windows=Windows)。服务端部署固化 F3/F4「备份→migrate→换二进制→重启→健康检查+回滚」;官网部署 pangolin.yanmeiai.com;客户端 apk/dmg/exe 挂 release 喂官网下载链接。密钥作用域:Apple/token 账户级、部署 key/Android keystore 仓库级。范围 A~F(排除 iOS/#26/#25)。</div>
<div class="path">docs/cicd-design.html · 真相源 docs/superpowers/specs/2026-07-05-cicd-design.md</div>
</a>
<a class="doc" href="contact-telegram-channels-design.html">
<div class="t">联系我们 · 渠道二级页(Telegram 频道/群组,DB 配置)<span class="tag html">HTML</span></div>
<div class="d">点 Telegram 进二级页,按 kind 分组(频道/群组/Bot)列多条链接,含 @handle/说明/认证/「打开·加入」动作,全渠道(含邮箱/发卡)统一一张 contact_link 表(靠 url 协议区分 mailto/https/tg)。独立 GET /v1/contact。规则:平台 >1 条链接才进二级,否则点击直达。LINE 同构但先灰置「即将开放」(registry comingSoon 开关,配好即去灰)。不展示成员数、群组=加入。含可点原型。</div>