Files
QWQLwToo 2513eb2903
build-winui / winui (push) Has been cancelled
继续更新 update 门户站点界面和功能
2026-06-26 20:17:48 +08:00

11 KiB

YMhut Unified Management Backend Architecture Review

结论

server/unified-management 目前已经具备统一服务的基本形态:一个 Go 后端同时承接旧版更新 JSON、下载、媒体源、反馈提交、新客户端 bootstrap、管理后台、SQLite/MySQL 存储和旧项目同步。现有 go test ./... 全部通过,说明核心兼容路由和主要模块有基本回归保障。

但当前实现仍属于“快速整合型单体”:internal/web/router.gointernal/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.jsonmedia-types.jsontool-status.jsonmodules.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 单体部署,但按边界拆成分层模块:

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.jsonGET /update-info 旧客户端更新信息 internal/http/legacy/update.go
GET /tool-status.jsonGET /tool-status 旧工具状态 internal/http/legacy/static_json.go
GET /modules.jsonGET /modulesGET /api/modules 旧模块配置 internal/http/legacy/static_json.go
GET /media-types.jsonGET /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 聚合:

legacy feedback request
  -> LegacyFeedbackAdapter
  -> FeedbackCommand(CreateTicket)
  -> FeedbackService
  -> FeedbackRepository + AttachmentStorage
  -> LegacyFeedbackStatusDTO

旧状态查询只返回:

  • ok
  • code
  • status
  • statusLabel
  • statusDetail
  • category
  • priority
  • hasReply
  • reply
  • receivedAt
  • updatedAt
  • mailSent
  • duplicate

不返回内部 noteassigneehandledBy、本地文件路径、审计日志、mail record。

后台管理能力设计

后台建议分为以下域:

  1. 仪表盘

    提供反馈数量、今日反馈、数据源总数、可见源数量、发布版本、数据库状态、最近心跳、最近客户端调用。只读,适合高频刷新。

  2. 反馈工单

    支持分页、筛选、搜索、状态流转、公开回复、内部备注、评论、标签、分派、优先级、SLA、附件查看、CSV 导出。状态流转应集中在 FeedbackService,不要由 Store 直接决定。

  3. 发布管理

    管理发布包上传、版本号、平台/架构、SHA256、manifest 生成、update-info.json 同步、版本公告保存、公告历史恢复。

  4. 兼容 JSON

    管理 update-info.jsonmedia-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_rolesadmin_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.goclient_routes.goadmin_feedback_routes.goadmin_release_routes.goadmin_source_routes.goadmin_system_routes.gostatic_routes.go
  • 引入统一 RouteGrouphttp.ServeMux 包装,避免一个巨大 switch 继续增长。

第三阶段:拆 Store

  • 将实体移动到 internal/domain/*internal/contracts/*
  • 将 SQL 拆成 FeedbackRepositoryReleaseRepositorySourceRepositoryAuditRepositoryAdminRepository
  • 将迁移、连接、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。

验证清单

当前已通过:

go test ./...

后续每次重构必须至少验证:

  • 旧版更新 JSON 路由仍返回 200 且字段不减少。
  • 旧版反馈 POST / 能创建工单,重复反馈码返回 duplicate。
  • 旧版反馈状态查询不泄漏内部字段。
  • 管理后台写操作未登录返回 401,未带 CSRF 返回 403。
  • 发布包上传拒绝路径逃逸和不支持扩展名。
  • 数据源健康检测拒绝非 HTTP/HTTPS 重定向。
  • SQLite 默认启动正常,MySQL 配置失败时 failover 行为明确。
  • 旧项目同步 dry-run 不写数据,run 前有备份。