diff --git a/docs/00-project-profile.md b/docs/00-project-profile.md index 33f0b4c..d213a15 100644 --- a/docs/00-project-profile.md +++ b/docs/00-project-profile.md @@ -2,8 +2,8 @@ generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件) wiki_page: Project-Profile wiki_url: https://git.ilapage.cn/OPC/chorus/wiki/Project-Profile.- -wiki_revision: c911e12b96e71d1da25c0d4346d938a4351cd5da -synchronized_at: 2026-08-21T06:15:04Z +wiki_revision: 811dfc91e824a8ce509fe042455a66c6c1a4f433 +synchronized_at: 2026-08-21T15:02:06Z # 项目档案 @@ -44,12 +44,14 @@ synchronized_at: 2026-08-21T06:15:04Z | `internal/core` 核心域库 | 领域模型、provider 协议抽象、生成编排、队列状态、加密接口 | Go 1.26.5、GORM、标准库 | `go test ./internal/core/...` | 不单独发布 | **不得 import Gin、go-admin、gobreaker 或 imaging** | | `internal/platform` 基础设施适配 | 出站 HTTP/SSRF、熔断、图片处理、存储等接口实现 | 标准库、sony/gobreaker、disintegration/imaging | `go test ./internal/platform/...` | 随服务二进制发布 | 通过接口注入 core,不反向污染领域层 | | `portal` 用户端二进制 | 会话、页面/HTMX 片段、JSON API,MVP 阶段内嵌 worker | Gin、html/template、HTMX、Alpine、Tailwind | `pnpm --dir portal/web build`、`go test ./portal/...`、浏览器 E2E | 单二进制 | 依赖 core 与 platform;提交链路不得调用上游 | -| `admin` 管理端后端 | Provider/Model/路由池/记录/用户与点数管理 | 固定提交的 go-admin(Gin、GORM、Casbin、JWT) | `go test ./admin/...` | 独立二进制 | 依赖 core;不得复制生成逻辑 | +| `admin` 管理端后端 | Provider、模型、Prompt、路由池、生成记录与终端用户只读查询 | 固定提交的 go-admin(Gin、GORM、Casbin、JWT) | `go -C admin test ./...` | 独立二进制 | 嵌套 Go module;依赖 core;不得复制生成逻辑或读写点数 | | `admin-ui` 管理端前端 | go-admin-ui CRUD 与少量定制页 | Vue 3.5.41、Element Plus 2.14.4、Vue CLI 5.0.9 | `pnpm install --frozen-lockfile`、`pnpm build:prod` | 静态产物 | 代码生成器只在隔离开发环境使用 | | `migrations` 数据库迁移 | 业务表、`sys_*` 基线和菜单/API 配置的全部生产演进 | golang-migrate SQL | up/down 隔离库验证 | 随版本发布 | **生产数据库结构的唯一事实来源** | 管理员 `sys_user` 与终端用户 `users` 分表。MVP-0 只要求 core、platform、portal 和必要迁移可运行;admin/admin-ui 在 MVP-1 接入,但生产所需 `sys_*` 初始结构和配置仍必须先转成版本化 SQL。任何构建、CI 或部署都不得依赖 `D:\github\goadmin` 的绝对路径。 +#23 已把固定 `go-admin` 的所需后端源导入 `admin/` 这个嵌套 Go module,并把内部 import 改为仓库模块路径。运行入口是 `admin/cmd/server.go`;生产仅保留 `chorus-admin server --config <受保护配置>`,不导入原项目的 `cmd/migrate`、代码生成、Swagger、WebSocket 或静态文件路由。该入口只连接已经迁移的数据库,不执行 AutoMigrate、迁移或 seed。 + ## 技术栈与运行环境 ### 固定来源基线 @@ -117,6 +119,7 @@ synchronized_at: 2026-08-21T06:15:04Z | 编译 | `go build ./...` | 无错误 | | 单元测试 | `go test ./...` | 全部通过 | | 静态检查 | `go vet ./...` | 无输出 | +| 管理端编译与测试 | `go -C admin build .`、`go -C admin test ./...` | 独立 admin module 无错误 | | 数据库迁移 | `migrate -path migrations -database "$CHORUS_MIGRATE_URL" up` | 迁移版本前进且无错误 | | 幂等种子 | `go run ./cmd/chorus-seed` | 只输出完成状态,不输出凭据 | | 启动用户端 | `scripts\chorus-dev.bat start` | 后台启动并检查 `/login`,不执行迁移或 seed | diff --git a/docs/02-architecture-and-code-map.md b/docs/02-architecture-and-code-map.md index 8faa951..aae7ac3 100644 --- a/docs/02-architecture-and-code-map.md +++ b/docs/02-architecture-and-code-map.md @@ -2,8 +2,8 @@ generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件) wiki_page: Architecture-and-Code-Map wiki_url: https://git.ilapage.cn/OPC/chorus/wiki/Architecture-and-Code-Map.- -wiki_revision: 8805724b04c14ef2bb5161a79a037b36e1485b68 -synchronized_at: 2026-08-21T09:20:42Z +wiki_revision: 8c1c40529eb6da550fdfc395ec878a0431c9ef30 +synchronized_at: 2026-08-21T15:02:17Z # 架构与代码地图 @@ -29,13 +29,20 @@ chorus/ │ └── crypto/ 密钥加密接口 ├── internal/platform/ HTTP/SSRF、gobreaker、imaging、本地/S3 适配 ├── portal/ 用户页面、HTMX 片段、JSON API、worker 组装 -├── admin/ 固定 go-admin 后端,业务 app 在 app/chorus/ +├── admin/ 固定 go-admin 后端的嵌套 Go module;生产入口 cmd/server.go,业务 app 在 app/chorus/ ├── admin-ui/ 固定 go-admin-ui 导入代码与定制页 └── migrations/ 所有生产表、sys_* 基线和配置种子 ``` 固定来源和提交见 [项目档案](Project-Profile.-)。`D:\github\goadmin` 只用于来源审查和首次导入,运行、CI 与部署不得依赖该路径。 +### #23 已落地的管理端后端 + +- `admin/` 是独立 Go module;从仓库根目录使用 `go -C admin build .` 和 `go -C admin test ./...`。`admin/cmd/server.go` 只注册生产 `server` 子命令,必须提供受保护的 go-admin settings 文件和 `CHORUS_MASTER_KEY`。 +- `admin/app/chorus/` 实现 Provider、ProviderModel、PromptTemplate、RoutePool、Generation 与终端用户查询 API。所有 Chorus API 经过固定 go-admin 的 JWT 与 Casbin 链;JWT 只从 `Authorization: Bearer` 读取,不接受 Query 或 Cookie token。 +- 原 go-admin 的 AutoMigrate、代码生成、Swagger、WebSocket 与静态文件路由未导入生产入口。`/api/v1/chorus/` 不提供 DELETE;被引用记录使用启停而不是物理删除。 +- 通用操作日志对 `/api/v1/chorus` 完全跳过请求体与结果持久化,避免把凭据写入 `sys_oper_log`;配置变更和被拒绝的探测由 `admin_audit_events` 记录脱敏摘要。 + ## MVP-0 的最小形态 | 目录 | MVP-0 实现 | 暂缓 | @@ -196,10 +203,10 @@ ClaimLease(只取得租约并记录 lease 事件) 管理 API 位于独立管理员认证/Casbin 下的 `/api/v1/chorus/`: -- providers/models/templates/users 使用列表、详情、创建、更新和启停;已被引用的记录不提供物理删除。Provider 响应只给 `has_credential`、活动 credential 版本和 `key_id`,永不返回 `api_key_enc`/明文。 +- providers/models/templates 使用列表、详情、创建、更新和启停;users/generations 只读列表。已被引用的记录不提供物理删除。Provider 响应只给 `has_credential`、活动 credential 版本和 `key_id`,永不返回 `api_key_enc`/明文或密文信封。 - `PUT providers/:id/credential` 只接收新明文一次,事务内加密、创建新版本、切换 active、退役旧版本并写审计;`POST providers/:id/credential/:version/activate` 可审计回退。普通 Provider 更新省略 secret 即保持不变,不能用空字符串意外清除。 - route-pools 使用 `version` 乐观锁;发布活动绑定时校验能力、至少一个启用成员、正权重、PromptTemplate 兼容和 breaker 参数,不合格返回字段级错误。 -- `POST provider-models/:id/connectivity-checks` 需要独立权限和 CSRF/JWT 保护。事务锁定最近检查并预留 running 记录;冷却内返回 429 和 `retry_after_seconds`。服务端按 api_type 使用预先配置的固定最小探针,不接收任意 Prompt/extra_body,经过相同 SSRF/认证/超时链路,完成后写脱敏结果与 audit。保存配置不自动测试,CI/日常调试只用 mock;首个真实 Provider、探针和冷却值仍是上线前人工确认门禁。 +- `POST provider-models/:id/connectivity-checks` 有独立 Casbin API 权限,并且仅接受 Authorization Bearer JWT,不使用 Cookie/Query token,因此没有浏览器 Cookie CSRF 通道。事务锁定最近检查并预留 running 记录;冷却内返回 429 和 `retry_after_seconds`。未显式授权时 API 写一条脱敏拒绝审计并返回 403,绝不构造出站请求。只有运行时明确设置 `CHORUS_ADMIN_ALLOW_CONNECTIVITY_PROBES=1`,并同时提供正数冷却、HTTP 超时与响应上限,服务端才按 api_type 使用固定最小探针;不接收任意 Prompt/extra_body,仍经过同一 SSRF/认证/超时链路,完成后写脱敏结果与 audit。保存配置不自动测试,CI/日常调试只用 mock;首个真实 Provider、探针和冷却值仍是上线前人工确认门禁。 #### portal 契约 diff --git a/docs/04-local-development-and-verification.md b/docs/04-local-development-and-verification.md index 538e5eb..2ba1641 100644 --- a/docs/04-local-development-and-verification.md +++ b/docs/04-local-development-and-verification.md @@ -2,8 +2,8 @@ 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: 6ee10fcf46eda115b5d1db03f94b0ba2c0f74655 -synchronized_at: 2026-08-21T09:23:59Z +wiki_revision: 6975232fead63ed60c480fb4bf7c0e9188a430d1 +synchronized_at: 2026-08-21T15:02:26Z # 本地开发与验证 @@ -44,7 +44,10 @@ synchronized_at: 2026-08-21T09:23:59Z | `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_MASTER_KEY` / 对应 key ring 配置 | Provider Key AES-GCM 解密与轮换;管理端启动也必须提供 | +| `CHORUS_ADMIN_ALLOW_CONNECTIVITY_PROBES` | 默认不设置或 `0`,管理端拒绝连通性探测;只有人工授权真实探测时才设为 `1` | +| `CHORUS_ADMIN_CONNECTIVITY_COOLDOWN_SECONDS` | 探测已授权时的正整数冷却;未授权时不需要 | +| `CHORUS_PROVIDER_HTTP_TIMEOUT_SECONDS` / `CHORUS_PROVIDER_MAX_RESPONSE_BYTES` | 探测已授权时的正整数安全 HTTP 限制 | | `CHORUS_SESSION_KEY` | portal 会话,必须与主密钥分离 | | `CHORUS_STORAGE_ROOT` | 受保护生成物目录 | | `CHORUS_ENV` | `development/test/production`,生产强制安全开关 | @@ -142,6 +145,16 @@ go run ./cmd/chorus-admin-bootstrap 集成测试使用运行时生成的构造账号与密码,并要求显式的 `CHORUS_RUN_ADMIN_BOOTSTRAP_TESTS=1` 和指向隔离库的 `CHORUS_ADMIN_BOOTSTRAP_TEST_DSN`。测试结束会删除构造账号;不得把该变量指向开发共享库或生产库。 +### 启动管理端后端(#23) + +先完成 migrations 和管理员 bootstrap。把 `admin/config/settings.example.yml` 复制到仓库外的受保护位置,并在其中设置独立 JWT secret 与数据库连接;示例文件不得填入真实值。当前终端安全注入 `CHORUS_MASTER_KEY` 后启动: + +```powershell +go -C admin run . server --config "<受保护 settings.yml 路径>" +``` + +该命令只启动 go-admin 管理 API,不执行 migration、seed 或 AutoMigrate,也不注册代码生成、Swagger、WebSocket 或静态文件路由。管理 API 使用 `Authorization: Bearer `;不要在 URL 或 Cookie 放置 token。连通性探测默认返回 403 且不出站。只有经过人工批准的单次真实检查,才在本次受保护进程设置 `CHORUS_ADMIN_ALLOW_CONNECTIVITY_PROBES=1`,并同时提供正数 `CHORUS_ADMIN_CONNECTIVITY_COOLDOWN_SECONDS`、`CHORUS_PROVIDER_HTTP_TIMEOUT_SECONDS` 和 `CHORUS_PROVIDER_MAX_RESPONSE_BYTES`。 + ### 3. go-admin schema-first 生成(MVP-1) 1. 先在 `chorus_codegen` 执行同一套版本化 SQL。 @@ -269,6 +282,18 @@ corepack pnpm --dir portal/web test:e2e - 浏览器:HTMX 动态状态、终态停止、认证过期、网络错误;375/768/1024/1440 无主区域横向滚动,并检查键盘、44px 触控目标和 reduced-motion。 - 供应链:Go/Node 依赖锁定、漏洞和许可证检查按实现工单确定命令。 +### 管理端后端集成测试(#23) + +管理端测试只允许使用精确名称为 `chorus_test` 的可丢弃 MySQL 数据库;测试写入随机后缀的合成 Provider/Model/Route 数据并清理,不调用真实上游。运行: + +```powershell +$env:CHORUS_RUN_ADMIN_TESTS = "1" +go -C admin test -count=1 ./... +$env:CHORUS_RUN_ADMIN_TESTS = $null +``` + +覆盖凭据加密、轮换和回退、普通更新不清除凭据、路由发布版本冲突、JWT/Casbin 路由边界、禁用探测不出站,以及探测冷却只预留一次。根模块的 migration up/down/up 回归仍需在可丢弃库执行:`go test -count=1 ./migrations -run TestMVP1MigrationsUpDownUpMySQL`。 + ## 完成修改前 ```powershell @@ -276,6 +301,8 @@ git status --short --branch go build ./... go vet ./... go test ./... +go -C admin build . +go -C admin test ./... corepack pnpm --dir portal/web install --frozen-lockfile corepack pnpm --dir portal/web build corepack pnpm --dir portal/web test:e2e