docs: 更新本地环境与验证流程 (#1)
@@ -1,115 +1,140 @@
|
||||
# 本地开发与验证
|
||||
|
||||
本页覆盖两类工作:**文档与流程**(现在就能跑)和 **Go 服务**(MVP-0 实现工单落地后可跑)。标注“MVP-0 落地后”的步骤在代码存在前会失败,这是预期的。
|
||||
本页区分“现在可执行的文档流程”和“产品代码落地后可执行的 Go/前端/数据库流程”。代码不存在或本机版本不满足时必须如实记录,不把预期当作通过。
|
||||
|
||||
## 环境要求
|
||||
|
||||
| 项 | 要求 | 检查命令 |
|
||||
| 项 | 目标要求 | 检查命令 |
|
||||
|---|---|---|
|
||||
| Git | 任意近期版本 | `git --version` |
|
||||
| Python 3 | 仅标准库,供 Harness 工具使用 | `python --version` |
|
||||
| Go | 1.22 或更高 | `go version` |
|
||||
| MySQL | 8.0(本地或容器),需支持 `SKIP LOCKED` | `mysql --version` |
|
||||
| golang-migrate | 命令行工具 | `migrate -version` |
|
||||
| Tailwind CLI | standalone 可执行文件,无需 npm | `tailwindcss --help` |
|
||||
| Git | 近期版本 | `git --version` |
|
||||
| Python | Python 3 标准库 | `python --version` |
|
||||
| Go | **1.26.5** | `go version` |
|
||||
| MySQL | 8.0,支持 SKIP LOCKED | `mysql --version` |
|
||||
| golang-migrate | 可执行文件 | `migrate -version` |
|
||||
| Node | >=22,仅 admin-ui | `node --version` |
|
||||
| pnpm | 9.15.1,由 packageManager/Corepack 固定 | `pnpm --version` |
|
||||
| Tailwind | standalone,仅 portal 样式 | `tailwindcss --help` |
|
||||
|
||||
不需要 Node.js、Redis 或消息队列。用到的环境变量:
|
||||
2026-08-20 盘点:本机 Go 1.23.0、MySQL 5.7.38、未安装 migrate,不能用于产品构建或迁移验收;Node 22.22.1 可用,但当前全局 pnpm 11.21.0,应按 admin-ui 的 `packageManager` 使用 pnpm 9.15.1。升级环境必须单独完成,不伪造验证结果。
|
||||
|
||||
| 变量 | 用途 | 缺失后果 |
|
||||
|---|---|---|
|
||||
| `CHORUS_DSN` | MySQL 连接串 | 服务无法启动 |
|
||||
| `CHORUS_MASTER_KEY` | provider api_key 的 AES-GCM 主密钥 | 无法解密上游密钥,生成全部失败 |
|
||||
| `GITEA_TOKEN` | Wiki 同步与工单操作 | 只影响文档同步,不影响服务 |
|
||||
固定来源:
|
||||
|
||||
凭据只通过环境变量提供,不写入仓库。
|
||||
- `D:\github\goadmin\go-admin` @ `f06540883b41d03782bb6b2c4150f298f328c6b6`
|
||||
- `D:\github\goadmin\go-admin-ui` @ `67d393d713877572fab0b897296a4c1d525fc81d`
|
||||
- `D:\github\goadmin\go-admin-doc` @ `424855aacf6905f3fde860c3331385cb25529a0d`
|
||||
|
||||
只从这些固定提交审查/导入,不直接在其工作区开发 chorus,也不让 chorus 构建依赖绝对路径。
|
||||
|
||||
主要环境变量:
|
||||
|
||||
| 变量 | 用途 |
|
||||
|---|---|
|
||||
| `CHORUS_DSN` | MySQL 连接 |
|
||||
| `CHORUS_MASTER_KEY` / 对应 key ring 配置 | Provider Key AES-GCM 解密与轮换 |
|
||||
| `CHORUS_SESSION_KEY` | portal 会话,必须与主密钥分离 |
|
||||
| `CHORUS_STORAGE_ROOT` | 受保护生成物目录 |
|
||||
| `CHORUS_ENV` | `development/test/production`,生产强制安全开关 |
|
||||
| `GITEA_TOKEN` | Wiki/工单操作,不影响产品服务 |
|
||||
|
||||
## 第一次运行
|
||||
|
||||
### 1. 检查工作区与文档结构
|
||||
### 1. 文档与工作区
|
||||
|
||||
```powershell
|
||||
git status --short --branch
|
||||
python dev_scripts/harness.py check --strict
|
||||
python -m unittest discover -s tests -v
|
||||
$env:GITEA_URL = "https://git.ilapage.cn"
|
||||
python dev_scripts/harness.py sync --check
|
||||
```
|
||||
|
||||
预期:分支干净、输出“DevHarness 检查通过”、所有测试通过。
|
||||
### 2. 准备隔离数据库(产品代码落地后)
|
||||
|
||||
### 2. 准备数据库(MVP-0 落地后)
|
||||
创建两个无生产数据的库:一个跑应用迁移测试,一个用于 go-admin 结构研究/代码生成。两者不得指向共享或生产实例。
|
||||
|
||||
```powershell
|
||||
mysql -u root -p -e "CREATE DATABASE chorus DEFAULT CHARSET utf8mb4;"
|
||||
$env:CHORUS_DSN = "user:pass@tcp(127.0.0.1:3306)/chorus?parseTime=true&charset=utf8mb4"
|
||||
migrate -path migrations -database "mysql://$env:CHORUS_DSN" up
|
||||
mysql -u root -p -e "CREATE DATABASE chorus_test DEFAULT CHARSET utf8mb4;"
|
||||
mysql -u root -p -e "CREATE DATABASE chorus_codegen DEFAULT CHARSET utf8mb4;"
|
||||
$env:CHORUS_DSN = "user:pass@tcp(127.0.0.1:3306)/chorus_test?parseTime=true&charset=utf8mb4"
|
||||
migrate -path migrations -database "<golang-migrate MySQL URL>" up
|
||||
migrate -path migrations -database "<golang-migrate MySQL URL>" down
|
||||
migrate -path migrations -database "<golang-migrate MySQL URL>" up
|
||||
```
|
||||
|
||||
预期:迁移版本前进,`generations` 等表已创建。
|
||||
连接串格式必须按 golang-migrate 的 MySQL driver 验证,不把 GORM DSN 直接拼成未经验证的 URL。每个迁移先 up、down、再 up;从空库重放全部迁移才算通过。
|
||||
|
||||
### 3. 配置一个上游(MVP-0 落地后)
|
||||
### 3. go-admin schema-first 生成(MVP-1)
|
||||
|
||||
MVP-0 阶段管理端尚未接入,用一次性命令写入一个 provider 与 provider_model:
|
||||
1. 先在 `chorus_codegen` 执行同一套版本化 SQL。
|
||||
2. 启动仅限本机的 admin/admin-ui 开发实例。
|
||||
3. 从数据库表列表导入业务表元数据,配置并预览生成结果。
|
||||
4. 生成 Go/Vue 文件后检查输出路径、字段类型、敏感字段、权限和重复代码。
|
||||
5. 不直接采用“生成迁移脚本”或 `/gen/todb` 的副作用;把菜单/API 配置整理成带 down 的 SQL。
|
||||
6. 清空隔离库,从 migrations 重放并重新生成/构建。
|
||||
7. 生产构建验证 dev-tools 路由不存在;仅隐藏菜单不算关闭。
|
||||
|
||||
```powershell
|
||||
$env:CHORUS_MASTER_KEY = "<32 字节 base64 主密钥>"
|
||||
go run ./cmd/seedprovider --name dev --base-url https://<上游> --api-type chat --model <模型名>
|
||||
```
|
||||
go-admin AutoMigrate 不进入以上标准流程。如确需对照固定提交初始化结构,人工在额外可丢弃库运行一次,导出结构差异后销毁;禁止连接共享/生产库,也禁止把该命令放入应用启动、容器入口或部署脚本。
|
||||
|
||||
预期:命令输出新建的 provider_model id;数据库中 `api_key_enc` 是密文而非明文。
|
||||
### 4. 配置 mock 上游与种子用户(MVP-0)
|
||||
|
||||
### 4. 启动服务并走通一次生成(MVP-0 落地后)
|
||||
MVP-0 不开放注册。使用可重复、不会在日志输出密钥的种子命令建立测试用户、默认 prompt template、Provider 和 ProviderModel。默认先连接 mock HTTP 上游,覆盖文本、图片、429、5xx、超时、连接错误、400、401 和内容策略拒绝。
|
||||
|
||||
真实 Provider 的连通性检查只能由操作者明确触发一次低成本请求,并核对审计与冷却;不能作为自动测试或反复调试方式。
|
||||
|
||||
### 5. 启动 portal(MVP-0)
|
||||
|
||||
```powershell
|
||||
go run ./portal
|
||||
```
|
||||
|
||||
预期日志包含监听端口与“worker started”。然后在浏览器打开 `http://127.0.0.1:8080`:
|
||||
浏览器验证:
|
||||
|
||||
1. 注册或用种子用户登录,进入双栏首页;
|
||||
2. 切到「文生文」,输入一句提示词,点生成;
|
||||
3. 左栏立即出现 loading 卡片,右栏可见状态;
|
||||
4. 数秒后卡片原地替换为结果,轮询停止(响应中不再有 `hx-trigger`);
|
||||
5. 切到「图生图」,上传 1~2 张图,标记主体图与参考图,再生成一次;
|
||||
6. 数据库中该条 `generations` 的 `status=succeeded`,`rendered_prompt` 非空,`attempts` 有一条记录,`generation_outputs.thumb_path` 有值。
|
||||
|
||||
**第 6 步是 MVP-0 的验收口径**:页面看到结果只是表象,落库字段齐全才算流程真正跑通。
|
||||
1. 用种子用户登录,不应出现公开注册链接;
|
||||
2. 桌面双栏、375px 移动单列均可完成文本和图片提交;
|
||||
3. 第一张图自动 primary,其余 reference,MVP-0 没有角色编辑/拖拽;
|
||||
4. 提交后立即显示 queued/running,终态停止轮询;
|
||||
5. 文本、图片、失败、网络轮询错误和认证过期都有明确界面;
|
||||
6. 数据库中 `rendered_prompt`、`attempts`、latency 或失败 error 字段齐全;
|
||||
7. 输出通过鉴权访问,不能猜 URL 读取其他用户文件。
|
||||
|
||||
## 常用调试方式
|
||||
|
||||
| 症状 | 先看哪里 |
|
||||
| 症状 | 先看 |
|
||||
|---|---|
|
||||
| 卡片一直转圈 | `generations.status`。仍是 `pending` 说明 worker 没取到任务;`running` 且 `lease_until` 已过期说明 worker 崩了或卡在上游 |
|
||||
| 结果不对但没报错 | `generations.rendered_prompt`——多数“模型不听话”其实是提示词合成错了 |
|
||||
| 生成失败 | `generations.attempts` 与 `error_message`,能看出是哪一家、什么错误、耗时多少 |
|
||||
| 上游连不上 | 先确认不是 SSRF 拦截命中(日志中的拦截记录),再查 `base_url` 与密钥解密 |
|
||||
| 页面样式丢失 | Tailwind CLI 是否在 watch,`portal/web/static/` 产物是否存在 |
|
||||
| pending 不动 | worker 是否启动、取任务索引和数据库版本 |
|
||||
| running 租约过期 | lease_owner/token/until、上游超时、陈旧 worker CAS |
|
||||
| 成功但内容不对 | rendered_prompt 与 prompt template 版本 |
|
||||
| 400/401 尝试多家 | retryable 实现错误 |
|
||||
| 文件存在但页面 403/404 | 用户归属、原子落位、缩略图记录 |
|
||||
| 上游连不上 | SSRF 日志、DNS/IPv6、redirect、proxy 和 base_url |
|
||||
| 管理端生成异常 | 是否先迁移再导表,是否误把菜单脚本当业务 DDL |
|
||||
| 样式丢失 | portal Tailwind 产物或 admin-ui pnpm/Vue CLI 构建 |
|
||||
|
||||
调试上游时用 mock HTTP 服务代替真实上游:`internal/core/provider` 的测试已提供可复用的 mock,能构造 429、超时、400 和内容拒绝四种响应。不要用真实额度反复试错。
|
||||
不要在日志、SQL、工单或 Wiki 中贴 API Key、Cookie、真实用户输入和生产文件。
|
||||
|
||||
单条 SQL 快速定位:
|
||||
## 测试策略
|
||||
|
||||
```sql
|
||||
SELECT id, kind, status, provider_model_id, attempt_count, error_code, latency_ms
|
||||
FROM generations ORDER BY id DESC LIMIT 10;
|
||||
```
|
||||
- 迁移:空 MySQL 8 隔离库逐个/全量 up-down-up,验证索引、外键、唯一约束和种子幂等。
|
||||
- 队列:并发认领、租约过期重新认领、旧 token 最终写 0 行、优雅退出、attempt 原子性。
|
||||
- Provider:全部 retryable 类别使用 mock,不消耗真实额度。
|
||||
- SSRF:IPv4/IPv6 私网、DNS rebinding、redirect 链、环境代理、结果 URL。
|
||||
- 安全:密码/session/CSRF、登录节流、跨用户任务与文件、错误脱敏、密钥轮换。
|
||||
- 浏览器:HTMX 动态状态、终态停止、认证过期、网络错误;375/768/1024,无主区域横向滚动,键盘和 reduced-motion。
|
||||
- 供应链:Go/Node 依赖锁定、漏洞和许可证检查按实现工单确定命令。
|
||||
|
||||
## 完成修改前
|
||||
|
||||
按顺序执行,全部通过才算完成:
|
||||
|
||||
```powershell
|
||||
git status --short --branch
|
||||
go build ./...
|
||||
go vet ./...
|
||||
go test ./...
|
||||
pnpm --dir admin-ui install --frozen-lockfile
|
||||
pnpm --dir admin-ui build:prod
|
||||
python dev_scripts/harness.py check --strict
|
||||
python -m unittest discover -s tests -v
|
||||
python dev_scripts/harness.py sync --check
|
||||
git diff --check
|
||||
```
|
||||
|
||||
另外确认:
|
||||
|
||||
- 改了表结构 → 有对应 `migrations/` 文件,且 up 与 down 各跑过一次;
|
||||
- 改了 `retryable`、SSRF、加解密 → 有针对性单元测试;
|
||||
- 改了页面结构、流程、状态、权限或异常处理 → 有 `prototypes/<工单号>/<版本>/index.html` 审核快照并已确认;
|
||||
- 改了入口、命令、业务规则或排错方式 → 已评估对 `docs/` 的影响;
|
||||
- 未执行或无法覆盖的验证 → 已写进工单,不得默认“应该没问题”。
|
||||
只运行受当前范围影响且实际存在的产品命令;不存在或因工具版本不能执行的项写入工单。涉及迁移、安全、队列、权限或 UI 时,还必须执行上面的专项验证并记录结果。
|
||||
|
||||
Reference in New Issue
Block a user