diff --git a/.gitignore b/.gitignore index 26231795..2ee5a554 100644 --- a/.gitignore +++ b/.gitignore @@ -128,7 +128,11 @@ backend/cmd/server/server deploy/docker-compose.override.yml .gocache/ vite.config.js +# docs/ 目录保留项目文档 +!docs/ docs/* +!docs/PROJECT_REVIEW.md +!docs/reports/ .serena/ .codex/ frontend/coverage/ diff --git a/DEV_GUIDE.md b/DEV_GUIDE.md index d0d362e0..1439dee5 100644 --- a/DEV_GUIDE.md +++ b/DEV_GUIDE.md @@ -1,346 +1,324 @@ # sub2api 项目开发指南 -> 本文档记录项目环境配置、常见坑点和注意事项,供 Claude Code 和团队成员参考。 +> 本文档记录项目环境配置、开发规范和常见问题,供 Claude Code 和团队成员参考。 ## 一、项目基本信息 | 项目 | 说明 | |------|------| -| **上游仓库** | Wei-Shaw/sub2api | -| **Fork 仓库** | bayma888/sub2api-bmai | -| **技术栈** | Go 后端 (Ent ORM + Gin) + Vue3 前端 (pnpm) | -| **数据库** | PostgreSQL 16 + Redis | -| **包管理** | 后端: go modules, 前端: **pnpm**(不是 npm) | +| **远程仓库** | https://www.tksea.top/pham/tokens-reef | +| **技术栈** | Go 后端 (Ent ORM + Gin) + Vue3 前端 | +| **数据库** | PostgreSQL 15+ + Redis 7+ | +| **包管理** | 后端: go modules, 前端: npm | -## 二、本地环境配置 +--- -### PostgreSQL 16 (Windows 服务) +## 二、项目规范 + +### 2.1 代码规范 + +#### 后端目录结构 + +``` +backend/internal/ +├── config/ # 配置管理 (viper) +├── domain/ # 领域模型 +├── handler/ # HTTP 处理器 +├── service/ # 业务逻辑层 +├── repository/ # 数据访问层 +├── middleware/ # HTTP 中间件 +├── pkg/ # 内部工具包 +├── util/ # 工具函数 +├── testutil/ # 测试工具和 fixtures +└── web/ # 前端嵌入 +``` + +#### 前端目录结构 + +``` +frontend/src/ +├── api/ # API 调用封装 +├── components/ # 可复用组件 +├── composables/ # Vue 组合式函数 +├── stores/ # Pinia 状态管理 +├── views/ # 页面视图 +├── types/ # TypeScript 类型定义 +├── utils/ # 工具函数 +└── i18n/ # 国际化 +``` + +### 2.2 命名约定 + +| 类型 | 约定 | 示例 | +|------|------|------| +| 接口 | PascalCase + 后缀 | `UserService`, `AccountRepository` | +| 实现 | camelCase + 后缀 | `userService`, `accountRepository` | +| 测试文件 | 源文件_test.go | `user_service_test.go` | +| 测试 Stub | stub + 名称 | `stubUserRepo` | +| 前端组件 | PascalCase | `UserList.vue` | +| 前端测试 | __tests__/xxx.spec.ts | `UserList.spec.ts` | + +### 2.3 Git 提交规范 + +**格式**: +``` +(): + + +``` + +**Type 类型**: +- `feat`: 新功能 +- `fix`: Bug 修复 +- `docs`: 文档更新 +- `refactor`: 重构 +- `test`: 测试相关 +- `chore`: 构建/工具/清理 +- `security`: 安全修复 + +**示例**: +``` +fix(config): resolve Windows path resolution issue + +- Add optional configPaths parameter to load() +- Use t.TempDir() for test isolation +``` + +### 2.4 测试规范 + +**后端测试**: +```bash +# 单元测试 +go test -tags=unit ./... + +# 集成测试(需要数据库) +go test -tags=integration ./... + +# 特定包 +go test -tags=unit ./internal/service/ -v +``` + +**前端测试**: +```bash +# 运行测试 +npm run test:run + +# 监听模式 +npm run test + +# 覆盖率 +npm run test:coverage +``` + +**测试原则**: +1. 测试文件与源码同目录(Go: `*_test.go`, Vue: `__tests__/`) +2. 使用 `t.TempDir()` 创建隔离临时目录 +3. 清理资源:关闭文件、释放锁、重置全局状态 +4. Windows 兼容:注意路径、pipe、文件锁差异 + +--- + +## 三、本地环境配置 + +### 3.1 PostgreSQL | 配置项 | 值 | |--------|-----| | 端口 | 5432 | -| psql 路径 | `C:\Program Files\PostgreSQL\16\bin\psql.exe` | -| pg_hba.conf | `C:\Program Files\PostgreSQL\16\data\pg_hba.conf` | -| 数据库凭据 | user=`sub2api`, password=`sub2api`, dbname=`sub2api` | -| 超级用户 | user=`postgres`, password=`postgres` | +| 数据库 | sub2api | +| 用户 | sub2api / sub2api | +| 超级用户 | postgres / postgres | -### Redis +### 3.2 Redis | 配置项 | 值 | |--------|-----| | 端口 | 6379 | | 密码 | 无 | -### 开发工具 +### 3.3 开发工具 ```bash -# golangci-lint v2.7 -go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7 +# golangci-lint +go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest -# pnpm (前端包管理) -npm install -g pnpm -``` - -## 三、CI/CD 流水线 - -### GitHub Actions Workflows - -| Workflow | 触发条件 | 检查内容 | -|----------|----------|----------| -| **backend-ci.yml** | push, pull_request | 单元测试 + 集成测试 + golangci-lint v2.7 | -| **security-scan.yml** | push, pull_request, 每周一 | govulncheck + gosec + pnpm audit | -| **release.yml** | tag `v*` | 构建发布(PR 不触发) | - -### CI 要求 - -- Go 版本必须是 **1.25.7** -- 前端使用 `pnpm install --frozen-lockfile`,必须提交 `pnpm-lock.yaml` - -### 本地测试命令 - -```bash -# 后端单元测试 -cd backend && go test -tags=unit ./... - -# 后端集成测试 -cd backend && go test -tags=integration ./... - -# 代码质量检查 -cd backend && golangci-lint run ./... - -# 前端依赖安装(必须用 pnpm) -cd frontend && pnpm install -``` - -## 四、常见坑点 & 解决方案 - -### 坑 1:pnpm-lock.yaml 必须同步提交 - -**问题**:`package.json` 新增依赖后,CI 的 `pnpm install --frozen-lockfile` 失败。 - -**原因**:上游 CI 使用 pnpm,lock 文件不同步会报错。 - -**解决**: -```bash -cd frontend -pnpm install # 更新 pnpm-lock.yaml -git add pnpm-lock.yaml -git commit -m "chore: update pnpm-lock.yaml" +# Ent 代码生成 +go install entgo.io/ent/cmd/ent@latest ``` --- -### 坑 2:npm 和 pnpm 的 node_modules 冲突 +## 四、常用命令 -**问题**:之前用 npm 装过 `node_modules`,pnpm install 报 `EPERM` 错误。 +### 4.1 后端命令 -**解决**: ```bash -cd frontend -rm -rf node_modules # 或 PowerShell: Remove-Item -Recurse -Force node_modules -pnpm install +# 运行服务 +go run ./cmd/server/ + +# 构建 +go build -o bin/server ./cmd/server/ + +# 生成 Ent 代码(修改 schema 后必须执行) +go generate ./ent + +# 单元测试 +go test -tags=unit ./... + +# 集成测试 +go test -tags=integration ./... + +# Lint 检查 +golangci-lint run ./... + +# 检查所有 +go test -tags=unit ./... && golangci-lint run ./... +``` + +### 4.2 前端命令 + +```bash +# 安装依赖 +npm install + +# 开发服务器 +npm run dev + +# 构建 +npm run build + +# 类型检查 +npx vue-tsc --noEmit + +# 测试 +npm run test:run + +# Lint +npm run lint +``` + +### 4.3 数据库命令 + +```bash +# 连接数据库 +psql -U sub2api -h 127.0.0.1 -d sub2api + +# 执行迁移 +psql -U sub2api -h 127.0.0.1 -d sub2api -f migrations/xxx.sql + +# 查看表结构 +\dt +\d table_name ``` --- -### 坑 3:PowerShell 中 bcrypt hash 的 `$` 被转义 +## 五、常见问题 -**问题**:bcrypt hash 格式如 `$2a$10$xxx...`,PowerShell 把 `$2a` 当变量解析,导致数据丢失。 +### 5.1 Ent Schema 修改后不生效 -**解决**:将 SQL 写入文件,用 `psql -f` 执行: +**原因**: Ent 是代码生成工具,修改 schema 后需要重新生成 + +**解决**: ```bash -# 错误示范(PowerShell 会吃掉 $) -psql -c "INSERT INTO users ... VALUES ('$2a$10$...')" - -# 正确做法 -echo "INSERT INTO users ... VALUES ('\$2a\$10\$...')" > temp.sql -psql -U sub2api -h 127.0.0.1 -d sub2api -f temp.sql -``` - ---- - -### 坑 4:psql 不支持中文路径 - -**问题**:`psql -f "D:\中文路径\file.sql"` 报错找不到文件。 - -**解决**:复制到纯英文路径再执行: -```bash -cp "D:\中文路径\file.sql" "C:\temp.sql" -psql -f "C:\temp.sql" -``` - ---- - -### 坑 5:PostgreSQL 密码重置流程 - -**场景**:忘记 PostgreSQL 密码。 - -**步骤**: -1. 修改 `C:\Program Files\PostgreSQL\16\data\pg_hba.conf` - ``` - # 将 scram-sha-256 改为 trust - host all all 127.0.0.1/32 trust - ``` -2. 重启 PostgreSQL 服务 - ```powershell - Restart-Service postgresql-x64-16 - ``` -3. 无密码登录并重置 - ```bash - psql -U postgres -h 127.0.0.1 - ALTER USER sub2api WITH PASSWORD 'sub2api'; - ALTER USER postgres WITH PASSWORD 'postgres'; - ``` -4. 改回 `scram-sha-256` 并重启 - ---- - -### 坑 6:Go interface 新增方法后 test stub 必须补全 - -**问题**:给 interface 新增方法后,编译报错 `does not implement interface (missing method XXX)`。 - -**原因**:所有测试文件中实现该 interface 的 stub/mock 都必须补上新方法。 - -**解决**: -```bash -# 搜索所有实现该 interface 的 struct cd backend +go generate ./ent +git add ent/ +``` + +### 5.2 接口新增方法后编译失败 + +**原因**: 所有实现该接口的 mock/stub 都需要补全新方法 + +**解决**: +```bash +# 搜索所有 stub grep -r "type.*Stub.*struct" internal/ grep -r "type.*Mock.*struct" internal/ # 逐一补全新方法 ``` ---- +### 5.3 Windows 上测试超时 -### 坑 7:Windows 上 psql 连 localhost 的 IPv6 问题 +**原因**: Windows pipe 的 Sync() 会阻塞 -**问题**:psql 连 `localhost` 先尝试 IPv6 (::1),可能报错后再回退 IPv4。 - -**建议**:直接用 `127.0.0.1` 代替 `localhost`。 - ---- - -### 坑 8:Windows 没有 make 命令 - -**问题**:CI 里用 `make test-unit`,本地 Windows 没有 make。 - -**解决**:直接用 Makefile 里的原始命令: -```bash -# 代替 make test-unit -go test -tags=unit ./... - -# 代替 make test-integration -go test -tags=integration ./... +**解决**: 先关闭 write end 再调用 Sync +```go +_ = stdoutW.Close() +_ = stderrW.Close() +Sync() ``` ---- +### 5.4 配置测试读取了错误的文件 -### 坑 9:Ent Schema 修改后必须重新生成 +**原因**: viper 搜索路径包含意外的配置文件 -**问题**:修改 `ent/schema/*.go` 后,代码不生效。 +**解决**: 使用可选参数传入测试目录 +```go +// 生产 +load(false) -**解决**: -```bash -cd backend -go generate ./ent # 重新生成 ent 代码 -git add ent/ # 生成的文件也要提交 +// 测试 +load(false, t.TempDir()) ``` ---- +### 5.5 PowerShell 变量转义问题 -### 坑 10:前端测试看似正常,但后端调用失败(模型映射被批量误改) +**问题**: bcrypt hash 中的 `$` 被解析为变量 -**典型现象**: -- 前端按钮点测看起来正常; -- 实际通过 API/客户端调用时返回 `Service temporarily unavailable` 或提示无可用账号; -- 常见于 OpenAI 账号(例如 Codex 模型)在批量修改后突然不可用。 +**解决**: 使用文件执行 SQL +```bash +echo "INSERT INTO users ... VALUES ('\$2a\$10\$...')" > temp.sql +psql -f temp.sql +``` -**根因**: -- OpenAI 账号编辑页默认不显式展示映射规则,容易让人误以为“没映射也没关系”; -- 但在**批量修改同时选中不同平台账号**(OpenAI + Antigravity/Gemini)时,模型白名单/映射可能被跨平台策略覆盖; -- 结果是 OpenAI 账号的关键模型映射丢失或被改坏,后端选不到可用账号。 +### 5.6 psql 不支持中文路径 -**修复方案(按优先级)**: -1. **快速修复(推荐)**:在批量修改中补回正确的透传映射(例如 `gpt-5.3-codex -> gpt-5.3-codex-spark`)。 -2. **彻底重建**:删除并重新添加全部相关账号(最稳但成本高)。 +**解决**: 复制到英文路径再执行 +```bash +cp "D:\中文\file.sql" "C:\temp.sql" +psql -f "C:\temp.sql" +``` -**关键经验**: -- 如果某模型已被软件内置默认映射覆盖,通常不需要额外再加透传; -- 但当上游模型更新快于本仓库默认映射时,**手动批量添加透传映射**是最简单、最低风险的临时兜底方案; -- 批量操作前尽量按平台分组,不要混选不同平台账号。 +### 5.7 PostgreSQL 密码重置 + +1. 修改 `pg_hba.conf`,将 `scram-sha-256` 改为 `trust` +2. 重启服务: `Restart-Service postgresql-x64-16` +3. 无密码登录重置密码 +4. 改回 `scram-sha-256` 并重启 --- -### 坑 11:PR 提交前检查清单 +## 六、PR 检查清单 -提交 PR 前务必本地验证: +提交前务必验证: - [ ] `go test -tags=unit ./...` 通过 -- [ ] `go test -tags=integration ./...` 通过 +- [ ] `go test -tags=integration ./...` 通过(如适用) - [ ] `golangci-lint run ./...` 无新增问题 -- [ ] `pnpm-lock.yaml` 已同步(如果改了 package.json) -- [ ] 所有 test stub 补全新接口方法(如果改了 interface) -- [ ] Ent 生成的代码已提交(如果改了 schema) +- [ ] `npm run test:run` 通过 +- [ ] `npx vue-tsc --noEmit` 无类型错误 +- [ ] Ent 生成的代码已提交(如改了 schema) +- [ ] 测试 stub 已更新(如改了 interface) +- [ ] 无敏感信息泄露 -## 五、常用命令速查 +--- -### 数据库操作 +## 七、CI/CD 流水线 -```bash -# 连接数据库 -psql -U sub2api -h 127.0.0.1 -d sub2api +| Workflow | 触发条件 | 检查内容 | +|----------|----------|----------| +| backend-ci.yml | push, PR | 单元测试 + Lint | +| security-scan.yml | push, PR, 周一 | 安全扫描 | +| release.yml | tag v* | 构建发布 | -# 查看所有用户 -psql -U postgres -h 127.0.0.1 -c "\du" +--- -# 查看所有数据库 -psql -U postgres -h 127.0.0.1 -c "\l" +## 八、参考资源 -# 执行 SQL 文件 -psql -U sub2api -h 127.0.0.1 -d sub2api -f migration.sql -``` - -### Git 操作 - -```bash -# 同步上游 -git fetch upstream -git checkout main -git merge upstream/main -git push origin main - -# 创建功能分支 -git checkout -b feature/xxx - -# Rebase 到最新 main -git fetch upstream -git rebase upstream/main -``` - -### 前端操作 - -```bash -# 安装依赖(必须用 pnpm) -cd frontend -pnpm install - -# 开发服务器 -pnpm dev - -# 构建 -pnpm build -``` - -### 后端操作 - -```bash -# 运行服务器 -cd backend -go run ./cmd/server/ - -# 生成 Ent 代码 -go generate ./ent - -# 运行测试 -go test -tags=unit ./... -go test -tags=integration ./... - -# Lint 检查 -golangci-lint run ./... -``` - -## 六、项目结构速览 - -``` -sub2api-bmai/ -├── backend/ -│ ├── cmd/server/ # 主程序入口 -│ ├── ent/ # Ent ORM 生成代码 -│ │ └── schema/ # 数据库 Schema 定义 -│ ├── internal/ -│ │ ├── handler/ # HTTP 处理器 -│ │ ├── service/ # 业务逻辑 -│ │ ├── repository/ # 数据访问层 -│ │ └── server/ # 服务器配置 -│ ├── migrations/ # 数据库迁移脚本 -│ └── config.yaml # 配置文件 -├── frontend/ -│ ├── src/ -│ │ ├── api/ # API 调用 -│ │ ├── components/ # Vue 组件 -│ │ ├── views/ # 页面视图 -│ │ ├── types/ # TypeScript 类型 -│ │ └── i18n/ # 国际化 -│ ├── package.json # 依赖配置 -│ └── pnpm-lock.yaml # pnpm 锁文件(必须提交) -└── .claude/ - └── CLAUDE.md # 本文档 -``` - -## 七、参考资源 - -- [上游仓库](https://github.com/Wei-Shaw/sub2api) -- [Ent 文档](https://entgo.io/docs/getting-started) -- [Vue3 文档](https://vuejs.org/) -- [pnpm 文档](https://pnpm.io/) +- [项目复盘总结](docs/PROJECT_REVIEW.md) +- [审查报告](docs/reports/) +- [Ent 文档](https://entgo.io/) +- [Vue 3 文档](https://vuejs.org/) +- [Gin 文档](https://gin-gonic.com/) diff --git a/docs/PROJECT_REVIEW.md b/docs/PROJECT_REVIEW.md new file mode 100644 index 00000000..cd4b5ce2 --- /dev/null +++ b/docs/PROJECT_REVIEW.md @@ -0,0 +1,336 @@ +# Sub2API 项目复盘总结 + +**复盘日期**: 2026/04/13 +**项目版本**: main (d44fa6b) +**复盘范围**: 全项目开发、测试、部署经验 + +--- + +## 一、项目概况 + +### 1.1 项目定位 + +**Sub2API** 是一个企业级 AI API 网关平台,核心功能: +- 多平台 AI 服务聚合(OpenAI、Gemini、Anthropic、Sora 等) +- API Key 管理与认证 +- 用户订阅与计费 +- 负载均衡与智能路由 +- 运维监控与告警 + +### 1.2 项目规模 + +| 指标 | 数量 | +|------|------| +| 后端 Go 文件 | 450+ 个 | +| 后端代码行数 | ~370,000 行 | +| 后端测试文件 | 383 个 | +| 前端 TypeScript/Vue 文件 | 310 个 | +| 前端组件 | 114 个 | +| 前端视图 | 53 个 | +| 前端测试用例 | 301 个 | +| 数据库迁移 | 97 个 | + +### 1.3 技术栈 + +| 层级 | 技术选型 | +|------|----------| +| 后端框架 | Go 1.26+ / Gin | +| ORM | Ent (Facebook) | +| 依赖注入 | Google Wire | +| 前端框架 | Vue 3 + TypeScript | +| 状态管理 | Pinia | +| 样式方案 | TailwindCSS | +| 构建工具 | Vite | +| 数据库 | PostgreSQL 15+ | +| 缓存 | Redis 7+ | +| 容器化 | Docker + Docker Compose | + +--- + +## 二、开发经验总结 + +### 2.1 测试相关经验 + +#### 经验 1: Windows 平台测试兼容性 + +**问题**: 3 个测试包在 Windows 上失败 +- `config` 包:配置路径解析差异(`/app/data` → `D:\app\data`) +- `handler` 包:测试 stub 返回值错误 +- `logger` 包:`Sync()` 在 pipe 上阻塞 + +**解决方案**: +```go +// config: 添加可选参数实现测试隔离 +func load(allowMissingJWTSecret bool, configPaths ...string) (*Config, error) + +// logger: 先关闭 write end 再 Sync +_ = stdoutW.Close() +Sync() + +// logger: 添加 Reset() 关闭文件句柄 +func Reset() { + if fileCloser != nil { + _ = fileCloser() + } +} +``` + +**教训**: 跨平台开发必须考虑: +1. 路径分隔符差异 +2. 文件锁定机制差异 +3. Pipe/Socket 行为差异 + +#### 经验 2: 测试隔离原则 + +**问题**: 测试相互干扰,配置文件被意外读取 + +**最佳实践**: +- 使用 `t.TempDir()` 创建隔离临时目录 +- 每个测试独立的配置/数据目录 +- Cleanup 函数确保资源释放 +- 避免全局状态污染 + +```go +func TestXXX(t *testing.T) { + tmpDir := t.TempDir() // 自动清理 + // 使用 tmpDir 作为测试数据目录 +} +``` + +### 2.2 代码质量经验 + +#### 经验 3: 接口变更的测试维护 + +**问题**: 接口新增方法后,所有 mock/stub 编译失败 + +**解决方案**: +1. 使用 `grep -r "type.*Stub.*struct"` 定位所有 stub +2. 批量补全新方法 +3. 考虑使用 mockery 等代码生成工具 + +#### 经验 4: Ent Schema 变更流程 + +**问题**: 修改 schema 后代码不生效 + +**正确流程**: +```bash +# 1. 修改 ent/schema/*.go +# 2. 重新生成 +go generate ./ent +# 3. 提交生成的代码 +git add ent/ +# 4. 可能需要数据库迁移 +``` + +### 2.3 前端开发经验 + +#### 经验 5: 包管理器一致性 + +**问题**: 项目使用 pnpm,但误用 npm 导致 lock 文件冲突 + +**解决方案**: +- 统一使用单一包管理器 +- 删除 `pnpm-lock.yaml` 或 `package-lock.yaml` 其中之一 +- CI 必须与本地保持一致 + +#### 经验 6: 模型映射管理 + +**问题**: 批量编辑跨平台账号时,模型映射被错误覆盖 + +**教训**: +- 批量操作按平台分组 +- 关键映射变更需二次确认 +- 模型映射应有版本/审计追踪 + +--- + +## 三、项目规范更新 + +### 3.1 代码规范 + +#### Go 后端规范 + +1. **目录结构** + ``` + internal/ + ├── config/ # 配置(viper) + ├── domain/ # 领域模型 + ├── handler/ # HTTP 处理器 + ├── service/ # 业务逻辑 + ├── repository/ # 数据访问 + ├── pkg/ # 内部工具包 + └── testutil/ # 测试工具 + ``` + +2. **命名约定** + - 接口:`XXXService`, `XXXRepository` + - 实现:`xxxService`, `xxxRepository` + - 测试文件:`xxx_test.go` + - 测试 stub:`stubXXX`, `mockXXX` + +3. **错误处理** + - 使用 `internal/pkg/errors` 定义错误码 + - 业务错误返回结构化响应 + - 日志脱敏敏感信息 + +4. **测试规范** + - 单元测试:`go test -tags=unit` + - 集成测试:`go test -tags=integration` + - 测试覆盖率目标:80%+ + +#### Vue 前端规范 + +1. **目录结构** + ``` + src/ + ├── api/ # API 调用 + ├── components/ # 可复用组件 + ├── composables/ # 组合式函数 + ├── stores/ # Pinia 状态 + ├── views/ # 页面视图 + ├── types/ # TypeScript 类型 + └── utils/ # 工具函数 + ``` + +2. **测试规范** + - 测试文件:`__tests__/xxx.spec.ts` + - 使用 Vitest 运行测试 + - 组件测试关注用户交互 + +### 3.2 Git 规范 + +#### 提交信息格式 + +``` +(): + + + +