Files
beads-group/docs/server-report.md
T

49 lines
5.7 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.
# 服务端交付报告
实现目录:`perler-beads-server`,Go 1.25 + Gin + pgx PostgreSQL + Redis。全部 JSON 接口为 HTTP 200 与 `{code,msg,data}`;code=403 未登录、401 未授权。所有计划接口已经注册。打印成功为 SVG 下载。
## 启动
先启动 PostgreSQL 和 Redis,使用 `.env.example` 配置 `DATABASE_URL`、`REDIS_URL`、`ADMIN_USERNAME`、至少 12 字符的 `ADMIN_PASSWORD`、`APP_ENV`,再执行 `go run ./cmd/server`。应用不会自动读取 `.env`,请通过容器环境或 shell export 注入。生产环境必须提供 `WECHAT_APP_ID` 和 `WECHAT_APP_SECRET`;仅 `APP_ENV=development` 接受 `dev-guest`。开发登录是共享演示身份,不应用于真实顾客。
启动时执行内嵌幂等迁移 `internal/server/migrations/001_initial.sql`。`SEED_DEMO=true` 在没有门店时写入 store-001、两个启用桌位、四张原创 7×7 像素图纸和十种 DEMO 色号。演示地址、营业时间和色号必须在上线前替换。生产环境不提供内存数据库降级。
## 数据与权限
业务数据持久化 PostgreSQL;Redis 只保存随机令牌会话与登录限流。令牌 SHA-256 哈希作为 Redis 键,有效期七天。微信 code2Session 请求只在服务端执行,openid 派生稳定用户 ID,平台密钥不返回。管理员账号从环境获取。默认不信任 X-Forwarded-For,以免伪造 IP 绕过限流;部署在代理后登录限流按代理源 IP 聚合,请在真实网络压力验证中评估并配置可信代理支持。
图纸大小限制 200×200,色板最多 512 色;色号必须唯一、hex 必须六位十六进制,cells 数量必须匹配尺寸,所有非透明格必须引用已定义颜色。保存图纸必须匹配当前门店维护色板,物料位置由服务端权威数据回填。顾客保存只能 private,所有者才能删除;私有图纸访问验证身份,工作人员只能访问所属门店。后台账号当前属于 store-001,无跨店授权。
桌位必须存在且已启用。服务请求从有效到店会话读取门店与桌位,提交时再次校验桌位;打印请求必须引用有访问权限且属于当前门店的图纸。requestId UUID 由数据库主键持久保证幂等,同用户并发请求通过事务锁串行;相同键不同 kind/note/patternId 返回 code=409。重试返回原始创建结果。员工状态只能 pending→accepted→completed,顾客仅取消自己的 pending。状态更新使用行锁,避免并发覆盖。
SVG 标注毫米尺寸、网格色号、坐标、色量、50 mm 校准标尺,pitchMm 为 2–10。文字转义,图纸 ID 不拼接文件路径。临时文件下载后一分钟清理。超大图注明打印机海报/分页模式并保持 100% 缩放。服务请求是人工打印任务,不驱动硬件。支付与储值 capability 恒为 enabled=false。
## 验证
先写图纸校验、授权状态机、幂等内容散列测试,执行时出现 undefined Pattern/Transition/Fingerprint 的预期失败,再实施。随后增加匿名 API 权限、私有图纸门店隔离、SVG 尺寸与转义检查。
实际执行通过:
```sh
GOPATH=/tmp/perler-go GOCACHE=/tmp/perler-go-cache GOMODCACHE=/tmp/perler-go-mod go test ./...
GOPATH=/tmp/perler-go GOCACHE=/tmp/perler-go-cache GOMODCACHE=/tmp/perler-go-mod go vet ./...
GOPATH=/tmp/perler-go GOCACHE=/tmp/perler-go-cache GOMODCACHE=/tmp/perler-go-mod go build -o /tmp/perler-beads-server ./cmd/server
```
`TestPostgresPersistentIdempotency` 无 TEST_DATABASE_URL 时跳过。执行该测试必须使用数据库名包含 test 的独立数据库;它检查数据库唯一键且回滚数据。初期系统没有 Docker/PostgreSQL/Redis,随后主任务使用临时 PostgreSQL/Redis 启动真实联调环境;独立 perler_test 数据库的集成测试实际通过。微信真实凭据、生产 DNS/TLS 和打印设备仍未验证。
## 审查修复
- 服务请求事务内读取图纸与桌位改用同一 tx,避免单连接池等待自己占用的连接;收藏列表采用单次 JOIN 查询,避免 rows 未释放时嵌套借连接。
- 启用 Gin ContextWithFallback,统一给请求 context 设置 15 秒业务操作期限;数据库、Redis 与微信请求继承客户端取消。事务回滚使用独立 3 秒清理 context。
- SVG 页面宽度至少 100 mm,50 mm 标尺完全位于页内;长标题按字符宽度换行,打印提示分行。图纸网格仍精确保持 pitchMm。新增最小图纸在 2/5/10 mm 的尺寸与文本边界测试。
- 演示数据扩为十色及四个原创像素图案(心、菱形、小花、星),全部 DEMO 标识。已初始化的库不会被 seed 覆盖,需要独立新库查看新演示数据。
- 新增 TestSingleConnectionHandlers:独立 TEST_DATABASE_URL 下将 pool MaxConns=1,有限时地验证收藏、打印服务创建与幂等重试;无数据库时明确跳过。
- 修复后 go test ./...、go vet ./...、go build 全部再次通过;随后主任务已使用独立 perler_test 数据库实际执行并通过 PostgreSQL 集成测试。
## 最终补充
`WEBUI_DIR` 可配置为后台构建输出目录(需包含 index.html),后端直接提供静态文件及非 API GET/HEAD 深层路由 SPA 回退。未知 /api 与 /api/* 仍返回 HTTP200/code404 JSON。路径验证限制在输出目录内,拒绝目录穿越与指向目录外的符号链接;新增临时目录静态文件、SPA、API 和符号链接测试。
自定义异常恢复统一返回 HTTP200/code500 JSON。SVG 标题、尺寸说明与坐标分开预留行,色号字体按长度缩放以限制在格内。上述修改的 go test/vet/build 已通过;主任务随后已切换到更新后的二进制,并再次通过 23 项 API 联调断言及最终真实数据库回归。