继续更新 update 门户站点界面和功能
build-winui / winui (push) Has been cancelled

This commit is contained in:
QWQLwToo
2026-06-26 20:17:34 +08:00
parent f525e5f3ba
commit 2513eb2903
68 changed files with 5586 additions and 3195 deletions
@@ -0,0 +1,263 @@
# YMhut Unified Management Backend Architecture Review
## 结论
`server/unified-management` 目前已经具备统一服务的基本形态:一个 Go 后端同时承接旧版更新 JSON、下载、媒体源、反馈提交、新客户端 bootstrap、管理后台、SQLite/MySQL 存储和旧项目同步。现有 `go test ./...` 全部通过,说明核心兼容路由和主要模块有基本回归保障。
但当前实现仍属于“快速整合型单体”:`internal/web/router.go``internal/db/store.go` 承担了过多职责,后台能力已经铺开,但业务边界、数据访问边界、兼容适配边界还不够清晰。继续扩展前,应先把后台架构拆成稳定的分层单体,保留旧访问方式和旧反馈协议作为独立兼容层。
## 当前主要问题
1. 路由层过重
`internal/web/router.go` 同时处理公共门户、旧版路由、客户端 API、后台 API、静态资源、错误本地化、SSE、CSV 导出和文件下载。后续新增后台功能时,容易出现路径匹配顺序冲突、权限遗漏和响应结构不一致。
2. 数据层过重
`internal/db/store.go` 同时包含表结构迁移、实体定义、Repository、密码哈希、业务默认值、统计聚合、SQLite/MySQL failover、全表同步和旧原型 JSON 导入。它已经变成“全系统共享内核”,任何改动都容易影响多个业务域。
3. 兼容逻辑与新业务逻辑混杂
旧版 `update-info.json``media-types.json``tool-status.json``modules.json``/downloads/*` 和旧反馈 `POST /` 都是必须保留的外部契约,但现在它们和新 API 共享服务/存储细节,长期看会让新后台被旧 JSON 格式牵着走。
4. 安全策略需要后台化
当前有验证码、HttpOnly session cookie、CSRF、上传包校验和路径逃逸防护,这是好基础。但后台还需要更明确的密码策略、登录失败限流、会话持久化/吊销、审计事件规范、管理员角色模型。当前密码哈希是静态 SHA-256,建议迁移到 Argon2id 或 bcrypt。
5. 数据库双写/同步语义不清
配置里有 failover 和 hot sync 字段,但当前更接近手动全表复制和运行时 MySQL 失败回退 SQLite。需要明确“单主数据库、备份数据库、灾备同步”的关系,否则后台管理员很难判断哪些操作会覆盖数据。
6. 前端后台状态集中
`web/admin/src/App.vue` 集中了 API client、页面路由、全局状态、业务动作、表单转换、错误翻译和 SSE 连接。后台页面已经很多,建议拆成 `api/``stores/``features/`,否则维护体验会快速变差。
## 推荐后台架构
保持 Go 单体部署,但按边界拆成分层模块:
```text
cmd/unified-management
app/ # 进程启动、依赖组装、优雅退出
internal/http
middleware/ # auth、csrf、security headers、request id、rate limit
legacy/ # 旧访问方式适配器
clientapi/ # 新客户端 API
adminapi/ # 后台管理 API
setupapi/ # 首次初始化 API
static/ # admin/portal/setup 前端资源
internal/domain
feedback/ # 反馈工单聚合、状态流转、附件规则
releases/ # 发布包、版本公告、manifest
sources/ # 数据源目录、健康检查、调用日志
compatibility/ # 旧 JSON 文档模型和转换
audit/ # 审计事件
admin/ # 管理员、角色、会话
system/ # 健康检查、配置、数据库状态
internal/storage
migrations/ # schema 和版本迁移
repos/ # 按领域拆分 Repository
sqlstore/ # SQLite/MySQL 方言、连接、事务
sync/ # SQLite/MySQL 同步策略
internal/jobs
sourcecheck/ # 数据源健康检测
legacysync/ # 旧项目导入/同步
cleanup/ # 过期会话、旧日志、临时文件清理
internal/contracts
legacy/ # 旧客户端响应 DTO
client/ # 新客户端响应 DTO
admin/ # 后台响应 DTO
```
核心原则:
- `legacy` 只负责旧协议输入输出,不直接写业务表细节。
- `domain` 负责业务规则,不依赖 HTTP request/response。
- `storage` 负责持久化和事务,不包含业务默认文案、状态流转和 UI 语义。
- `adminapi` 是后台编排层,只调用 domain service,不直接拼 SQL。
- 所有对外 JSON 响应都定义 DTO,避免直接暴露数据库结构。
## 必须保留的旧版访问契约
这些路径应作为长期兼容 API,不随后台重构而改变:
| 旧版入口 | 当前用途 | 建议归属 |
| --- | --- | --- |
| `GET /update-info.json``GET /update-info` | 旧客户端更新信息 | `internal/http/legacy/update.go` |
| `GET /tool-status.json``GET /tool-status` | 旧工具状态 | `internal/http/legacy/static_json.go` |
| `GET /modules.json``GET /modules``GET /api/modules` | 旧模块配置 | `internal/http/legacy/static_json.go` |
| `GET /media-types.json``GET /media-types` | 旧媒体源目录 | `internal/http/legacy/media_types.go` |
| `GET /downloads/:filename` | 旧下载包 | `internal/http/legacy/downloads.go` |
| `POST /` | 旧反馈提交 | `internal/http/legacy/feedback.go` |
| `GET /?api=status&code=:code` | 旧反馈状态查询 | `internal/http/legacy/feedback.go` |
兼容层的响应字段应保持“只增不删、不改名、不改含义”。新后台可以增加内部字段,但旧接口输出必须通过 legacy DTO 过滤,避免把后台工单详情、内部备注、附件路径等泄漏给旧客户端。
## 旧版反馈兼容设计
旧反馈应当分为三个入口模型:
1. 简单 JSON 表单
兼容旧客户端或网页直接提交 `title/type/severity/contact/body/message`。服务端生成反馈码,返回旧状态结构。
2. 普通 multipart 表单
兼容旧表单字段 `title/subject/category/priority/message/description/email`。如果没有签名字段,按简单反馈处理。
3. 签名加密包 multipart
继续保留 `payload/timestamp/nonce/packageSha256/signature/package`。校验顺序固定为:请求大小 -> 时间窗 -> SHA256 格式 -> HMAC 签名 -> 加密包 magic -> 包哈希 -> 解密 -> zip 安全检查 -> 写入附件 -> 创建工单。
后台内部统一落到 `feedback_tickets` 聚合:
```text
legacy feedback request
-> LegacyFeedbackAdapter
-> FeedbackCommand(CreateTicket)
-> FeedbackService
-> FeedbackRepository + AttachmentStorage
-> LegacyFeedbackStatusDTO
```
旧状态查询只返回:
- `ok`
- `code`
- `status`
- `statusLabel`
- `statusDetail`
- `category`
- `priority`
- `hasReply`
- `reply`
- `receivedAt`
- `updatedAt`
- `mailSent`
- `duplicate`
不返回内部 `note``assignee``handledBy`、本地文件路径、审计日志、mail record。
## 后台管理能力设计
后台建议分为以下域:
1. 仪表盘
提供反馈数量、今日反馈、数据源总数、可见源数量、发布版本、数据库状态、最近心跳、最近客户端调用。只读,适合高频刷新。
2. 反馈工单
支持分页、筛选、搜索、状态流转、公开回复、内部备注、评论、标签、分派、优先级、SLA、附件查看、CSV 导出。状态流转应集中在 `FeedbackService`,不要由 Store 直接决定。
3. 发布管理
管理发布包上传、版本号、平台/架构、SHA256、manifest 生成、`update-info.json` 同步、版本公告保存、公告历史恢复。
4. 兼容 JSON
管理 `update-info.json``media-types.json`,提供验证、预览、保存、修订历史、恢复。该模块属于兼容层后台,不应成为新客户端的唯一数据来源。
5. 数据源目录
管理媒体/数据源、健康检测、客户端可见性、缓存时间、代理策略、调用日志。健康检测任务应进入 jobs 模块,并持久化任务结果。
6. 数据库与同步
明确 SQLite/MySQL 角色:推荐 SQLite 单机默认,MySQL 生产主库,SQLite 作为本地备份。后台按钮应显示方向、影响范围、覆盖风险和最后同步结果。
7. 系统设置
管理管理员密码、会话、旧项目路径、BaseURL、上传限制、签名密钥轮换、服务健康。
8. 审计日志
所有后台写操作、旧项目同步、发布包上传、JSON 恢复、密码修改都写入审计。审计事件统一字段:`actor/type/target/message/ip/userAgent/createdAt`
## 数据模型建议
将数据库实体按业务域拆分:
- `admin_users`
- `admin_sessions`
- `feedback_tickets`
- `feedback_comments`
- `feedback_attachments`
- `feedback_events`
- `release_packages`
- `release_notices`
- `release_notice_revisions`
- `legacy_json_revisions`
- `source_categories`
- `source_endpoints`
- `endpoint_health_checks`
- `endpoint_call_logs`
- `audit_logs`
- `database_sync_jobs`
- `legacy_sync_jobs`
建议新增:
- `schema_migrations`:记录数据库迁移版本。
- `admin_roles``admin_user_roles`:为后续多管理员预留。
- `settings`:保存可后台修改的配置项,和 `config.json` 做边界区分。
- `background_jobs`:统一记录旧同步、源检查、清理任务。
- `api_tokens`:为未来自动发布、CI 上传包、客户端管理接口预留。
## 改造优先级
第一阶段:稳住兼容契约
- 为旧版路径建立专门测试:`/update-info.json``/tool-status.json``/modules.json``/media-types.json``/downloads/*``POST /``/?api=status`
- 把旧响应结构固定为 DTO 测试快照。
- 给旧反馈三种提交方式分别补测试。
第二阶段:拆 HTTP 层
-`router.go` 拆成 `legacy_routes.go``client_routes.go``admin_feedback_routes.go``admin_release_routes.go``admin_source_routes.go``admin_system_routes.go``static_routes.go`
- 引入统一 `RouteGroup``http.ServeMux` 包装,避免一个巨大 switch 继续增长。
第三阶段:拆 Store
- 将实体移动到 `internal/domain/*``internal/contracts/*`
- 将 SQL 拆成 `FeedbackRepository``ReleaseRepository``SourceRepository``AuditRepository``AdminRepository`
- 将迁移、连接、failover、sync 从业务 repo 中拆出。
第四阶段:完善后台安全
- 密码哈希迁移到 Argon2id/bcrypt,并保留旧 SHA-256 登录后自动升级。
- 登录失败限流和验证码刷新频率限制。
- 会话持久化、会话吊销、Secure cookie 配置。
- 敏感配置和密钥不在 bootstrap 或日志中明文输出。
第五阶段:前端后台模块化
- `web/admin/src/api/*`:封装后台 API。
- `web/admin/src/stores/*`:按域拆状态。
- `web/admin/src/features/*`:按页面拆业务动作。
- `App.vue` 只保留壳层、导航、路由出口和全局 toast。
## 验证清单
当前已通过:
```powershell
go test ./...
```
后续每次重构必须至少验证:
- 旧版更新 JSON 路由仍返回 200 且字段不减少。
- 旧版反馈 `POST /` 能创建工单,重复反馈码返回 duplicate。
- 旧版反馈状态查询不泄漏内部字段。
- 管理后台写操作未登录返回 401,未带 CSRF 返回 403。
- 发布包上传拒绝路径逃逸和不支持扩展名。
- 数据源健康检测拒绝非 HTTP/HTTPS 重定向。
- SQLite 默认启动正常,MySQL 配置失败时 failover 行为明确。
- 旧项目同步 dry-run 不写数据,run 前有备份。