docs: merge dev tasks and doc requirements into unified agent brief

Single English document containing:
- Full 5-phase task breakdown (60+ tasks)
- Provider interface design and priority matrix
- API endpoint specifications
- Documentation requirements per task
- Testing requirements with examples
- Agent prompt instructions and commit rules
- Build and verification checklist

Signed-off-by: Boos4721 <boos4721@icloud.com>
This commit is contained in:
boos
2026-05-16 01:14:10 +08:00
parent 71a19cb863
commit 75acbab6c1
3 changed files with 746 additions and 451 deletions
-232
View File
@@ -1,232 +0,0 @@
# Go 后端重构 — 开发任务书
## 概述
将 BoosAPI 后端从 Node.js (Fastify/TypeScript) 重构为 Go。前端 (React SPA) 保持不变。
## 规模
- 后端源码文件:约 350+ .ts 文件(不含测试)
- API 端点:约 80+
- Provider 适配器:15+ 个平台
- Transformer 转换器:4 个协议(OpenAI、Anthropic、Gemini、Canonical)
## 开发原则
1. **API 兼容** — 所有端点 path/request/response 一致,前端零改动
2. **按协议推进** — 先 OpenAI(最常用)→ Anthropic → Gemini → Canonical
3. **测试先行** — 每个 handler 有 httptest
4. **增量替换** — Go binary 与 Node.js 可并存,逐步切流
5. **DB schema 兼容** — 复用现有 SQLite/MySQL/Postgres 表结构
---
## Phase 1:脚手架 ✅ 已完成
| 任务 | 状态 | 文件 |
|------|------|------|
| go mod init | ✅ | `go.mod` |
| 目录结构 | ✅ | `cmd/`, `internal/`, `pkg/` |
| 配置加载 | ✅ | `internal/config/config.go` — 全部环境变量 |
| 数据库连接 | ✅ | `internal/db/db.go` — SQLite/MySQL/Postgres |
| 迁移框架 | ✅ | `internal/db/migrate/000001_initial.up.sql` |
| Health Check | ✅ | `GET /healthz` — json + DB ping |
| 中间件 | ✅ | Logger、Auth(CORS)、Panic Recovery |
| chi 路由分组 | ✅ | `/admin`, `/v1`, `/api` |
| 优雅关闭 | ✅ | SIGINT/SIGTERM → graceful shutdown |
| Dockerfile | ✅ | 多阶段构建 ~20MB |
---
## Phase 2:Provider 核心代理(当前阶段)
### P2-A:HTTP 工具层
| # | 任务 | 文件 | 依赖 |
|---|------|------|------|
| 1 | SSE writer — `text/event-stream` 格式写入 | `pkg/httputil/sse.go` | — |
| 2 | HTTP 流式转发 — 将上游 stream 中继到客户端 | `pkg/httputil/stream.go` | 1 |
| 3 | HTTP 反向代理工具 — header 传递、URL 重写 | `pkg/httputil/proxy.go` | — |
| 4 | 共享 API 类型定义 | `pkg/types/api.go` | — |
### P2-B:Proxy Core 骨架
| # | 任务 | 文件 | 依赖 |
|---|------|------|------|
| 5 | Provider 接口定义:`Provider` interface | `internal/proxycore/provider.go` | 4 |
| 6 | 失败重试/降级策略 | `internal/proxycore/failover.go` | 5 |
| 7 | 通道选择与负载均衡 | `internal/proxycore/channel.go` | 5 |
| 8 | 核心编排器 `Orchestrator` | `internal/proxycore/orchestrator.go` | 5-7 |
| 9 | 请求构建:header 注入、URL 构建 | `internal/proxycore/request.go` | — |
### P2-C:OpenAI Provider
| # | 任务 | 文件 | 依赖 |
|---|------|------|------|
| 10 | Chat Completion 非流式 | `internal/provider/openai/chat.go` | 5, 9 |
| 11 | Chat Completion 流式 (SSE) | `internal/provider/openai/stream.go` | 1, 2, 10 |
| 12 | Models 列表 | `internal/provider/openai/models.go` | 5 |
| 13 | Images 生成/编辑 | `internal/provider/openai/images.go` | 5 |
| 14 | Embeddings | `internal/provider/openai/embeddings.go` | 5 |
| 15 | Audio (TTS/STT) | `internal/provider/openai/audio.go` | 5 |
| 16 | Files (上传/列表/内容) | `internal/provider/openai/files.go` | 5 |
| 17 | Responses API | `internal/provider/openai/responses.go` | 5, 9 |
### P2-D:Anthropic Provider
| # | 任务 | 文件 | 依赖 |
|---|------|------|------|
| 18 | Messages 非流式 | `internal/provider/anthropic/messages.go` | 5, 9 |
| 19 | Messages 流式 | `internal/provider/anthropic/stream.go` | 1, 2, 18 |
| 20 | 请求转换(OpenAI → Anthropic 格式) | `internal/transformer/anthropic/inbound.go` | — |
| 21 | 响应转换(Anthropic → OpenAI 格式) | `internal/transformer/anthropic/outbound.go` | — |
### P2-E:Gemini Provider
| # | 任务 | 文件 | 依赖 |
|---|------|------|------|
| 22 | Generate Content 非流式 | `internal/provider/gemini/content.go` | 5, 9 |
| 23 | Generate Content 流式 | `internal/provider/gemini/stream.go` | 1, 2, 22 |
| 24 | 请求转换(OpenAI → Gemini) | `internal/transformer/gemini/inbound.go` | — |
| 25 | 响应转换(Gemini → OpenAI) | `internal/transformer/gemini/outbound.go` | — |
### P2-F:Canonical 协议(用于多 provider 统一处理)
| # | 任务 | 文件 | 依赖 |
|---|------|------|------|
| 26 | Canonical Request 类型定义 | `internal/transformer/canonical/request.go` | — |
| 27 | Canonical Response 类型定义 | `internal/transformer/canonical/response.go` | — |
| 28 | Canonical → Provider 转换 | `internal/transformer/canonical/conversion.go` | 26-27 |
| 29 | Provider → Canonical 转换 | `internal/transformer/canonical/normalization.go` | 26-27 |
### P2-G:API 路由注册
| # | 任务 | 文件 | 依赖 |
|---|------|------|------|
| 30 | `/v1/chat/completions` | `internal/server/handler/chat.go` | 10, 11, 18, 19, 22, 23 |
| 31 | `/v1/models` | `internal/server/handler/models.go` | 12 |
| 32 | `/v1/images/*` | `internal/server/handler/images.go` | 13 |
| 33 | `/v1/embeddings` | `internal/server/handler/embeddings.go` | 14 |
| 34 | `/v1/audio/*` | `internal/server/handler/audio.go` | 15 |
| 35 | `/v1/files/*` | `internal/server/handler/files.go` | 16 |
| 36 | `/v1/responses` | `internal/server/handler/responses.go` | 17 |
| 37 | 路由统一注册 | `internal/server/router.go` | 30-36 |
---
## Phase 3:管理 API
| # | 任务 | 文件 | 依赖 |
|---|------|------|------|
| 38 | 管理员认证 (JWT + Bearer) | `internal/auth/jwt.go` | — |
| 39 | 用户 CRUD | `internal/server/handler/admin/users.go` | 38 |
| 40 | API Key 管理 | `internal/server/handler/admin/apikeys.go` | 38 |
| 41 | 站点管理 (上游 Provider 配置) | `internal/server/handler/admin/sites.go` | 38 |
| 42 | 账单/用量统计 | `internal/server/handler/admin/usage.go` | 38 |
| 43 | Token 路由配置 | `internal/server/handler/admin/routing.go` | 38 |
| 44 | 组织/团队管理 | `internal/server/handler/admin/orgs.go` | 38 |
| 45 | 设置页面 (数据库迁移、备份等) | `internal/server/handler/admin/settings.go` | 38 |
| 46 | 更新中心 (K3s/Helm) | `internal/server/handler/admin/update.go` | 38 |
---
## Phase 4:增值功能
| # | 任务 | 文件 | 依赖 |
|---|------|------|------|
| 47 | ComfyUI 反向代理 | `internal/server/handler/comfyui.go` | — |
| 48 | Video Agent (脚本→视频 pipeline) | `internal/server/handler/video_agent.go` | — |
| 49 | ComfyUI Agent SSE 对话 | `internal/server/handler/comfyui_agent.go` | 1 |
| 50 | 文件存储 (proxyFileStore) | `internal/services/filestore.go` | — |
| 51 | 搜索服务 | `internal/server/handler/search.go` | — |
---
## Phase 5:通知 + 运维
| # | 任务 | 文件 | 依赖 |
|---|------|------|------|
| 52 | 通知服务 (Telegram) | `internal/notify/telegram.go` | — |
| 53 | 通知服务 (企业微信/飞书/通用 Webhook) | `internal/notify/webhook.go` | — |
| 54 | 通知服务 (Bark/Server酱/SMTP) | `internal/notify/others.go` | — |
| 55 | 通知节流 (冷静期合并) | `internal/notify/throttle.go` | 52-54 |
| 56 | 桌面版后端适配 | `internal/desktop/adapter.go` | — |
| 57 | 桌面版 runtime 状态 API | `internal/server/handler/desktop.go` | 56 |
| 58 | OAuth Provider (Claude/Codex/Gemini) | `internal/oauth/provider.go` | — |
| 59 | OAuth 会话存储 | `internal/oauth/session.go` | 38 |
| 60 | 后台定时任务 (签到、模型探测、日志清理) | `internal/cron/scheduler.go` | — |
---
## API 兼容性要求
所有 Go handler 必须保持与现有 Node.js 相同的:
### 请求
- URL 路径
- HTTP Method
- Query 参数
- Request Body JSON 结构
- Header 名称
### 响应
- HTTP Status Code
- Response Body JSON 结构
- SSE 事件格式 (`data: {...}\n\n`)
- Error 格式 (`{"error": {...}}`)
- 速率限制 Header (`X-RateLimit-*`)
### 验证方法
```
curl -s http://localhost:4000/v1/models \
-H "Authorization: Bearer $PROXY_TOKEN" | jq .
# 返回格式必须与 Node.js 版一致
```
---
## Provider 优先级矩阵
| Provider | 优先级 | 使用量 | 复杂度 | 阶段 |
|----------|--------|--------|--------|------|
| OpenAI | P0 | 🔴🔴🔴 | 中 | Phase 2 |
| Anthropic | P0 | 🔴🔴🔴 | 高 (转换器) | Phase 2 |
| Google Gemini | P1 | 🟡🟡 | 高 (转换器) | Phase 2 |
| OneAPI/NewAPI | P1 | 🟡🟡 | 低 | Phase 3 |
| Claude (自有平台) | P1 | 🟡🟡 | 中 | Phase 3 |
| Codex | P2 | 🟢 | 中 | Phase 4 |
| VoAPI/RIX/Super | P2 | 🟢 | 低 | Phase 4 |
| Veloera/Sub2/DoneHub | P2 | 🟢 | 低 | Phase 4 |
---
## 测试策略
| 层级 | 工具 | 覆盖 |
|------|------|------|
| 单元测试 | `testing` | Provider 转换逻辑、工具函数 |
| Handler 测试 | `httptest` | 每个 API 端点 |
| 集成测试 | 自建 test suite | 完整请求→响应链路 |
| Provider 测试 | mock HTTP server | 模拟上游返回,验证转发正确性 |
| 兼容性测试 | 对照 Node.js 版输出 | 相同请求 → 相同响应 |
---
## 构建与发布
```bash
# 开发构建
CGO_ENABLED=0 go build -o boosapi ./cmd/boosapi/
# 生产构建 (带版本号)
CGO_ENABLED=0 go build -ldflags="-s -w -X main.version=$(git describe --tags --always)" \
-o boosapi ./cmd/boosapi/
# Docker 构建
docker build -f docker/Dockerfile -t boosapi:latest .
# 运行
./boosapi
# 或
docker run -p 4000:4000 boosapi:latest
```
-219
View File
@@ -1,219 +0,0 @@
# Go 后端重构 — 文档需求
## 文档目标
1. **开发者上手** — 5 分钟内能本地跑起来改代码
2. **架构可理解** — 新团队能看懂模块划分和请求链路
3. **API 兼容参考** — 前端/客户端开发者知道怎么调用
4. **运维可操作** — 部署、日志、监控、问题排查
---
## 一、开发者文档
### 1.1 README.md 更新
| 需求 | 内容 |
|------|------|
| 简介 | BoosAPI 是什么,Go 重构版 |
| 快速开始 | `go build ./cmd/boosapi` → `./boosapi` |
| 前置依赖 | Go 1.26+,SQLite 无需安装 |
| 环境变量 | 简表(AUTH_TOKEN、PROXY_TOKEN、PORT、DB_TYPE、DB_URL) |
| 示例命令 | 用 `curl` 验证 `/healthz` 和 `/v1/models` |
### 1.2 CONTRIBUTING.md
| 需求 | 内容 |
|------|------|
| 分支策略 | `refactor/go-backend` → `main` |
| 编码规范 | Go 标准 `gofmt`、`go vet`、无 lint 警告 |
| 提交规范 | Conventional Commits:`feat:` `fix:` `refactor:` `docs:` `test:` |
| PR 流程 | 每个 Phase 先开 PR review |
| 测试要求 | 新 handler 必须有 httptest;改逻辑不能降低覆盖率 |
### 1.3 GoDoc 注释
| 需求 | 内容 |
|------|------|
| 每个 export 函数 | 一行注释说明作用 |
| 每个 export 类型 | 说明用途和字段含义 |
| Package 注释 | `package db` — 简短说明包职责 |
| Handler 注释 | 说明对应的 API 端点和行为 |
**示例:**
```go
// Package provider defines the Provider interface for upstream AI API backends.
//
// Each provider (OpenAI, Anthropic, Gemini) implements this interface to
// support chat completions, streaming, and other capabilities through
// a unified abstraction.
package provider
```
---
## 二、架构文档
### 2.1 架构概览
**位置:** `docs/architecture.md`
| 需求 | 内容 |
|------|------|
| 整体架构图 | ASCII 或 mermaid 图:前端 → 路由 → 代理核心 → Provider |
| 请求生命周期 | 从 HTTP 入站到上游响应回来的完整路径 |
| 模块边界 | `proxycore`、`provider`、`transformer`、`handler` 的职责 |
| 关键数据流 | SSE 流式请求/响应、WebSocket 传输路径 |
### 2.2 Provider 适配器设计
**位置:** `docs/provider-architecture.md`
| 需求 | 内容 |
|------|------|
| Provider 接口定义 | Go interface + 方法签名 |
| Provider 注册机制 | 如何添加新的 Provider |
| 转换器模式 | Inbound/Outbound converter 模式说明 |
| 支持列表 | 当前已支持的 Provider 和对应基准 URL |
### 2.3 数据库 Schema
**位置:** `docs/database.md`
| 需求 | 内容 |
|------|------|
| ER 图 | mermaid `erDiagram` |
| 表结构 | 每张表的字段、类型、索引、外键 |
| 迁移流程 | 新增字段/表的操作步骤 |
| 兼容性 | SQLite / MySQL / PostgreSQL 差异 |
---
## 三、API 文档
### 3.1 管理 API
**位置:** `docs/management-api.md`(已有,需更新)
| 端点 | 方法 | 说明 |
|------|------|------|
| `/admin/users` | GET/POST | 用户列表/创建 |
| `/admin/users/:id` | GET/PUT/DELETE | 用户详情/更新/删除 |
| `/admin/api-keys` | GET/POST | API Key 管理 |
| `/admin/sites` | GET/POST | 上游站点管理 |
| `/admin/usage` | GET | 用量统计 |
| `/admin/settings` | GET/PUT | 系统设置 |
| `/admin/update-center` | GET/POST | K3s 更新中心 |
| `/admin/backup` | POST | 手动备份 |
### 3.2 代理 API(OpenAI 兼容)
| 端点 | 方法 | 说明 |
|------|------|------|
| `/v1/chat/completions` | POST | Chat 补全(流式+非流式) |
| `/v1/models` | GET | 模型列表 |
| `/v1/images/generations` | POST | 图片生成 |
| `/v1/images/edits` | POST | 图片编辑 |
| `/v1/embeddings` | POST | 向量嵌入 |
| `/v1/audio/transcriptions` | POST | 语音转文字 |
| `/v1/audio/translations` | POST | 语音翻译 |
| `/v1/audio/speech` | POST | 文字转语音 |
| `/v1/files` | GET/POST | 文件管理 |
| `/v1/files/:id` | GET/DELETE | 文件详情 |
| `/v1/files/:id/content` | GET | 文件内容 |
| `/v1/responses` | POST | Responses API |
### 3.3 自定义 API
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/comfyui/prompt` | POST | ComfyUI 工作流执行 |
| `/api/comfyui/history` | GET | ComfyUI 历史 |
| `/api/comfyui/view` | GET | ComfyUI 图片查看 |
| `/api/comfyui/proxy/ui*` | GET | ComfyUI UI 代理 |
| `/api/video-agent/*` | POST | 视频生成 Agent |
| `/api/comfyui-agent/chat` | POST | ComfyUI 对话助手 (SSE) |
| `/api/search` | POST | 搜索 |
| `/api/events` | GET | SSE 事件流 |
| `/api/auth/*` | POST | 登录/认证 |
---
## 四、运维文档
### 4.1 部署文档(已有,需更新)
**位置:** `docs/deployment.md`
| 需求 | 说明 |
|------|------|
| Docker 镜像 | 从 Go 构建改为多阶段,体积变化 |
| 环境变量 | 所有 BoosAPI 环境变量(更新 BOOSAPI_*) |
| Docker Compose | 示例更新为 Go 版本镜像 |
| 健康检查 | `/healthz` 端点使用说明 |
| 资源要求 | Go binary 内存/CPU 需求 |
### 4.2 运维手册(已有,需更新)
**位置:** `docs/operations.md`
| 需求 | 说明 |
|------|------|
| 日志 | Go slog 输出格式与日志级别 |
| 监控 | 健康检查、prometheus/metrics |
| 故障排查 | 常见错误和排查步骤 |
| 备份恢复 | SQLite/MySQL/Postgres 备份命令 |
### 4.3 CLI 参数
| 参数 | 说明 |
|------|------|
| `-h` / `--help` | 帮助 |
| `-version` | 版本号 |
| `-config` | 配置文件路径(可选) |
---
## 五、GoDoc 发布(可选)
| 需求 | 工具 |
|------|------|
| 在线 GoDoc | `pkg.go.dev/github.com/cita-777/boosapi` |
| 本地生成 | `go doc ./...` |
---
## 文档模板
每个 Go package 的 README 模板:
`````markdown
# package `<name>`
`package <name>` 提供了...
## 用法
```go
import "github.com/cita-777/boosapi/internal/<path>"
```
## 类型
### `<TypeName>`
```go
type TypeName struct {
Field1 Type `json:"field1"`
Field2 Type `json:"field2"`
}
```
## 函数
### `<FuncName>`
```go
func FuncName(param Type) (ResultType, error)
```
`````
+746
View File
@@ -0,0 +1,746 @@
# BoosAPI Go Backend Rewrite — Agent Development Brief
You are a senior Go developer tasked with rewriting the BoosAPI backend from Node.js/Fastify/TypeScript to Go. The frontend (React SPA) and database schema remain unchanged.
## Repository
- **Branch:** `refactor/go-backend`
- **Remote:** `gitea` (`https://git.boos.lat/boos/BoosAPI.git`)
- **Go version:** 1.26
- **Module:** `github.com/cita-777/boosapi`
## Golden Rules
1. **API compatibility first.** Every endpoint path, HTTP method, request body, response JSON, SSE event format, and error shape must match the existing Node.js implementation exactly. Frontend must work with zero changes.
2. **Test before claim.** Every handler must have an `httptest` test. Every provider must have a mock HTTP server test. Run `go test ./...` and `go vet ./...` before committing.
3. **One phase at a time.** Complete all tasks in the current phase before moving to the next.
4. **Phase 1 is done.** Do not touch Phase 1 files unless fixing a bug.
5. **Commit convention:** `feat:` for new functionality, `fix:` for bugs, `refactor:` for restructuring, `docs:` for documentation, `test:` for tests. Always sign off: `Signed-off-by: Boos4721 <boos4721@icloud.com>`
6. **Go standard:** `gofmt`, `go vet`, no lint warnings. Use stdlib where possible.
---
## Architecture
```
┌──────────────────┐
│ React SPA │
│ (unchanged) │
└────────┬─────────┘
│ HTTP / SSE / WebSocket
┌────────▼─────────┐
│ Go Backend │
│ (net/http + chi) │
│ │
│ ┌───────────┐ │
│ │ chi Router │ │
│ └─────┬─────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ Proxy │ │
│ │ Core │ │
│ └─────┬─────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ Providers │ │
│ │ (interfce)│ │
│ └─────┬─────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ DB Layer │ │
│ │ (sql.DB) │ │
│ └───────────┘ │
└──────────────────┘
```
### Directory Layout
```
cmd/boosapi/main.go # Entry point (Phase 1 done, do not touch)
internal/
config/config.go # Env var loader (Phase 1 done)
db/db.go # DB connection + migration runner (Phase 1 done)
db/migrate/ # SQL migration files (Phase 1 done)
server/
router.go # Route registration (extend as you add handlers)
middleware/middleware.go # Auth, CORS, Logger, Recover (Phase 1 done)
handler/ # HTTP handlers
health.go # GET /healthz (Phase 1 done)
chat.go # POST /v1/chat/completions
models.go # GET /v1/models
images.go # POST /v1/images/*
embeddings.go # POST /v1/embeddings
audio.go # POST /v1/audio/*
files.go # GET/POST /v1/files/*
responses.go # POST /v1/responses
comfyui.go # ComfyUI reverse proxy
video_agent.go # Video generation agent
comfyui_agent.go # ComfyUI conversational agent (SSE)
search.go # POST /api/search
admin/ # Admin handlers
users.go
apikeys.go
sites.go
usage.go
routing.go
orgs.go
settings.go
update.go
proxycore/
provider.go # Provider interface
orchestrator.go # Core orchestrator (route, failover, fallback)
channel.go # Channel selection + load balancing
request.go # Request building (headers, URL)
failover.go # Retry + degradation strategy
provider/
openai/
chat.go # Chat completion (non-streaming)
stream.go # Chat completion (SSE streaming)
models.go # Models list
images.go # Image generation/edits
embeddings.go # Embeddings
audio.go # TTS/STT
files.go # File upload/list/content
responses.go # Responses API
anthropic/
messages.go # Messages (non-streaming)
stream.go # Messages (SSE streaming)
gemini/
content.go # Generate content (non-streaming)
stream.go # Generate content (SSE streaming)
transformer/
canonical/
request.go # Canonical request type
response.go # Canonical response type
conversion.go # Canonical ↔ Provider conversion
anthropic/
inbound.go # OpenAI → Anthropic request conversion
outbound.go # Anthropic → OpenAI response conversion
gemini/
inbound.go # OpenAI → Gemini request conversion
outbound.go # Gemini → OpenAI response conversion
auth/
jwt.go # JWT generation + validation
session.go # Session store
notify/
telegram.go # Telegram bot notification
webhook.go # Webhook (WeChat/Feishu/generic)
others.go # Bark, ServerChan, SMTP
throttle.go # Cooldown merging
oauth/
provider.go # OAuth provider interface
session.go # OAuth session storage
codex.go # Codex OAuth
claude.go # Claude OAuth
gemini.go # Gemini OAuth
cron/
scheduler.go # Background job scheduler
desktop/
adapter.go # Electron desktop backend adapter
runtime.go # Desktop runtime status
services/
filestore.go # Proxy file storage
search.go # Search service
pkg/
httputil/
sse.go # SSE writer utilities
stream.go # HTTP streaming relay
proxy.go # HTTP reverse proxy tools
types/
api.go # Shared API types
```
---
## Phase 2: Provider Core Proxy
### P2-A: HTTP Utility Layer
#### Task 1: SSE Writer (`pkg/httputil/sse.go`)
Create a helper for Server-Sent Events over `http.ResponseWriter`.
```go
package httputil
// SSEWriter wraps http.ResponseWriter for SSE streaming.
type SSEWriter struct {
w http.ResponseWriter
flusher http.Flusher
done <-chan struct{} // for client disconnect detection
}
func NewSSEWriter(w http.ResponseWriter) (*SSEWriter, error)
func (s *SSEWriter) WriteEvent(eventType string, data []byte) error
func (s *SSEWriter) WriteJSON(eventType string, v interface{}) error
func (s *SSEWriter) Done() <-chan struct{}
```
- Set `Content-Type: text/event-stream`, `Cache-Control: no-cache`, `Connection: keep-alive`
- Each event: `data: {json}\n\n`
- Must detect client disconnection via `r.Context().Done()`
- Must flush after each event
#### Task 2: HTTP Stream Relay (`pkg/httputil/stream.go`)
Relay an upstream SSE/streaming response to a downstream `SSEWriter`.
```go
// RelayStream copies an upstream streaming response to w. It handles
// chunked transfer from an *http.Response body and forwards data.
func RelayStream(ctx context.Context, dst *SSEWriter, src *http.Response) error
```
- Copy bytes from `src.Body` to `dst`
- Stop when context is cancelled (client disconnect)
- Close `src.Body` when done
#### Task 3: HTTP Proxy Utilities (`pkg/httputil/proxy.go`)
```go
// CopyHeaders copies headers from src to dst.
func CopyHeaders(dst, src http.Header)
// ForwardedHeaderSet builds the X-Forwarded-* headers.
func ForwardedHeaderSet(r *http.Request, host string) http.Header
```
#### Task 4: Shared Types (`pkg/types/api.go`)
Define shared request/response types used across the application:
- `ChatRequest`, `ChatMessage`, `ChatChoice`
- `StreamChoice`, `Delta`
- `Model`, `ModelList`
- `ErrorResponse`, `Usage`
- `ImageRequest`, `ImageResponse`
- `EmbeddingRequest`, `EmbeddingResponse`
- `AudioRequest`, `AudioResponse`
- `FileObject`, `FileList`
- `APIResponse`, `PaginatedResponse`
- SSE event types: `TextEvent`, `ImageEvent`, `CharacterPrompts`, `SceneEvent`, `TTSEvent`, `WorkflowEvent`, `DoneEvent`
### P2-B: Proxy Core Skeleton
#### Task 5: Provider Interface (`internal/proxycore/provider.go`)
Define the core `Provider` interface:
```go
// Provider defines the interface for upstream AI API backends.
type Provider interface {
// Name returns the provider identifier (e.g., "openai", "anthropic").
Name() string
// ChatCompletion sends a non-streaming chat completion request.
ChatCompletion(ctx context.Context, req *ChatRequest) (*ChatResponse, error)
// ChatCompletionStream sends a streaming chat completion request.
// Returns a channel of StreamEvents.
ChatCompletionStream(ctx context.Context, req *ChatRequest) (<-chan StreamEvent, error)
// Models returns the list of available models from this provider.
Models(ctx context.Context) ([]Model, error)
}
```
Start minimal. Only add methods that are actually implemented. The interface will grow as providers are added.
#### Task 6: Failover Strategy (`internal/proxycore/failover.go`)
```go
// FailoverPolicy defines how to handle upstream failures.
type FailoverPolicy struct {
MaxRetries int
RetryDelay time.Duration
FallbackOrder []string // provider names in fallback order
}
// ShouldRetry determines if a request should be retried based on the error.
func ShouldRetry(err error, attempt int) bool
```
#### Task 7: Channel Selection (`internal/proxycore/channel.go`)
```go
// ChannelSelector picks the best upstream channel for a given model request.
type ChannelSelector struct {
// ...
}
func (s *ChannelSelector) Select(ctx context.Context, model string, preferProvider string) (*ProviderChannel, error)
```
- Weighted random selection based on site priority and weight
- Skip disabled/cooldown sites
- Return error if no channel is available
#### Task 8: Core Orchestrator (`internal/proxycore/orchestrator.go`)
```go
// Orchestrator manages the full lifecycle of a proxy request.
type Orchestrator struct {
selector *ChannelSelector
failover *FailoverPolicy
registry *ProviderRegistry
}
func NewOrchestrator(selector *ChannelSelector, failover *FailoverPolicy, registry *ProviderRegistry) *Orchestrator
// Execute handles a proxy request: select channel, call provider, handle failover.
func (o *Orchestrator) Execute(ctx context.Context, req *ProxyRequest) (*ProxyResponse, error)
// ExecuteStream handles a streaming proxy request.
func (o *Orchestrator) ExecuteStream(ctx context.Context, req *ProxyRequest) (<-chan StreamEvent, error)
```
#### Task 9: Request Builder (`internal/proxycore/request.go`)
```go
// BuildUpstreamRequest constructs an HTTP request to the upstream provider.
// Injects headers (x-boosapi-*, authorization, user-agent, content-type).
// Handles URL construction, query parameters, body serialization.
func BuildUpstreamRequest(ctx context.Context, channel *ProviderChannel, body []byte) (*http.Request, error)
```
- Inject `Content-Type: application/json`
- Set `Authorization: Bearer <channel API key>`
- Pass through `x-boosapi-*` headers from downstream
- Handle streaming vs non-streaming content type
### P2-C: OpenAI Provider
#### Task 10: Chat Completion Non-Streaming (`internal/provider/openai/chat.go`)
```go
type Provider struct {
baseURL string
httpClient *http.Client
}
func (p *Provider) ChatCompletion(ctx context.Context, req *ChatRequest) (*ChatResponse, error)
```
- POST `{baseURL}/v1/chat/completions`
- Map `ChatRequest` → OpenAI request JSON
- Parse OpenAI response JSON → `ChatResponse`
- Handle errors (4xx, 5xx, rate limits)
#### Task 11: Chat Completion Streaming (`internal/provider/openai/stream.go`)
```go
func (p *Provider) ChatCompletionStream(ctx context.Context, req *ChatRequest) (<-chan StreamEvent, error)
```
- POST `{baseURL}/v1/chat/completions` with `stream: true`
- Parse SSE `data: {...}` lines
- Each line → `StreamEvent`
- On `[DONE]` → close channel
- Use `httputil.SSEWriter` for downstream forwarding
#### Task 12: Models (`internal/provider/openai/models.go`)
```go
func (p *Provider) Models(ctx context.Context) ([]Model, error)
```
- GET `{baseURL}/v1/models`
- Parse response, return model list
#### Task 13: Images (`internal/provider/openai/images.go`)
```go
func (p *Provider) GenerateImage(ctx context.Context, req *ImageRequest) (*ImageResponse, error)
func (p *Provider) EditImage(ctx context.Context, req *ImageEditRequest) (*ImageResponse, error)
```
- POST `{baseURL}/v1/images/generations`
- POST `{baseURL}/v1/images/edits` (multipart form)
#### Task 14: Embeddings (`internal/provider/openai/embeddings.go`)
```go
func (p *Provider) CreateEmbedding(ctx context.Context, req *EmbeddingRequest) (*EmbeddingResponse, error)
```
#### Task 15: Audio (`internal/provider/openai/audio.go`)
```go
func (p *Provider) CreateTranscription(ctx context.Context, req *AudioRequest) (*AudioResponse, error)
func (p *Provider) CreateTranslation(ctx context.Context, req *AudioRequest) (*AudioResponse, error)
func (p *Provider) CreateSpeech(ctx context.Context, req *TTSRequest) (*http.Response, error)
```
- Transcriptions/Translations: multipart form POST
- Speech: JSON POST, return raw audio binary
#### Task 16: Files (`internal/provider/openai/files.go`)
```go
func (p *Provider) ListFiles(ctx context.Context) ([]FileObject, error)
func (p *Provider) UploadFile(ctx context.Context, file *FileUpload) (*FileObject, error)
func (p *Provider) GetFile(ctx context.Context, fileID string) (*FileObject, error)
func (p *Provider) GetFileContent(ctx context.Context, fileID string) (io.ReadCloser, error)
func (p *Provider) DeleteFile(ctx context.Context, fileID string) error
```
#### Task 17: Responses API (`internal/provider/openai/responses.go`)
```go
type ResponsesProvider struct {
// wraps Provider for POST /v1/responses
}
func (p *ResponsesProvider) CreateResponse(ctx context.Context, req *ResponsesRequest) (*ResponsesResponse, error)
```
### P2-D: Anthropic Provider
#### Task 18: Messages Non-Streaming (`internal/provider/anthropic/messages.go`)
Implement Anthropic Messages API format.
```go
type Provider struct {
baseURL string
httpClient *http.Client
}
func (p *Provider) Messages(ctx context.Context, req *AnthropicMessagesRequest) (*AnthropicMessagesResponse, error)
```
- POST `{baseURL}/v1/messages`
- Anthropic-specific request/response types
- Handle `x-api-key` header auth
#### Task 19: Messages Streaming (`internal/provider/anthropic/stream.go`)
```go
func (p *Provider) MessagesStream(ctx context.Context, req *AnthropicMessagesRequest) (<-chan AnthropicStreamEvent, error)
```
- POST with `stream: true`
- Parse Anthropic SSE format (`event: message_start`, `event: content_block_delta`, etc.)
- Convert to unified StreamEvent
### P2-E: Gemini Provider
#### Task 22: Generate Content Non-Streaming (`internal/provider/gemini/content.go`)
Implement Google Gemini GenerateContent API.
```go
type Provider struct {
baseURL string
httpClient *http.Client
}
func (p *Provider) GenerateContent(ctx context.Context, req *GeminiRequest) (*GeminiResponse, error)
```
- POST `{baseURL}/v1beta/models/{model}:generateContent`
- Gemini-specific request/response types
- API key as query param
#### Task 23: Generate Content Streaming (`internal/provider/gemini/stream.go`)
```go
func (p *Provider) GenerateContentStream(ctx context.Context, req *GeminiRequest) (<-chan GeminiStreamEvent, error)
```
### P2-F: Canonical Protocol Transformers
#### Task 26: Canonical Types (`internal/transformer/canonical/request.go`, `response.go`)
Define provider-agnostic request/response types that all providers convert to/from:
```go
type CanonicalRequest struct {
Model string
Messages []CanonicalMessage
Stream bool
MaxTokens int
Temperature float64
// ... other common parameters
}
type CanonicalResponse struct {
ID string
Model string
Choices []CanonicalChoice
Usage *Usage
}
```
#### Task 27: Conversions (`internal/transformer/canonical/conversion.go`)
```go
// ToOpenAI converts a canonical request to OpenAI format.
func ToOpenAI(req *CanonicalRequest) (*OpenAIChatRequest, error)
// FromOpenAIResponse converts an OpenAI response to canonical format.
func FromOpenAIResponse(resp *OpenAIChatResponse) (*CanonicalResponse, error)
// ToAnthropic, FromAnthropicResponse, ToGemini, FromGeminiResponse...
```
### P2-G: API Route Registration
#### Task 30-37: Handlers + Router
Create handler files under `internal/server/handler/` and register routes in `internal/server/router.go`.
**Chat handler** (`handler/chat.go`):
```go
type ChatHandler struct {
orchestrator *proxycore.Orchestrator
}
func (h *ChatHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
```
- Parse `ChatRequest` from body
- If `stream: true` → use SSE streaming path
- If `stream: false` → use non-streaming path
- Return OpenAI-compatible response format
**Router** (`server/router.go`):
```go
func RegisterRoutes(r chi.Router, deps *Dependencies) {
// /v1 routes (proxy token protected)
r.Route("/v1", func(r chi.Router) {
r.Use(middleware.ProxyToken(deps.Config.ProxyToken))
r.Post("/chat/completions", deps.ChatHandler.ServeHTTP)
r.Get("/models", deps.ModelsHandler.ServeHTTP)
r.Post("/images/generations", deps.ImagesHandler.Generate)
// ...
})
// /api routes
r.Route("/api", func(r chi.Router) {
r.Post("/comfyui-agent/chat", deps.ComfyUIAgentHandler.ServeHTTP)
// ...
})
// /admin routes (auth token protected)
r.Route("/admin", func(r chi.Router) {
r.Use(middleware.AuthToken(deps.Config.AuthToken))
// ...
})
}
```
---
## Phase 3: Management API
#### Task 38: JWT Auth (`internal/auth/jwt.go`)
Implement JWT token generation and validation for admin sessions.
```go
func GenerateToken(secret string, userID string, role string) (string, error)
func ValidateToken(secret string, tokenString string) (*Claims, error)
```
#### Task 39-46: Admin Handlers
Each handler follows this pattern:
```go
type UsersHandler struct {
db *sql.DB
}
func (h *UsersHandler) List(w http.ResponseWriter, r *http.Request) // GET /admin/users
func (h *UsersHandler) Get(w http.ResponseWriter, r *http.Request) // GET /admin/users/{id}
func (h *UsersHandler) Create(w http.ResponseWriter, r *http.Request) // POST /admin/users
func (h *UsersHandler) Update(w http.ResponseWriter, r *http.Request) // PUT /admin/users/{id}
func (h *UsersHandler) Delete(w http.ResponseWriter, r *http.Request) // DELETE /admin/users/{id}
```
Required admin endpoints:
| Route | Handler | SQL Query |
|-------|---------|-----------|
| `GET /admin/users` | `UsersHandler.List` | `SELECT * FROM users ORDER BY created_at DESC` |
| `POST /admin/users` | `UsersHandler.Create` | `INSERT INTO users ...` |
| `GET /admin/users/{id}` | `UsersHandler.Get` | `SELECT * FROM users WHERE id = ?` |
| `PUT /admin/users/{id}` | `UsersHandler.Update` | `UPDATE users SET ... WHERE id = ?` |
| `DELETE /admin/users/{id}` | `UsersHandler.Delete` | `DELETE FROM users WHERE id = ?` |
| `GET /admin/api-keys` | `APIKeysHandler.List` | `SELECT * FROM api_keys` |
| `POST /admin/api-keys` | `APIKeysHandler.Create` | `INSERT INTO api_keys ...` |
| `GET /admin/sites` | `SitesHandler.List` | `SELECT * FROM sites ORDER BY priority DESC` |
| `POST /admin/sites` | `SitesHandler.Create` | `INSERT INTO sites ...` |
| `PUT /admin/sites/{id}` | `SitesHandler.Update` | `UPDATE sites SET ... WHERE id = ?` |
| `DELETE /admin/sites/{id}` | `SitesHandler.Delete` | `DELETE FROM sites WHERE id = ?` |
| `GET /admin/usage` | `UsageHandler.Summary` | `SELECT ... FROM usage_logs GROUP BY ...` |
| `GET /admin/settings` | `SettingsHandler.Get` | Application settings |
| `PUT /admin/settings` | `SettingsHandler.Update` | Application settings |
---
## Phase 4: Value-Added Features
#### Task 47: ComfyUI Proxy (`internal/server/handler/comfyui.go`)
Reverse proxy for ComfyUI (port 8188). Key endpoints:
- `POST /api/comfyui/prompt` → `POST /prompt`
- `GET /api/comfyui/history` → `GET /history`
- `GET /api/comfyui/view` → `GET /view`
- `GET /api/comfyui/proxy/ui*` → `GET /*` (with HTML rewriting)
#### Task 48: Video Agent (`internal/server/handler/video_agent.go`)
One-shot script → video pipeline. Uses the gateway's own `/v1/chat/completions` and `/v1/images/generations` and `/v1/audio/speech`.
Endpoints:
- `POST /api/video-agent/analyze`
- `POST /api/video-agent/character-prompts`
- `POST /api/video-agent/generate-character`
- `POST /api/video-agent/scene-prompt`
- `POST /api/video-agent/generate-tts`
- `POST /api/video-agent/full-workflow`
#### Task 49: ComfyUI Agent SSE Chat (`internal/server/handler/comfyui_agent.go`)
Conversational agent using SSE streaming. The LLM generates structured SSE events directly.
- `POST /api/comfyui-agent/chat` — receives user message, streams agent response
- System prompt instructs LLM to emit SSE-formatted output
- Event types: `text`, `character_prompts`, `image`, `scene`, `tts`, `comfyui_workflow`, `done`
---
## Phase 5: Notifications + Operations
#### Task 52-55: Notification Service (`internal/notify/`)
Multi-channel notification dispatch with cooldown merging.
| Channel | Config key | Delivery |
|---------|-----------|----------|
| Telegram | `telegramEnabled`, `telegramBotToken`, `telegramChatId` | Bot API |
| WeChat Work | `wecom*` | Webhook |
| Feishu | `feishu*` | Webhook |
| Generic Webhook | `webhookUrl` | JSON POST |
| Bark | `bark*` | HTTP (iOS) |
| ServerChan | `serverchan*` | HTTP |
| SMTP | `smtp*` | Email |
#### Task 58-59: OAuth (`internal/oauth/`)
Provider OAuth flows for Claude, Codex, Gemini:
```go
// OAuthProvider handles the OAuth flow for an AI platform.
type OAuthProvider interface {
AuthURL(state string) string
ExchangeCode(ctx context.Context, code string) (*OAuthToken, error)
RefreshToken(ctx context.Context, refreshToken string) (*OAuthToken, error)
}
```
---
## Documentation Requirements
Each task must include appropriate documentation:
### Code-Level Documentation
- Every exported Go function must have a doc comment
- Every exported type must have a doc comment
- Every package must have a `package` doc comment
Example:
```go
// Package provider defines the Provider interface for upstream AI API backends.
//
// Each provider (OpenAI, Anthropic, Gemini) implements this interface to
// support chat completions, streaming, and other capabilities through
// a unified abstraction.
package provider
```
### API Documentation
When adding a new handler, document the endpoint in the handler file:
```go
// POST /v1/chat/completions
//
// Creates a model response for the given chat conversation.
// Supports both streaming (SSE) and non-streaming responses.
//
// Request: ChatRequest
// Response (non-streaming): ChatResponse
// Response (streaming): SSE events of StreamChoice
//
// Errors:
// 400 - Invalid request body
// 401 - Missing or invalid API key
// 429 - Rate limited
// 500 - Upstream error
```
### User-Facing Documentation
Update the relevant doc files under `docs/` when adding significant functionality:
- `docs/deployment.md` — Environment variables, Docker setup
- `docs/operations.md` — Log format, health checks, troubleshooting
- `docs/management-api.md` — Admin API reference
- `docs/architecture.md` — Architecture overview (create if missing)
---
## Testing Requirements
Every handler must have a test:
```go
func TestChatHandler_NonStreaming(t *testing.T) {
// Setup mock server for upstream
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(openai.ChatResponse{...})
}))
defer upstream.Close()
// Setup handler with mock upstream URL
handler := NewChatHandler(&Config{UpstreamBaseURL: upstream.URL})
// Create request
body := `{"model":"gpt-4","messages":[{"role":"user","content":"hi"}]}`
req := httptest.NewRequest("POST", "/v1/chat/completions", strings.NewReader(body))
req.Header.Set("Authorization", "Bearer test-token")
rec := httptest.NewRecorder()
// Serve
handler.ServeHTTP(rec, req)
// Assert
assert.Equal(t, http.StatusOK, rec.Code)
var resp ChatResponse
json.Unmarshal(rec.Body.Bytes(), &resp)
assert.Equal(t, "gpt-4", resp.Model)
}
```
### Test Coverage Targets
- Provider packages: 80%+ (mock HTTP server)
- Handler packages: 80%+ (httptest)
- Transformer packages: 90%+ (pure function tests)
- Utility packages: 90%+
- Overall project: 70%+
---
## Provider Implementation Priority
| Provider | Priority | Complexity | When |
|----------|----------|-----------|------|
| OpenAI (Chat, Models) | P0 | Medium | Phase 2-A |
| OpenAI (Images, Embeddings, Audio, Files) | P0 | Low-Medium | Phase 2-A |
| Anthropic Messages | P0 | High (different auth, streaming format) | Phase 2-B |
| Google Gemini | P1 | High (different API structure) | Phase 2-C |
| OneAPI / NewAPI | P1 | Low (OpenAI-compatible) | Phase 3 |
| Claude Platform | P1 | Medium | Phase 3 |
| Codex | P2 | Medium | Phase 4 |
| VoAPI / RIX / Super | P2 | Low | Phase 4 |
| Veloera / Sub2 / DoneHub | P2 | Low | Phase 4 |
---
## Build & Run
```bash
# Build
CGO_ENABLED=0 go build -o boosapi ./cmd/boosapi/
# Run
AUTH_TOKEN=admin PROXY_TOKEN=proxy ./boosapi
# Test
go test ./... -v -count=1
# Vet
go vet ./...
# Docker
docker build -f docker/Dockerfile -t boosapi:latest .
docker run -p 4000:4000 -e AUTH_TOKEN=admin -e PROXY_TOKEN=proxy boosapi:latest
```
## Before Committing
1. `go vet ./...` — zero warnings
2. `go test ./...` — all tests pass
3. `gofmt -s -w .` — code is formatted
4. `git diff --cached` — review for secrets (no real IPs, tokens, passwords)
5. Commit message follows convention: `feat:`, `fix:`, `refactor:`, `docs:`, `test:`
6. Sign off: `Signed-off-by: Boos4721 <boos4721@icloud.com>`