Initial certificate system

This commit is contained in:
nelso
2026-06-06 19:32:24 +08:00
commit ce4ed6213b
105 changed files with 9133 additions and 0 deletions

102
docs/decision-log.md Normal file
View File

@@ -0,0 +1,102 @@
# 开发决策记录
本文档记录开发过程中由 Codex 先行拍板的实现决定。后续如果业务方有不同意见,可以按条目调整。
## 已确认决策
### D001 PDF 生成策略
- 决定PDF 由服务端生成,不在用户浏览器生成。
- 策略:按需生成 + 30 天缓存。
- 原因:证书属于正式凭证,服务端生成更利于统一版式、审计、作废状态控制和后续模板替换。
### D002 证书编号格式
- 决定:`EPX{YYYY}-{项目代码}-{7位短码}-{2位校验码}`
- 示例:`EPX2026-DBY-K7M9Q2R-83`
- 说明:内部数据库继续使用 `BIGINT` 主键,对外编号使用短码和校验码,降低枚举和手输错误风险。
### D003 公开查询方式
- 决定:一期公开查询支持两种方式:证书编号 + 姓名 + 图形验证码,或手机号 + 姓名 + 图形验证码。
- 说明:手机号 + 姓名可能匹配多张证书,查询结果按列表展示。
- 风控:继续保留图形验证码和基础频率限制,降低批量撞库风险。
### D004 作废证书 PDF
- 决定:一期作废证书不允许下载正常 PDF。
- 展示:查询页、直达页、二维码核验页统一显示作废状态。
### D005 证书模板
- 决定:一期先使用占位模板。
- 要求:模板文件与业务逻辑分离,后续替换 Logo、公章、排版、正式文案时不改核心业务代码。
### D006 更正和补发
- 决定:一期不实现复杂更正/补发流程。
- 一期保留证书编辑、作废、重置链接等主链路操作。
## Codex 先行决定
### C001 项目代码维护方式
- 决定:后台提供项目/课程代码配置,导入 Excel 使用项目代码匹配,不允许随意生成编号中的项目代码。
- 原因:避免同一项目出现多个拼写,确保证书编号稳定。
### C002 一期部署方式
- 决定:单机 Docker Compose 部署。
- 组件Nginx、前端静态资源、FastAPI 后端、MySQL。
- 原因:符合低并发和快速上线目标,减少运维复杂度。
### C003 文件目录
- 决定:使用 `/data/certificate-system/uploads``error-reports``exports``pdf-cache`
- 原因便于备份策略区分PDF 缓存不进入长期备份。
### C004 初始化管理员
- 决定:通过初始化命令创建第一个系统管理员。
- 原因:避免在公开页面暴露注册入口。
### C005 访问 token 一期存储
- 决定:一期在 `certificate_access_tokens` 中同时保存 token 哈希和 token 原值。
- 原因:后台导出必须能生成证书对外直达链接;纯哈希无法反推出链接。
- 风险:数据库泄露时 token 原值可被直接使用。
- 后续优化:将 token 原值改为应用层加密存储,或仅在生成时写入导出文件并提供链接重置机制。
### C006 验证码和限流
- 决定:一期使用后端进程内存保存图形验证码和简单 IP 频率计数。
- 原因:一期单机部署,不引入 Redis满足快速上线和低并发目标。
- 后续优化:访问量上来后迁移到 Redis并把限流前移到 Nginx 或网关层。
### C007 后台 UI 风格
- 决定:后台采用浅色、清爽、偏办公工具的视觉风格。
- 原因:这个系统是日常管理工具,用户需要快速查找和处理数据,不适合厚重的深色或营销化页面。
### C008 后台 PDF 下载方式
- 决定:后台证书 PDF 下载使用带 Authorization token 的 blob 请求。
- 原因:受保护的后台接口不能依赖普通链接跳转,否则浏览器不会带前端保存的登录 token容易导致下载失败。
### C009 Excel 导入字段
- 决定:导入模板只保留姓名、手机号、项目代码、发证日期。
- 原因:证书名称、课程名称、阶段名称、发证单位属于项目配置,不应该在每一行 Excel 里重复填写。
- 备注:导入备注字段一期移除;批量导入后的备注缺少明确展示和业务使用场景。
### C010 导入批次文件管理
- 决定:后台保留导入批次列表,并支持下载原始 Excel、下载错误报告、删除批次记录。
- 删除范围:只删除上传文件、错误报告和批次记录,不删除已经确认导入后生成的学员和证书。
- 原因:导入文件会占用服务器存储,但导入后的业务数据应作为正式数据继续保留。
### C011 Certificate Rendering Template
- Decision: keep `certificate-template-lab` as a standalone visual tuning page.
- Decision: production PDF rendering now uses the approved certificate image as the base layer, then renders learner/course/date/certificate number dynamically with Pillow.
- Current limitation: the data model only has `issue_date`; until separate training start/end dates are added, the rendered course date range uses `issue_date` for both start and end.
- Current limitation: mentor, issuer names, and QR area remain from the approved base image for visual consistency.