diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md index 8c4cf7de..08410c1c 100644 --- a/.workbuddy/memory/MEMORY.md +++ b/.workbuddy/memory/MEMORY.md @@ -5,9 +5,37 @@ - **仓库路径**:`d:/project/sub2api` - **技术栈**:Go(后端)+ Vue 3(前端),PostgreSQL + Redis,Gin 框架,ent ORM - **主要模块**:`backend/internal/service/`(核心服务),`backend/internal/handler/`,`backend/internal/pkg/` +- **Gitea 仓库**:https://www.tksea.top/pham/tokensea(字节海洋) +- **GitHub 仓库**:https://github.com/phamnazage-jpg/tokens-reef(代码质量修复) ## 代码审查历史 +### 2026-04-02 E2E 测试修复 + +**问题清单**: + +| ID | 文件 | 问题 | 修复方案 | +|----|------|------|---------| +| E2E-01 | user-apikey-lifecycle.spec.ts | API Key 路径错误 `/api/v1/keys` | 改为 `/api/v1/api-keys`(24处) | +| E2E-02 | admin-users.spec.ts:156-157 | 余额调整 Payload 错误 | 确认格式正确:`{balance, operation, notes}` | +| E2E-03 | admin-groups.spec.ts:229-232 | Rate Multiplier Payload 错误 | 确认格式正确:`{entries: [...]}` | + +**修复提交**: +- `8b19f56` fix: update E2E test API paths and payloads to match backend + +### 2026-04-02 后端修复 + +**已修复问题**: + +| ID | 文件 | 问题 | 修复方案 | +|----|------|------|---------| +| P0-01 | sticky_session_test.go | 缺少 context import | 添加 `import "context"` | +| P0-02 | wire_gen.go | 缺少 usageLogRepository | 添加参数 | +| P0-03 | admin_service_stub_test.go | 缺少 GetGroupAPIKeyCount | 添加 stub | +| P1-01 | gateway_service.go | defaultMaxLineSize 过大 | 优化为合理值 | +| P1-02 | account_service.go | TestCredentials 返回 nil | 实现真实验证 | +| P1-03 | group_handler.go GetStats | 返回硬编码零值 | 实现真实数据查询 | + ### 2026-03-31(首次基线审查) **审查的 commit**: @@ -19,17 +47,13 @@ | ID | 级别 | 文件 | 问题摘要 | 状态 | |----|------|------|---------|------| -| P0-01 | 🔴 P0 | `backend/internal/service/sticky_session_test.go:108` | shouldClearStickySession 测试调用缺少 ctx 参数,`go test -tags unit` 编译失败 | ❌ 未修复 | -| P1-01 | 🟡 P1 | `backend/internal/service/gateway_service.go:44` | defaultMaxLineSize = 500MB,高并发下 OOM 风险 | ❌ 未修复 | -| P1-02 | 🟡 P1 | `backend/internal/service/account_service.go:386-398` | TestCredentials 三平台均 return nil,凭证验证功能形同虚设 | ❌ 未修复 | -| P1-03 | 🟡 P1 | `backend/internal/handler/admin/group_handler.go:362-368` | GetStats API 返回硬编码零值 mock 数据 | ❌ 未修复 | -| P1-04 | 🟡 P1 | `backend/internal/handler/sora_client_handler_test.go` | 16 个 Sora 相关测试用 t.Skip 长期屏蔽,无 Issue 追踪 | ❌ 未修复 | -| 挑剔-01 | 💭 | 多个 service 文件 | math/rand 使用缺少注释说明用途 | ❌ 未修复 | -| 挑剔-02 | 💭 | `gemini_messages_compat_service.go:44` | geminiDummyThoughtSignature 魔法字符串无文档 | ❌ 未修复 | -| 挑剔-03 | 💭 | `backend/internal/pkg/models/interface.go:220-225` | ModelError.Error() 使用 fmt.Sprint 而非 fmt.Sprintf,格式化占位符不生效 | ❌ 未修复 | +| P0-01 | 🔴 P0 | `backend/internal/service/sticky_session_test.go:108` | shouldClearStickySession 测试调用缺少 ctx 参数,`go test -tags unit` 编译失败 | ✅ 已修复 | +| P1-01 | 🟡 P1 | `backend/internal/service/gateway_service.go:44` | defaultMaxLineSize = 500MB,高并发下 OOM 风险 | ✅ 已修复 | +| P1-02 | 🟡 P1 | `backend/internal/service/account_service.go:386-398` | TestCredentials 三平台均 return nil,凭证验证功能形同虚设 | ✅ 已修复 | +| P1-03 | 🟡 P1 | `backend/internal/handler/admin/group_handler.go:362-368` | GetStats API 返回硬编码零值 mock 数据 | ✅ 已修复 | +| P1-04 | 🟡 P1 | `backend/internal/handler/sora_client_handler_test.go` | 16 个 Sora 相关测试用 t.Skip 长期屏蔽,无 Issue 追踪 | ✅ 已改善 | +| 挑剔-01 | 💭 | 多个 service 文件 | math/rand 使用缺少注释说明用途 | ✅ 已改善 | +| 挑剔-02 | 💭 | `gemini_messages_compat_service.go:44` | geminiDummyThoughtSignature 魔法字符串无文档 | ✅ 已改善 | +| 挑剔-03 | 💭 | `backend/internal/pkg/models/interface.go:220-225` | ModelError.Error() 使用 fmt.Sprint 而非 fmt.Sprintf,格式化占位符不生效 | ✅ 已修复 | -**健康度评分**:7/10 - -## 2026-03-31 第二次巡检(09:58) - -无新 commit,所有已知问题状态未变,报告文件已追加第二次审查章节。 +**健康度评分**:9/10 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..d996a95a --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,183 @@ +# CLAUDE.md - Sub2API Project Guide + +This file provides Claude Code with specific guidance for working on Sub2API. + +## Project Context + +Sub2API is an AI API Gateway that distributes API quotas from AI subscriptions (OpenAI, Anthropic, Google, etc.) to users through generated API keys. + +## Quick Reference + +| Item | Value | +|------|-------| +| Backend Port | 8080 | +| Frontend Dev | pnpm dev | +| Test Account | lon22@qq.com / admin123 | +| Go Path | D:/Program Files/Go/bin/go.exe | + +## Test Commands + +```bash +# Frontend (Vitest) +cd frontend && pnpm test -- --run + +# Backend (Go) - Use full path on Windows +D:/Program Files/Go/bin/go.exe test -short ./... + +# E2E (Playwright) +cd tests && npx playwright test --project=chromium +``` + +## Important Notes + +### Windows-Specific +- Go installed at: `D:/Program Files/Go/` +- Use full path: `D:/Program Files/Go/bin/go.exe` +- Logger test (`internal/pkg/logger`) times out on Windows due to zap Fsync() - skip with `-skip "logger"` + +### Backend Build +- Frontend builds to: `backend/internal/web/dist/` +- Build command: `cd frontend && pnpm build` +- Binary: `backend/sub2api.exe` + +### Database +- Uses Ent ORM for Go +- Generate code: `go generate ./ent` in backend/ + +## File Patterns + +### Backend (Go) +- Handlers: `backend/internal/handler/` +- Services: `backend/internal/service/` +- Routes: `backend/internal/server/routes/` + +### Frontend (Vue) +- API: `frontend/src/api/` +- Components: `frontend/src/components/` +- Stores: `frontend/src/stores/` +- Tests: `frontend/src/**/*.spec.ts` + +### E2E Tests +- Location: `tests/e2e/*.spec.ts` +- Config: `tests/playwright.config.ts` +- Pages: `tests/e2e/pages/` + +## Common Development Tasks + +### Running Tests +```bash +# All tests +cd tests && npm test + +# Just E2E +cd tests && npx playwright test + +# Frontend unit tests +cd frontend && pnpm test + +# Backend tests +cd backend && D:/Program Files/Go/bin/go.exe test -short ./... +``` + +### Adding a Feature +1. Backend first: handler → service → repository +2. Add route registration +3. Frontend API client +4. Vue component +5. Tests + +### Code Generation +```bash +cd backend +go generate ./ent +go generate ./cmd/server +``` + +## Key Dependencies + +### Backend +- `go.uber.org/zap` - Logging +- `gin-gonic/gin` - HTTP framework +- `ent/ent` - ORM +- `redis/go-redis` - Redis client + +### Frontend +- `vue` 3.4+ +- `vite` 5+ +- `tailwindcss` +- `pinia` - State management +- `vitest` - Testing + +## Testing Best Practices + +1. **Frontend**: Tests live next to components in `__tests__/` directories +2. **E2E**: Use Page Object pattern in `tests/e2e/pages/` +3. **Backend**: Tests in `_test.go` files alongside source + +## Troubleshooting + +### Backend won't start +- Check PostgreSQL and Redis are running +- Verify `backend/config.yaml` is correct + +### Frontend build fails +- Run `pnpm install` in frontend directory +- Check Node.js version (18+) + +### E2E tests fail +- Ensure backend is running on port 8080 +- Check test account exists: lon22@qq.com + +## tokens-reef 独立修复仓库 + +为了避免与主仓库 Wei-Shaw/sub2api 混淆,Sub2API 的代码质量修复(P0/P1 问题)存放在独立的仓库中: + +| 属性 | 值 | +|------|-------| +| 仓库名称 | `tokens-reef`(token 海洋) | +| 仓库地址 | https://github.com/phamnazage-jpg/tokens-reef | +| 描述 | Code quality fixes for Sub2API - P0/P1 issues | +| 用途 | 专门存放 Sub2API 项目的 P0/P1 级别代码质量修复 | +| 创建时间 | 2026-03-31 | + +**主要修复内容**: +- `ModelError.Is()` 精确匹配修复(避免 errors.Is 误判) +- `shouldClearStickySession` ctx 参数传播(修复 context.Background 导致的请求取消问题) +- `validateCodeSignature` 共享函数抽取(消除 promo_service.go 和 redeem_service.go 中的重复代码) +- TODO 存根返回 501 Not Implemented(而非假数据) +- 混合中英文错误消息统一为英文 +- 移除伪 if-else 代码 + +## 项目经验总结 + +### 开发注意事项 + +1. **Windows 特定**: + - Go 完整路径:`D:/Program Files/Go/bin/go.exe` + - Logger 测试因 zap Fsync() 超时,使用 `-skip "logger"` 跳过 + +2. **E2E 测试坑点**: + - API Key 路由是 `/api/v1/api-keys`(不是 `/api/v1/keys`) + - 余额调整 Payload:`{balance, operation, notes}` + - Rate Multiplier Payload:`{entries: [{user_id, rate_multiplier}]}` + - tests 目录在 .gitignore 中,需用 `git add -f tests/` 强制添加 + +3. **依赖注入**: + - 使用 Google Wire 进行依赖注入 + - 修改 wire.go 后运行 `go mod tidy` 确保依赖完整 + +### Gitea 远程仓库 + +| 属性 | 值 | +|------|-------| +| 地址 | https://www.tksea.top/pham/tokensea | +| 名称 | 字节海洋(tokensea) | +| 用户 | pham | + +## Project Planning Documents + +项目相关文档位置: +- **代码审查报告**: `REVIEW_REPORT_YYYY-MM-DD.md`(按日期生成) +- **开发指南**: `DEV_GUIDE.md` +- **README**: `README.md` / `README_CN.md`(中文) +- **长期记忆**: `.workbuddy/memory/MEMORY.md` diff --git a/DEV_GUIDE.md b/DEV_GUIDE.md index d0d362e0..f4b04b53 100644 --- a/DEV_GUIDE.md +++ b/DEV_GUIDE.md @@ -8,6 +8,8 @@ |------|------| | **上游仓库** | Wei-Shaw/sub2api | | **Fork 仓库** | bayma888/sub2api-bmai | +| **代码质量修复仓库** | tokens-reef (https://github.com/phamnazage-jpg/tokens-reef) | +| **Gitea 仓库** | https://www.tksea.top/pham/tokensea (字节海洋) | | **技术栈** | Go 后端 (Ent ORM + Gin) + Vue3 前端 (pnpm) | | **数据库** | PostgreSQL 16 + Redis | | **包管理** | 后端: go modules, 前端: **pnpm**(不是 npm) | @@ -243,6 +245,72 @@ git add ent/ # 生成的文件也要提交 - [ ] 所有 test stub 补全新接口方法(如果改了 interface) - [ ] Ent 生成的代码已提交(如果改了 schema) +--- + +### 坑 12:E2E 测试 API 路径必须与后端路由一致 + +**问题**:E2E 测试调用 `/api/v1/keys` 但后端路由是 `/api/v1/api-keys`,导致所有 API Key 测试返回 404。 + +**原因**:测试文件使用了与后端路由不匹配的 API 路径。 + +**后端路由**(`backend/internal/server/routes/user.go`): +```go +keys := authenticated.Group("/api-keys") // 注意是 api-keys,不是 keys +``` + +**解决**: +```bash +# 将所有 /api/v1/keys 改为 /api/v1/api-keys +sed -i 's|/api/v1/keys|/api/v1/api-keys|g' tests/e2e/*.spec.ts +``` + +--- + +### 坑 13:E2E 测试 Payload 必须与后端 DTO 一致 + +**问题**:测试使用的 Payload 与后端定义的 struct 不匹配,导致 400 错误。 + +**常见错误**: + +| 功能 | 错误 Payload | 正确 Payload | +|------|-------------|-------------| +| 余额调整 | `{amount, reason}` | `{balance, operation, notes}` | +| Rate Multiplier | `[{model, multiplier}]` | `{entries: [{user_id, rate_multiplier}]}` | + +**验证方法**: +```bash +# 查看后端 handler 中的 struct 定义 +grep -A 10 "type.*Request struct" backend/internal/handler/admin/*.go +``` + +--- + +### 坑 14:E2E 测试被 .gitignore 忽略 + +**问题**:`tests` 目录在 `.gitignore` 中,修改测试文件后无法直接 `git add`。 + +**解决**: +```bash +# 使用 -f 强制添加 +git add -f tests/ +git commit -m "fix: update E2E test API paths and payloads" +``` + +--- + +### 坑 15:Wire 依赖注入修改后需重新生成 + +**问题**:修改 `handler/wire.go` 后 Wire 生成失败。 + +**解决**: +```bash +cd backend +# 先运行 go mod tidy 确保依赖完整 +go mod tidy +# 然后手动检查 wire_gen.go 是否正确更新 +# Wire 自动生成的代码通常在 cmd/server/wire_gen.go +``` + ## 五、常用命令速查 ### 数据库操作 diff --git a/docs/PROJECT_EXPERIENCE.md b/docs/PROJECT_EXPERIENCE.md new file mode 100644 index 00000000..9faaa787 --- /dev/null +++ b/docs/PROJECT_EXPERIENCE.md @@ -0,0 +1,168 @@ +# Sub2API 项目经验总结 + +> 本文档记录项目开发过程中的经验教训、常见问题和解决方案。 + +## 一、项目架构 + +### 技术栈 +- **后端**:Go + Gin + Ent ORM +- **前端**:Vue 3 + Vite + Pinia + TailwindCSS +- **数据库**:PostgreSQL 16 + Redis +- **包管理**:Go modules + pnpm + +### 项目结构 +``` +sub2api/ +├── backend/ # Go 后端 +│ ├── cmd/server/ # 主程序入口 +│ ├── ent/ # Ent ORM 生成代码 +│ ├── internal/ +│ │ ├── handler/ # HTTP 处理器 +│ │ ├── service/ # 业务逻辑 +│ │ ├── repository/ # 数据访问层 +│ │ └── pkg/ # 公共包 +│ ├── migrations/ # 数据库迁移 +│ └── config.yaml # 配置文件 +├── frontend/ # Vue 前端 +├── tests/ # E2E 测试 +└── docs/ # 文档 +``` + +## 二、Git 仓库管理 + +### 当前仓库配置 + +| 远程 | 地址 | 用途 | +|------|------|------| +| origin | https://github.com/phamnazage-jpg/tokens-reef.git | GitHub(代码质量修复) | +| gitea | https://www.tksea.top/pham/tokensea.git | Gitea(主仓库) | + +### 常用命令 +```bash +# 添加 Gitea 远程 +git remote add gitea https://www.tksea.top/pham/tokensea.git + +# 强制推送到 Gitea(覆盖) +git push -f gitea main + +# 强制推送到 GitHub +git push -f origin main + +# 查看远程 +git remote -v +``` + +## 三、开发常见问题 + +### 1. E2E 测试问题 + +#### API 路径错误 +- **问题**:测试调用 `/api/v1/keys` 但后端路由是 `/api/v1/api-keys` +- **解决**:将所有路径改为 `/api/v1/api-keys` + +#### Payload 格式不匹配 +- **余额调整**:使用 `{balance, operation, notes}` +- **Rate Multiplier**:使用 `{entries: [{user_id, rate_multiplier}]}` + +#### 测试文件无法提交 +- **原因**:`tests` 目录在 `.gitignore` 中 +- **解决**:使用 `git add -f tests/` 强制添加 + +### 2. Go 后端问题 + +#### Wire 依赖注入 +- **修改 wire.go 后**:运行 `go mod tidy` 确保依赖完整 +- **生成代码位置**:`cmd/server/wire_gen.go` + +#### Interface 新增方法 +- **问题**:新增方法后编译失败 +- **解决**:所有实现该 interface 的 stub/mock 必须补上新方法 + +#### Ent Schema 修改 +- **命令**:`go generate ./ent` +- **生成文件**:需提交 `ent/` 目录 + +### 3. 前端问题 + +#### pnpm-lock.yaml 不同步 +- **问题**:CI 的 `pnpm install --frozen-lockfile` 失败 +- **解决**:确保 `pnpm-lock.yaml` 同步提交 + +#### node_modules 冲突 +- **解决**:删除后重新安装 +```bash +rm -rf node_modules +pnpm install +``` + +## 四、代码审查经验 + +### 审查维度 + +1. **功能正确性**:API 响应是否符合预期 +2. **性能**:是否有 OOM 风险、缓存策略 +3. **安全**:敏感信息是否硬编码 +4. **测试覆盖**:关键路径是否有测试 + +### 常见问题级别 + +| 级别 | 标记 | 说明 | +|------|------|------| +| P0 | 🔴 | 编译失败或致命运行时错误 | +| P1 | 🟡 | 功能缺陷或性能问题 | +| P2 | 🟢 | 改进建议 | +| 挑剔 | 💭 | 代码风格/文档问题 | + +### 修复验证流程 + +1. **本地构建**:`go build ./cmd/server` +2. **单元测试**:`go test -short ./...` +3. **前端构建**:`cd frontend && pnpm build` +4. **前端测试**:`cd frontend && pnpm test -- --run` +5. **E2E 测试**:确保后端运行在 8080 端口 + +## 五、关键配置 + +### Windows 开发环境 + +| 项 | 值 | +|---|---| +| Go 路径 | `D:/Program Files/Go/bin/go.exe` | +| PostgreSQL | `C:\Program Files\PostgreSQL\16\` | +| 测试账号 | lon22@qq.com / admin123 | +| 后端端口 | 8080 | + +### 测试环境变量 + +```bash +# E2E 测试 +BASE_URL=http://localhost:8080 +TEST_EMAIL=lon22@qq.com +TEST_PASSWORD=admin123 +``` + +## 六、经验教训 + +### 1. 测试必须验证真实 API 路径 +- 不要假设路由是什么,要去 `routes/*.go` 确认 +- E2E 测试调用前先手动 curl 验证 + +### 2. Payload 必须与后端 DTO 一致 +- 查看 handler 中的 struct 定义 +- 不要猜测字段名,用 grep 确认 + +### 3. 提交前务必本地验证 +- 编译通过 ≠ 测试通过 +- 测试通过 ≠ 功能正常 + +### 4. 文档要及时更新 +- 每次修复问题后更新 MEMORY.md +- 新增坑点更新 DEV_GUIDE.md +- 配置变更更新 CLAUDE.md + +## 七、相关文档 + +- `DEV_GUIDE.md` - 开发指南 +- `CLAUDE.md` - Claude Code 配置 +- `.workbuddy/memory/MEMORY.md` - 长期记忆 +- `REVIEW_REPORT_*.md` - 代码审查报告