Files
cmroubao/docs/03-tech-stack.md
T

165 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 技术栈
> “用什么”的权威速查表。状态为“待验证”的项不能在代码中当作既成事实。
## 技术栈一览
| 维度 | 选型 | 状态 | 说明 |
| --- | --- | --- | --- |
| Android 基础 | Roubao `main` 的 Kotlin 原生 Android 代码,应用版本 1.4.2 | 已接入并构建 | 固定 `main@c8a6d7f...`,来源与调整见 `android-buyer/UPSTREAM.md`。 |
| Android IDE/JDK | Android Studio Hedgehog 2023.1.1 或更高;JDK 17 | JDK/CLI 已验证,IDE 可选安装 | 命令行构建不依赖 Android Studio;首次用 IDE 导入时不接受自动升级。 |
| Android 构建链 | Gradle 8.2;AGP 8.2.0;Kotlin 1.9.20;JVM target 17 | 已验证 | 已补齐上游缺失的 `gradlew.bat`,不依赖全局 Gradle。 |
| Android SDK | compileSdk/targetSdk 34;minSdk 26;SDK Build Tools 34.0.0 | 已验证 | 支持 Android 8.0+;本机使用 Command-line Tools 22.0。 |
| Android UI | Jetpack Compose + Material 3;Compose Compiler 1.5.5 | 上游已核实 | Compose BOM 为 2023.10.01。 |
| Android 自动化 | `AccessibilityService` 语义节点动作;Shizuku 保留为上游兼容路径 | 搜索与 5 个候选已真机验证 | T-101/T-102 已完成精确输入、结果页确认、候选卡识别、详情截图和验证返回;没有坐标或 shell 降级。上游 `main` 仍保留 Shizuku 13.1.5。 |
| Android 候选证据 | API 30+ `AccessibilityService.takeScreenshot` + App cache JSON/PNG | 已真机验证 | 匿名 PNG 与只含 SHA-256、计数、尺寸的 manifest;转换/压缩使用独立 executor,文件 IO 使用 `Dispatchers.IO`。API 26-29 明确不支持该截图探针。 |
| 第一层任务源 | UTF-8 无 BOM 四行蝦皮订单文本 + 同订单号 JPEG | 已实现 | `task-contract` 共享 `ProbeTask/TaskSource`;CLI 输出到 `.local/`,只有显式 Debug 属性才注入 APK,默认构建会清除私有资产。 |
| Android 长任务 | 前台服务 + 持续通知 | T-207 已实现 | 30 秒 heartbeat、加密状态恢复、离线截止、`SAFE_STOPPED` 和加密结果 outbox。 |
| 后端语言 | Go 1.23.0 | MVP 已定 | 与现有本机工具链一致;构建测试必须设置 `GOTOOLCHAIN=local` 防止静默升级。 |
| 后端骨架 | Go Blueprint v0.10.11 生成的最小 Gin + SQLite 工程 | 已接入并收敛 | 只作为一次性脚手架输入;演示路由、默认 CORS、`.env` 自动加载、单例和 fatal 行为均已删除。 |
| 后端框架 | Gin v1.11.0 | MVP 已定 | 这是 `go.mod` 明确支持 Go 1.23.0 的最高已核实 Gin 版本。 |
| 数据访问 | 标准库 `database/sql` | MVP 已定 | 领域层通过仓储接口访问,避免先引入 ORM 和代码生成复杂度。 |
| 数据迁移 | Goose v3.26.0,使用嵌入式 SQL migration | 已验证 | v3.26.0 是已核实仍声明 Go 1.23.0 的最高版本;v3.27.x 要求 Go 1.25。 |
| 管理 Web | Gin + `html/template` + `embed` + 少量原生 JS/CSS | MVP 已定 | 不单独引入 SPA 工程,模板和静态资源随服务构建。 |
| 数据库 | SQLite | MVP 已定 | 单服务、单设备验证足够;多实例或并发提升前迁移 PostgreSQL。 |
| 图片/截图 | 后端受控本地文件目录 + `golang.org/x/image` v0.28.0 | 已验证 | JPEG/PNG/WebP 真解码后白底缩放并编码为 JPEG;数据库只存元数据和随机相对键。 |
| 管理鉴权 | bcrypt + 8 小时 opaque 服务端会话 Cookie | T-204 已验证 | `authctl` 预置 ADMIN;数据库只存密码 hash 与 session SHA-256,完整 RBAC 为 V2。 |
| App 鉴权 | BUYER 密码 + 预授权设备 secret + 1 小时 opaque token | T-204 已验证 | 首次原子绑定空闲设备;数据库只存 token SHA-256,不提供自助登记/refresh。 |
| VLM 接入 | Android 应用内统一适配器,优先兼容 OpenAI 风格多模态接口 | T-207 已实现,供应商待定 | 手机直连 provider;后端不代理模型;Key 使用 Keystore 加密存储,并回传非秘密 provenance。 |
| 离线执行 | 服务端运行授权 + Android 加密本地状态 | T-207 已实现 | 默认 30 分钟、5-120 分钟可配;30 秒 best-effort heartbeat,过期持久安全停止且 RUNNING 不自动重分配;结果通过加密 outbox 重放。 |
| 通知 | MVP 不使用推送 | 已定 | 点击“获取任务”调用原子 claim API;V2 再评估厂商推送/WebSocket。 |
| 后端测试 | 标准库 `testing` + `httptest` | T-206 已验证 | 当前含子测试 193 次覆盖配置、迁移、图片限制、任务事务、鉴权隔离、设备就绪、原子领取、幂等重放、有限离线租约、取消确认、跨连接与真实 TCP 并发。 |
| Android 测试 | Gradle `test` + `kotlinx-coroutines-test` 1.7.3 + MockWebServer 4.12.0 + 真实设备 smoke | T-206 已验证 | 184 次测试覆盖 runner、页面分类、VLM schema、人工确认、后台端点/JSON/图片同源契约和离线时钟;PKG110 完成私有 fixture/VLM mock 及后台登录、领取、95 秒断线、恢复、取消真机 smoke。 |
| 部署 | 单机局域网 Go 服务;容器化后置 | MVP 已定 | Android 测试机必须能通过 HTTPS 或受控测试网络访问。 |
## Roubao 上游版本基线
核实日期:2026-07-25。
| 项目 | 已核实值 |
| --- | --- |
| 上游仓库 | [`Turbo1123/roubao`](https://github.com/Turbo1123/roubao) |
| 许可证 | MIT |
| 默认分支 | `main` |
| 核实时 `main` commit | `c8a6d7f03422eb01744b01f3ee77bf7757741f7e` |
| `main` 应用版本 | 1.4.2(`versionCode 7`) |
| 开发 IDE | Android Studio Hedgehog 2023.1.1 或更高 |
| JDK / JVM target | 17 / 17 |
| Android SDK | compileSdk 34、targetSdk 34、minSdk 26 |
| SDK Build Tools | 34.0.0(AGP 8.2 官方兼容基线) |
| Gradle / AGP | 8.2 / 8.2.0 |
| Kotlin | 1.9.20 |
| Compose | Compose BOM 2023.10.01、Compiler 1.5.5、Material 3 |
| 自动化依赖 | Shizuku API/Provider 13.1.5 |
| 无障碍开发分支 | `roubao2.0+AccessibilityService`,核实时 commit `5b114c0a9476c359b27cfe994743fc7beb0a3554` |
上述版本已在 2026-07-25 使用 JDK 17.0.13、SDK 34 和 Build Tools 34.0.0 完成
Windows Debug 构建。上游无障碍分支落后于 `main` 的修复和 1.4.2 能力,因此不整体
切换分支;后续只选择性移植无障碍服务。
上游 Firebase 配置依赖未提交的 `google-services.json`,且第一层不需要遥测。
接入基线已移除 Google Services、Firebase Analytics/Crashlytics 及云端崩溃上报
设置,保留本地 `CrashHandler`,从而无需伪造或提交 Firebase 凭证。
## 关键决策
- 统一后端同时服务管理 Web 与 Android App;不是两套业务后端。
- 首版管理页面使用服务端渲染,避免在验证阶段维护独立前端构建链。
- Go Blueprint 只生成起始目录;正式代码必须删除演示逻辑,并按
`04-architecture.md` 的领域边界重组。
- SQLite 只服务单实例验证;出现多服务实例、并发写或正式备份要求时迁移 PostgreSQL。
- VLM 厂商可替换,领域层只接收结构化请求和结果,不传播供应商 SDK 类型。
- 需求提取与通用 MobileAgent 分离;只有声明 `supportsRequirementExtraction` 的
OpenAI 兼容 provider 可以进入 T-103 链路。
- 拼多多自动化是独立工作流模块,不能耦合后端数据库实现或管理页面。
## 骨架选择记录
- 来源:[`Melkeydev/go-blueprint`](https://github.com/Melkeydev/go-blueprint)
- 固定版本:`v0.10.11`(MIT)
- 生成目标:`Gin + SQLite`
- 不启用:React、HTMX、WebSocket、Redis、Docker 等高级特性
计划生成命令:
```powershell
go install github.com/melkeydev/go-blueprint@v0.10.11
go-blueprint create --name backend-api --framework gin --driver sqlite --git skip
```
Go Blueprint v0.10.11 当前生成的是 `Go 1.25.0 + Gin 1.12.0`,不能直接作为本项目
的 `go.mod`。2026-07-25 已在仓库外临时目录核实生成树,并把正式 `go.mod` 固定为:
```text
go 1.23.0
github.com/gin-gonic/gin v1.11.0
github.com/mattn/go-sqlite3 v1.14.48
github.com/pressly/goose/v3 v3.26.0
```
Gin v1.12.0 的 `go.mod` 要求 Go 1.25.0,因此本项目禁止升级到 Gin 1.12.x,除非先
单独批准升级 Go 工具链。正式接入还必须修正:
- 健康检查不得调用 `log.Fatal` 终止进程。
- 删除包级数据库单例和包加载阶段读取环境变量的写法。
- 关闭不需要的默认 CORS,不提交生成的 `.env`。
- 正确关闭数据库和 HTTP Server,注入 config/repository 以便测试。
- `mattn/go-sqlite3` 需要 CGO 和 GCC;构建环境必须显式验证。
不选择 `go-admin-team/go-admin`:Vue、多租户、Casbin RBAC、代码生成和定时任务
超出 MVP。不选择 `evrone/go-clean-template`:当前模板以 Fiber、PostgreSQL、
RabbitMQ、NATS 和 gRPC 为主,不符合最小 Gin + SQLite 边界。
## 计划目录
```text
android-buyer/ # 已接入的 Roubao Kotlin Android App
backend-api/
cmd/api/ # API 进程装配、信号和优雅关闭
cmd/migrate/ # 显式 migration up/down/status
internal/config/ # 环境变量和安全默认
internal/platform/database/ # SQLite 打开、pragma 和生命周期
internal/platform/migration/ # Goose provider 封装
internal/transport/httpapi/ # Gin 路由、健康检查和 HTTP Server
migrations/ # 嵌入式 Goose SQL migration
var/ # 本地运行数据,必须忽略
docs/
```
T-203 已建立 `domain/usecase/repository/sqlite` 和 `transport/webui`,handler 不直接
执行 SQL,Web 与 JSON API 复用同一 usecase。
T-205 已在该分层上增加独立 `LifecycleService` 与 SQLite immediate transaction,
固定 client-generated claim token、设备 readiness、CLAIMED/运行租约、execution、
安全取消和 task-scoped 参考图授权;当前 90 秒运行租约将在 T-206 扩展为默认
30 分钟有限离线授权,Android HTTP TaskSource 同时接入。
## 构建与运行命令
| 用途 | 命令 | 当前状态 |
| --- | --- | --- |
| Android 标准验证 | `.\init.ps1` | 已验证 |
| Android 构建 | `android-buyer\gradlew.bat assembleDebug --no-daemon` | 已验证 |
| Android 测试任务 | `android-buyer\gradlew.bat test --no-daemon` | 已验证;当前全工程 166 次测试通过 |
| Android 安装/启动 | `$env:RUN_START_COMMAND="1"; .\init.ps1` | 已在 Android 16 真机验证 |
| 后端依赖 | `$env:GOTOOLCHAIN="local"; go mod download`(在 `backend-api/`) | 已验证 |
| 后端测试 | `$env:GOTOOLCHAIN="local"; go test ./...; go test -race ./...; go vet ./...` | 已验证;192 个测试,全包 race 通过 |
| 后端构建 | `go build -o bin/cmroubao-api.exe ./cmd/api` 与 `./cmd/migrate` | 已验证 |
| 后端启动 | `go run ./cmd/api` | 已完成本机 HTTP smoke |
| 数据迁移 | `go run ./cmd/migrate up` | 已完成 `status/up/up/down/up` smoke |
`gradlew installDebug` 在当前 Android 16 设备上由旧版 AGP/ddmlib 返回 `-99`,
但 SDK Platform Tools 37.0.0 的 `adb install -r -t` 成功。标准脚本因此使用 SDK
内新版 ADB 安装,避免 PATH 中旧版 ADB 1.0.32。
## 依赖纪律
- 接入 Roubao 后优先使用其已有 HTTP、序列化、依赖注入和 UI 方案。
- 扩大 Shizuku 使用范围,或新增 OCR、浏览器自动化和第二套网络库前必须证明已有
能力不足。
- 后端新增库要说明用途;验证版不引入 ORM、消息队列、Redis、微服务或 SPA 框架。
- Go 依赖必须固定到 `go.mod`/`go.sum`;构建和 CI 不使用未固定的 `@latest`。
- `go.mod` 必须声明 `go 1.23.0`;验证使用 `GOTOOLCHAIN=local go test ./...` 或
PowerShell 等价环境变量,确保依赖没有暗中要求更高 Go 版本。
- handler 不直接写 SQL,repository 不依赖 Gin,domain/usecase 不导入具体数据库驱动。
- 密钥和设备令牌通过环境变量或本地忽略配置注入,不进入 Git。