Files
chorus/docs/04-local-development-and-verification.md
T

12 KiB
Raw Blame History

generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件) wiki_page: Local-Development-and-Verification wiki_url: https://git.ilapage.cn/OPC/chorus/wiki/Local-Development-and-Verification.- wiki_revision: 075e82a07b58c105c46d7fbcfb22d8ed6d8f97f8 synchronized_at: 2026-08-20T16:45:23Z

本地开发与验证

本页区分“现在可执行的文档流程”和“产品代码落地后可执行的 Go/前端/数据库流程”。代码不存在或本机版本不满足时必须如实记录,不把预期当作通过。

环境要求

项 目标要求 检查命令
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

2026-08-20 已完成 MVP-0 环境基线:便携 Go 1.26.5、golang-migrate v4.19.1 和隔离 MySQL 8.4.8 已验证。Chorus 专用实例监听 127.0.0.1:3308,使用独立数据目录和测试账号;既有 3307 实例与 MySQL 5.7 不受影响。Node 22.22.1 可用;admin-ui 后续仍必须按 packageManager 使用 pnpm 9.15.1,不能直接采用全局 pnpm 11。

固定来源:

  • D:\github\goadmin\go-admin @ f06540883b41d03782bb6b2c4150f298f328c6b6
  • D:\github\goadmin\go-admin-ui @ 67d393d713877572fab0b897296a4c1d525fc81d
  • D:\github\goadmin\go-admin-doc @ 424855aacf6905f3fde860c3331385cb25529a0d

只从这些固定提交审查/导入,不直接在其工作区开发 chorus,也不让 chorus 构建依赖绝对路径。

主要环境变量:

变量 用途
CHORUS_DSN Go 应用和种子命令使用的 GORM/MySQL DSN
CHORUS_MIGRATE_URL golang-migrate 专用 MySQL URL
CHORUS_SEED_USER_EMAIL / CHORUS_SEED_USER_PASSWORD 构造种子用户;仅通过环境注入
CHORUS_SEED_PROVIDER_BASE_URL mock Provider 基础 URL;不得指向生产
CHORUS_MASTER_KEY / 对应 key ring 配置 Provider Key AES-GCM 解密与轮换
CHORUS_SESSION_KEY portal 会话,必须与主密钥分离
CHORUS_STORAGE_ROOT 受保护生成物目录
CHORUS_ENV development/test/production,生产强制安全开关
CHORUS_SESSION_TTL_MINUTES 会话有效分钟数;生产必填
CHORUS_LOGIN_ATTEMPTS / CHORUS_LOGIN_WINDOW_SECONDS 单远端地址登录窗口限制;生产必填
CHORUS_MAX_PROMPT_BYTES prompt UTF-8 字节上限;生产必填
CHORUS_MAX_IMAGES 单任务图片数量上限;生产必填
CHORUS_MAX_IMAGE_BYTES / CHORUS_MAX_UPLOAD_BYTES 单图/整次 multipart 字节上限;生产必填
CHORUS_MAX_IMAGE_PIXELS 单图解码像素上限;生产必填
CHORUS_HISTORY_LIMIT 单次历史查询上限;生产必填
GITEA_TOKEN Wiki/工单操作,不影响产品服务

第一次运行

1. 文档与工作区

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

2. 进入固定工具环境并连接隔离数据库

工具和凭据都位于仓库外。以下占位路径由维护者替换为自己的本机工具目录;环境文件不得提交,也不得把展开后的 DSN 输出到终端、日志、工单或 Wiki。

$tools = "<本机工具目录>"
$env:PATH = "$tools\go1.26.5\bin;$tools\migrate-v4.19.1;$env:PATH"
. "$tools\chorus-test.env.ps1"

go version
migrate -version
mysql --version

当前已验证变量包括 CHORUS_MYSQL_HOST、CHORUS_MYSQL_PORT、CHORUS_MYSQL_DATABASE、CHORUS_MYSQL_USER、CHORUS_MYSQL_PASSWORD、CHORUS_DB_DSN 和 CHORUS_MIGRATE_URL。应用使用 GORM DSN,迁移工具使用单独验证过的 MySQL URL,不在两种格式之间临时拼接。

专用实例的可复制启动和停止方式如下;my.ini 必须绑定 127.0.0.1,并指定独立端口、数据目录、日志和 PID 文件。

$mysqlHome = "<MySQL 8 安装目录>"
$instance = "<Chorus MySQL 实例目录>"
Start-Process -FilePath "$mysqlHome\bin\mysqld.exe" `
  -ArgumentList "--defaults-file=$instance\my.ini", "--console" `
  -WindowStyle Hidden

$env:MYSQL_PWD = $env:CHORUS_MYSQL_ROOT_PASSWORD
& "$mysqlHome\bin\mysqladmin.exe" --protocol=tcp `
  --host=127.0.0.1 --port=3308 --user=root shutdown
$env:MYSQL_PWD = $null

能力探测使用构造查询,不创建业务表:

$env:MYSQL_PWD = $env:CHORUS_MYSQL_PASSWORD
mysql --protocol=tcp --host=$env:CHORUS_MYSQL_HOST `
  --port=$env:CHORUS_MYSQL_PORT --user=$env:CHORUS_MYSQL_USER `
  --database=$env:CHORUS_MYSQL_DATABASE `
  --execute="START TRANSACTION; SELECT id FROM (SELECT 1 AS id) AS capability_probe FOR UPDATE SKIP LOCKED; ROLLBACK;"
$env:MYSQL_PWD = $null

#6 已提供首个迁移和幂等种子命令。只在明确的隔离库执行:

migrate -path migrations -database $env:CHORUS_MIGRATE_URL up

$env:CHORUS_SEED_USER_EMAIL = "mvp0-test@chorus.invalid"
$env:CHORUS_SEED_USER_PASSWORD = "<本次构造密码>"
$env:CHORUS_SEED_PROVIDER_BASE_URL = "<mock 上游 URL>"
go run ./cmd/chorus-seed
go run ./cmd/chorus-seed

migrate -path migrations -database $env:CHORUS_MIGRATE_URL down -all
migrate -path migrations -database $env:CHORUS_MIGRATE_URL up

两次种子执行后应仍是一个构造用户、一个 mock Provider、两个 ProviderModel 和两个 Prompt。down -all 会删除隔离库业务数据,只能用于明确可丢弃的测试库。chorus_codegen 只在 MVP-1 的 go-admin 结构研究/代码生成工单中另行创建,不提前扩大当前账号权限。

3. go-admin schema-first 生成(MVP-1)

  1. 先在 chorus_codegen 执行同一套版本化 SQL。
  2. 启动仅限本机的 admin/admin-ui 开发实例。
  3. 从数据库表列表导入业务表元数据,配置并预览生成结果。
  4. 生成 Go/Vue 文件后检查输出路径、字段类型、敏感字段、权限和重复代码。
  5. 不直接采用“生成迁移脚本”或 /gen/todb 的副作用;把菜单/API 配置整理成带 down 的 SQL。
  6. 清空隔离库,从 migrations 重放并重新生成/构建。
  7. 生产构建验证 dev-tools 路由不存在;仅隐藏菜单不算关闭。

go-admin AutoMigrate 不进入以上标准流程。如确需对照固定提交初始化结构,人工在额外可丢弃库运行一次,导出结构差异后销毁;禁止连接共享/生产库,也禁止把该命令放入应用启动、容器入口或部署脚本。

4. 配置 mock 上游与种子用户(MVP-0)

MVP-0 不开放注册。使用可重复、不会在日志输出密钥的种子命令建立测试用户、默认 prompt template、Provider 和 ProviderModel。默认先连接 mock HTTP 上游,覆盖文本、图片、429、5xx、超时、连接错误、400、401 和内容策略拒绝。

真实 Provider 的连通性检查只能由操作者明确触发一次低成本请求,并核对审计与冷却;不能作为自动测试或反复调试方式。 本地 mock 协议服务可单独启动,用于 curl 或协议调试:

$env:CHORUS_MOCK_ADDR = "127.0.0.1:18080"
go run ./cmd/chorus-mock-provider

生产安全 Client 始终拒绝回环/私网 Provider URL。自动化端到端测试使用构造公共域名解析和受控 DialContext 把请求送到进程内 mock,不应为了让 portal 直连本机 mock 而放宽 SSRF 规则。

种子密码从 #11 起保存为 bcrypt:v1:<hash>。已有无版本构造哈希不会被登录兼容;使用同一构造邮箱和本次选择的密码重新运行 go run ./cmd/chorus-seed,会更新密码哈希而不新增用户。开发/测试未提供 session key 时进程随机生成临时 key,重启后会话失效;生产必须显式提供至少 32 字节且与 Provider 主密钥分离的 key。

5. 启动 portal(MVP-0)

go run ./portal

浏览器验证:

  1. 用种子用户登录,不应出现公开注册链接;
  2. 桌面双栏、375px 移动单列均可完成文本和图片提交;
  3. 第一张图自动 primary,其余 reference,MVP-0 没有角色编辑/拖拽;
  4. 提交后立即显示 queued/running,终态停止轮询;
  5. 文本、图片、失败、网络轮询错误和认证过期都有明确界面;
  6. 数据库中 rendered_prompt、attempts、latency 或失败 error 字段齐全;
  7. 输出通过鉴权访问,不能猜 URL 读取其他用户文件。

常用调试方式

症状 先看
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 构建

不要在日志、SQL、工单或 Wiki 中贴 API Key、Cookie、真实用户输入和生产文件。

测试策略

  • 迁移:空 MySQL 8 隔离库逐个/全量 up-down-up,验证索引、外键、唯一约束和种子幂等。
  • 队列:并发认领、租约过期重新认领、旧 token 最终写 0 行、优雅退出、attempt 原子性。从 #9 起该项必须连接迁移后的隔离 MySQL 8,mock SQL 不能替代。
$env:CHORUS_TEST_DSN = $env:CHORUS_DSN
go test -v -count=1 ./internal/core/queue/...
go test -race -count=1 ./internal/core/queue/...
$env:CHORUS_TEST_DSN = $null
Provider/worker 的 mock 协议、真实 MySQL 8 attempt/output 与优雅退出验证:

```powershell
$env:CHORUS_TEST_DSN = $env:CHORUS_DSN
go test -v -count=1 ./internal/core/provider/... ./internal/platform/http/... ./internal/platform/mockprovider/... ./portal/worker/...
go test -race -count=1 ./...
$env:CHORUS_TEST_DSN = $null

- Provider:全部 retryable 类别使用 mock,不消耗真实额度。
- Portal:真实 MySQL 8 覆盖登录/退出、session/CSRF 轮换、用户作用域幂等、pending 提交、上传边界、任务与文件跨用户授权、终态和 HTMX 401;测试结束 generation/input/output 和构造用户必须为 0。

```powershell
$env:CHORUS_TEST_DSN = $env:CHORUS_DSN
go test -v -count=1 ./portal/handler/... ./portal/service/... ./portal/session/... ./portal/auth/...
$env:CHORUS_TEST_DSN = $null
  • SSRF:IPv4/IPv6 私网、DNS rebinding、redirect 链、环境代理、结果 URL。
  • 安全:密码/session/CSRF、登录节流、跨用户任务与文件、错误脱敏、密钥轮换。
  • 浏览器:HTMX 动态状态、终态停止、认证过期、网络错误;375/768/1024,无主区域横向滚动,键盘和 reduced-motion。
  • 供应链:Go/Node 依赖锁定、漏洞和许可证检查按实现工单确定命令。

完成修改前

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

只运行受当前范围影响且实际存在的产品命令;不存在或因工具版本不能执行的项写入工单。涉及迁移、安全、队列、权限或 UI 时,还必须执行上面的专项验证并记录结果。