100 lines
9.7 KiB
Markdown
100 lines
9.7 KiB
Markdown
---
|
||||
|
|
id: T-405
|
|||
|
|
title: 采购工具 Windows 打包与运行文档
|
|||
|
|
phase: 4
|
|||
|
|
deps: [T-401]
|
|||
|
|
status: TODO
|
|||
|
|
created: 2026-08-04
|
|||
|
|
vikunja_task_id: 53
|
|||
|
|
context_ref: 8600c33
|
|||
|
|
work_branch: task/t-405-windows-package
|
|||
|
|
needs_device: false
|
|||
|
|
needs_human_review: true
|
|||
|
|
write_paths:
|
|||
|
|
- docs/tasks/T-405.md
|
|||
|
|
- client/pyproject.toml
|
|||
|
|
- client/requirements-build.txt
|
|||
|
|
- client/cmbuyer-client.spec
|
|||
|
|
- client/scripts/build_windows.ps1
|
|||
|
|
- client/scripts/verify_windows_bundle.py
|
|||
|
|
- client/tests/test_windows_packaging.py
|
|||
|
|
- client/README.md
|
|||
|
|
- docs/03-tech-stack.md
|
|||
|
|
- .gitignore
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<!-- BEGIN VIKUNJA EXPORT id=53 synced=2026-08-04T15:16:24Z sha256=31032aac3c37c9992ba7ce04a5bb3cac406b2e8cef54106eeb9213d2c7b75e91 -->
|
|||
|
|
## 问题 / 背景
|
|||
|
|
|
|||
|
|
T-401 完成生产接线和首次真实提交人工验收后,采购工具仍需转换为运营电脑可解压运行、可追溯到准确源码、构建环境实际依赖和可检查内容的 Windows 交付包。T-405 使用 PyInstaller 生成 onedir 目录并封装 ZIP,提供构建、运行时依赖清单、校验、运行、升级与卸载文档;打包和验收不连接 Android 设备,不执行采购、提交或付款。
|
|||
|
|
|
|||
|
|
## 关联需求与交互
|
|||
|
|
|
|||
|
|
- 功能:F-005、F-013 的 Windows 交付运行部分。
|
|||
|
|
- 用户故事:US-003、US-007、US-008。
|
|||
|
|
- 交互:IX-007、IX-008;保持“采购工具”名称、固定双 Tab 和安全退出语义。
|
|||
|
|
- 依赖:T-401;只打包已经完成人工安全验收的生产 composition。
|
|||
|
|
- 后续消费者:T-404 完整 MVP 验收。
|
|||
|
|
- needs_device=false;构建、内容检查和无设备启动测试不得连接 ADB 或拼多多。
|
|||
|
|
|
|||
|
|
## 方案
|
|||
|
|
|
|||
|
|
1. 新增独立 build requirements,固定兼容的 PyInstaller 版本;运行时依赖继续只由 requirements.txt / wheel metadata 管理,不把 PyInstaller 作为运营时依赖或在应用启动时下载组件。
|
|||
|
|
2. 维护显式 PyInstaller spec,生成 windowed onedir 包。入口唯一为 cmbuyer_client.app:main,只收集运行必需的 PySide6/uiautomator2/adbutils/Pillow 模块、Qt/Shiboken 运行库和已知资源;不使用任意目录收集、隐藏执行脚本或下载器。
|
|||
|
|
3. PowerShell 构建脚本从仓库根解析并校验精确 client 目录、Python 3.11+ venv、干净的显式输出目录和当前 commit;只清理已验证位于 client 构建输出下的目录,不对仓库根、用户目录、LOCALAPPDATA 或未解析变量执行递归删除。
|
|||
|
|
4. 构建前从已安装 wheel metadata/requirements 解析全部直接运行时依赖的规范名称和实际版本,不能只读取未锁定的需求表达式。至少显式探测 PySide6、Qt runtime、Shiboken6、uiautomator2、adbutils、Pillow;Qt 版本必须来自实际 Qt runtime,其他版本来自当前构建环境中实际解析的 distribution/runtime,而不是手写常量。
|
|||
|
|
5. 构建产物为版本化 onedir 目录和其 ZIP;生成不含秘密的 manifest,记录产品/版本、git commit、Python/PyInstaller 版本、构建 UTC、入口、ZIP SHA-256,以及上述全部直接运行时依赖和 Qt/Shiboken 组件的规范名称、实际版本与探测来源。未锁依赖因此仍可追溯,但不得声称字节级可复现。
|
|||
|
|
6. PyInstaller spec 必须保留校验所需的 distribution metadata/Qt runtime 事实。校验器分别从构建环境和实际 onedir/ZIP 内解析依赖集合与版本,要求和 manifest 精确一致;缺依赖、漏记直接依赖、版本不一致、无法探测或只相信 manifest 自报都必须失败,不发布 ZIP。
|
|||
|
|
7. bundle 内容校验显式拒绝 vikunja.env、任何 .env/token、client-state.sqlite3/WAL/SHM、LOCALAPPDATA 状态、日志、artifacts、截图、XML、业务 evidence manifest、tests/fixture、__pycache__、源码仓库元数据和支付凭据。交付依赖 manifest 是允许的专用构建元数据,不能混入业务证据。
|
|||
|
|
8. 校验器检查 ZIP 防路径穿越、文件清单、入口 EXE、关键依赖、重复/绝对路径、最大体积边界、SHA-256 和依赖版本;不得仅以 PyInstaller 退出码 0、requirements 约束或版本文件存在声称可交付。
|
|||
|
|
9. 运行文档固定“解压整个目录后运行”,说明采购服务精确 loopback、ADB 路径/serial 人工配置、设备 token 安全录入、运行数据位于 %LOCALAPPDATA%/cmbuyer、日志/状态位置和常见错误。不得要求复制 vikunja.env、源码、Python 或开发 venv。
|
|||
|
|
10. 升级只替换应用目录,先退出应用并保留 %LOCALAPPDATA%/cmbuyer;卸载只删除明确的应用解压目录,不自动删除状态、日志或证据。需要清理本地数据时必须另行人工确认精确路径。
|
|||
|
|
11. 在脱离源码目录、未安装 Python 的 Windows 测试环境解压并启动,检查产品名、双 Tab、配置/错误提示和安全关闭;测试使用空闲/无设备配置,零 claim、零 ADB、零真机动作、零提交。
|
|||
|
|
12. 不在 MVP 内实现安装器、自动更新、代码签名服务或后台常驻。若产物未签名,文档如实说明 Windows 提示与人工核验 SHA-256、commit 和依赖版本 manifest 的步骤,不能诱导绕过安全软件。
|
|||
|
|
|
|||
|
|
## 验收要点
|
|||
|
|
|
|||
|
|
- 构建脚本在合规 Windows venv 生成唯一 onedir ZIP 和 manifest;manifest 枚举 wheel metadata/requirements 中全部直接运行时依赖的实际版本,并至少包含 PySide6、Qt、Shiboken6、uiautomator2、adbutils、Pillow、Python、PyInstaller 与 git commit。
|
|||
|
|
- 构建环境探测结果、实际 onedir/ZIP 内 distribution metadata/Qt runtime 和 manifest 三方逐项一致;漏项、未知项、版本漂移、无法从 bundle 复核或伪造 manifest 均使校验失败。
|
|||
|
|
- 重复构建记录各自 commit、完整实际依赖版本集合和产物 SHA-256;依赖未锁时仍能追溯本次解析结果,但不声称字节级可复现。
|
|||
|
|
- 内容负例向 staging 注入 env/token、SQLite/WAL、日志、PNG/XML、tests/fixture、绝对/穿越路径时校验均失败且不发布 ZIP。
|
|||
|
|
- ZIP 解压后目录外无写入;应用所有状态仍进入 %LOCALAPPDATA%/cmbuyer,不污染安装目录或源码树。
|
|||
|
|
- 在无源码、无 Python 的 Windows 环境启动成功;产品名/双 Tab/配置错误/关闭路径可用,且无设备时零 claim、零 ADB、零提交、零付款。
|
|||
|
|
- 文档覆盖构建、SHA-256/commit/依赖版本核验、解压运行、配置、升级、卸载、日志和故障排查;明确系统只创建待付款订单且不付款。
|
|||
|
|
- 运行 client unittest、compileall、wheel metadata、打包专用测试、完整 init、上下文、Vikunja export 与 diff-check;记录产物绝对路径与 SHA-256,但不把 ZIP、manifest 中的本机秘密或构建目录提交 Git。
|
|||
|
|
- needs_human_review:运营电脑人工检查解压、启动、文档、Windows 安全提示、SHA-256 和依赖版本 manifest;确认前保持 DOING。
|
|||
|
|
|
|||
|
|
## 执行记录
|
|||
|
|
|
|||
|
|
(暂无)
|
|||
|
|
<!-- END VIKUNJA EXPORT -->
|
|||
|
|
|
|||
|
|
## 边界
|
|||
|
|
|
|||
|
|
- 只交付 PyInstaller `windowed onedir` 目录及其版本化 ZIP,不在本任务引入安装器、自动更新、后台
|
|||
|
|
常驻、下载器或代码签名服务。未签名时必须如实说明 Windows 提示和 SHA-256 人工核验步骤,
|
|||
|
|
不得指导绕过安全软件。
|
|||
|
|
- PyInstaller 只作为固定版本的构建依赖,不能进入运营时依赖或由应用启动时联网安装。运行时依赖
|
|||
|
|
仍以 `requirements.txt` / wheel metadata 为唯一声明来源,不维护第二份手写依赖清单;manifest
|
|||
|
|
必须记录本次构建环境实际解析并打入 bundle 的版本,不能只复制未锁定的版本约束。
|
|||
|
|
- bundle 和 ZIP 绝不能包含 `vikunja.env`、任何 `.env`/token、设备/claim 凭据、本地 SQLite/
|
|||
|
|
WAL/SHM、配置状态、日志、artifacts、截图、XML、证据 manifest、tests/fixture、源码仓库元数据、
|
|||
|
|
支付凭据或本机绝对路径。发现拒绝项必须失败且不发布产物。
|
|||
|
|
- 构建脚本只能清理已经解析并验证位于 `client` 构建输出目录下的精确路径;不得对仓库根、用户目录、
|
|||
|
|
`%LOCALAPPDATA%`、空变量、通配目标或未经验证的计算路径执行递归删除。
|
|||
|
|
- 交付 manifest 必须记录产品/版本、git commit、Python/PyInstaller、UTC、入口、产物 SHA-256,
|
|||
|
|
以及 wheel metadata/requirements 中**全部直接运行时依赖**的规范名称、实际解析版本和探测来源;
|
|||
|
|
至少显式包含 `PySide6`、实际 Qt runtime、`Shiboken6`、`uiautomator2`、`adbutils`、`Pillow`。
|
|||
|
|
Qt 必须从实际 runtime 探测,其余必须来自当前构建 distribution/runtime,不能使用手写常量。
|
|||
|
|
- 校验器必须分别从构建环境和实际 onedir/ZIP 内的 distribution metadata、Qt runtime/组件文件核对
|
|||
|
|
完整依赖集合与版本,并要求与 manifest 精确一致。漏项、版本漂移、无法从 bundle 复核或只信任
|
|||
|
|
manifest 自报都必须失败且不发布 ZIP;PyInstaller spec 必须保留完成该核对所需的最小 metadata。
|
|||
|
|
- manifest 不记录 token、设备 serial、用户名、业务数据或证据路径。依赖未锁时,实际版本集合用于
|
|||
|
|
追溯本次构建,但仍不得宣称字节级可复现;版本号或文件名不能替代 SHA-256/commit 证明。
|
|||
|
|
- 运行、升级和卸载不得自动删除 `%LOCALAPPDATA%/cmbuyer`。升级只替换明确的应用目录;清理状态、
|
|||
|
|
日志或证据必须另行由人确认精确路径,不能作为卸载脚本副作用。
|
|||
|
|
- 构建与验收 `needs_device: false`:不得连接 ADB、启动拼多多、领取真实任务、执行页面动作、提交
|
|||
|
|
订单或付款。无源码/无 Python 环境的启动验收使用空闲配置,保持零 claim、零真机动作。
|
|||
|
|
- 本任务不修改 T-401 提交安全逻辑,不增加支付、免密支付、先用后付或任何扣款能力。
|
|||
|
|
`needs_human_review: true`,运营电脑人工核验 ZIP、文档、启动和 SHA-256 前不得标 `DONE`。
|