项目问题分析与修复方案.md 14 KB

智慧停车项目问题分析与修复方案

分析日期:2026-09-07
分析范围:lc_garage 实际源码、配置、前端构建、项目文档与 Git 历史
结论性质:代码与配置静态审查 + 可执行构建验证,不替代真实闸机、打印机、摄像头和支付终端的现场验收。

1. 结论摘要

项目已经完成从旧的 GIN-VUE-ADMIN 服务端形态向 Wails 单进程桌面应用的主要迁移,并具备停车场配置、停车会话、数字票、支付流水、月卡、交接班、报表、打印和异常处置等基础模块。当前代码也已经出现 internal/modules 领域模块化结构,说明迁移正在持续进行。

距离可稳定交付仍有三类问题:

  1. 生产安全边界不够明确:上传、Swagger、监控和中央缴费机入口的公开性需要逐项确认;默认账号、敏感配置和调试能力仍应纳入发布安全策略。
  2. 设备和资金业务闭环不足:真实支付、道闸反馈、打印失败补偿、摄像头识别、LED 余位屏、备份恢复和对账仍有明显缺口。
  3. 文档和工程入口存在漂移:根目录 AGENTS.md、旧版 PROJECT.mdlc_garage/README.mddoc/PROJECT.mddoc/功能缺失.md 的架构、数据库和完成状态描述不完全一致。

2. 已验证现状

2.1 结构与入口

  • 实际应用目录为 lc_garage/,根目录是项目文档工作区。
  • Wails 入口为 lc_garage/main.go,通过 //go:embed all:frontend/dist 嵌入前端,并将 /api/* 反向代理到 Gin :8888
  • 后端实际代码位于 lc_garage/internal/,不存在文档中曾描述的 lc_garage/server/ 主目录。
  • 前端同时存在 frontend/web/ 两套目录;Wails 配置明确使用 frontendweb 更像历史遗留或兼容目录。
  • 新模块已实际存在:parking-sessiondigital-ticketpaymentmonthlyshiftreportprinterincidentcentral-paymentdeviceprovisioning 等。

2.2 验证结果

  • frontend: npm run build 成功,Vite 生成生产包;构建有 Sass 弃用提示及两个超过 500 KB 的 chunk 警告。
  • go test ./...: 当前环境失败在 Go 构建缓存目录 C:\Users\longc\AppData\Local\go-build 的访问权限,输出为 Access is denied,不能视为代码测试失败。
  • 项目进度文档声称的模块级测试命令应使用项目可写的 GOCACHE,并在 CI 中固定执行,避免环境权限造成误判。

3. 问题清单

P0:上线前必须处理

P0-1 公开路由和敏感数据访问边界需要收紧

证据:internal/initialize/router.go:70-92

  • Router.StaticFS(global.GVA_CONFIG.Local.StorePath, ...) 直接提供本地上传目录;车牌抓拍、头像等文件可通过可预测路径访问。
  • Swagger 在 :swagger/*any 直接注册,未看到生产环境开关。
  • dashboardRouter.InitDashboardRouter(PublicGroup) 将监控接口放在公开组;CPU、内存等运行信息不应默认匿名暴露。
  • PublicGroup.POST("/device-images/upload", deviceimage.Upload) 公开注册,上传接口应明确鉴权、文件类型、大小、路径和访问权限。
  • 中央缴费机公开接口是设备对接需要,但必须只允许设备令牌、来源网络或签名请求,不能按普通公开 API 处理。

修复方案:

  1. 将上传改为受 JWT/Casbin 保护的下载接口,或使用短时签名 URL;禁止目录遍历和原始文件名落盘。
  2. 增加 system.expose-swaggersystem.expose-monitor 等显式配置,生产默认关闭。
  3. 设备图片上传和中央缴费机接口分别使用设备认证中间件;记录设备 ID、请求摘要和失败原因。
  4. 为公开路由增加路由安全测试:匿名访问必须只允许健康检查和明确的设备协议接口。

P0-2 默认凭据和密钥管理不适合生产

证据:internal/initialize/seed.go 包含固定 bcrypt 密码和 README.md:32-35 公开写出 admin/123456config.yaml 还保留对象存储示例密钥字段。

修复方案:

  • 首次启动进入初始化向导,强制设置管理员密码;发布包不再预置可直接登录的通用密码。
  • 将 JWT secret、设备 token、摄像头密码和第三方支付密钥移出仓库,使用系统凭据存储或受保护配置文件。
  • 对历史数据库提供管理员密码轮换迁移;启动时检测默认密码并阻止生产模式继续运行。

P0-3 SQLite 并发写、备份和恢复策略缺失

证据:internal/initialize/gorm_sqlite.go:47-53 只设置连接池,没有设置 WAL、busy_timeout 或备份策略;config.yaml:185-199 允许 max-open-conns: 100

风险:设备事件、支付、操作日志和定时任务并发写入时可能出现 database is locked;进程或磁盘损坏会导致本地运营数据丢失。

修复方案:

  1. SQLite 初始化后执行 PRAGMA journal_mode=WALPRAGMA busy_timeout=5000、合理的 synchronous 设置,并将写并发控制在可验证范围。
  2. 增加在线一致性备份或安全快照,备份文件校验、保留周期和恢复演练。
  3. 对支付、停车会话、月卡和交接班增加恢复后校验任务,发现跨表不一致时生成异常事件。
  4. 增加并发写压力测试和断电恢复测试,测试不依赖用户目录下不可写的 Go 缓存。

P0-4 服务启动失败处理不可靠

证据:internal/core/server.go:34-40 调用 s.ListenAndServe().Error()internal/initialize/gorm.go:77-84 在迁移失败时使用 os.Exit(0)

风险:监听失败可能触发 nil error 解引用;数据库迁移失败却以成功码退出,Windows 启动器和发布脚本无法正确识别失败。

修复方案:

  • 保存 err := s.ListenAndServe(),对 http.ErrServerClosed 单独处理,其余错误记录并以失败状态退出或通知 Wails 主进程。
  • os.Exit(0) 改为错误返回/受控退出码 1,并在启动错误日志中写明迁移步骤和恢复建议。
  • 启动前执行端口、数据库路径和配置值校验,失败时不要启动前端窗口。

P0-5 真实资金交易尚未形成可审计闭环

证据:doc/功能缺失.mdinternal/modules/payment 的现状说明;当前 payment_record 主要记录本地业务结果,POS、扫码和中央缴费机仍需真实设备或网关确认。

修复方案:

  • 建立支付订单状态机:待支付、处理中、成功、失败、不确定、已退款、已撤销。
  • 为支付记录增加渠道订单号、幂等键、回调时间、原始渠道状态和退款/冲正关联。
  • 外部支付只能在可信回调、主动查询或设备签名结果确认后标记成功;重复回调必须幂等。
  • 交接班和收入报表按支付入口、支付方式、操作员、班次、退款和差异统一对账。

P1:应在近期完成

P1-1 道闸和读卡器状态模型仍然混杂

现状记录见 doc/功能缺失.md:117-139。读卡器、闸机控制器、连接管理器和运行时状态存在多套来源;串口/TCP 的 ACK、分片、超时、重连和落杆反馈还需要现场验证。

修复方案:拆分设备类型与通道拓扑,统一 DeviceRuntime 状态源;所有开闸/关闸命令落 device_command_log,校验 ACK、超时和重试,增加地感、防砸、落杆确认和人工兜底测试。

P1-2 模拟道闸必须具备不可误用的运行保护

config.yaml:210 当前为 gate-simulator: false,默认值正确;但仍应在启动时显示运行模式,并在生产构建或生产配置中拒绝开启模拟模式。模拟模式下的“开闸成功”不能被当作真实硬件确认。

修复方案:增加 environment=productiongate-simulator 互斥校验;模拟模式所有指令标记 simulated=true,前端和审计记录明确显示。

P1-3 打印失败没有持久化补偿任务

现状:票机打印仍以同步硬件调用为主,失败重试、重打、作废和异常处置尚未形成完整任务模型。

修复方案:新增打印任务表和状态机,先创建任务再执行硬件动作;记录短写、串口错误、设备离线和重试次数,允许受权限控制的重打/作废,并与数字票和停车会话建立补偿规则。

P1-4 月卡、交接班和收入报表的财务口径仍不完整

现状:月卡退款缺少完整退款流水和审批;自然月/季/年、并发办理、人工白名单保护需要继续完善;交接班和报表还需要覆盖所有支付方式、退款和差异。

修复方案:

  • 月卡办理、续费、退款、白名单变更和支付流水使用同一事务及幂等键。
  • 用日历月/季度/年度计算有效期,明确过期、冻结、转车和退款规则。
  • 交接班增加唯一 active 约束、收款前当班校验、管理者复核和锁定机制。
  • 报表提供明细追溯、导出、打印和支付记录对账。

P1-5 数字票过期任务和跨表对账不足

doc/功能缺失.md 指出 ExpireAt 自动执行和状态不一致检测仍不完整。应明确待支付票、已支付未离场票的过期规则,并由定时任务执行状态迁移和异常告警。

P2:产品能力和工程质量提升

  • 摄像头 RTSP/SDK、OCR 置信度、防重复识别和通道绑定。
  • LED 余位屏协议、推送、离线重试和恢复同步。
  • 远程设备诊断、设备告警中心和现场运维审计。
  • 历史会话、日志和抓拍图片归档清理;上传文件容量配额。
  • 短信/邮件验证从模拟实现升级为真实供应商适配,并增加频率限制。
  • 通道事件从内存队列升级为持久化队列,支持重启恢复。
  • 前端 bundle 拆分,处理 ECharts 约 1 MB chunk;清理 Sass @import/legacy API 弃用警告。
  • 增加 API、JWT、Casbin、操作日志脱敏、登录登出、越权和配置校验测试。

4. 文档与结构问题

4.1 架构描述互相冲突

  • 根目录 PROJECT.md 仍描述 server/ 独立后端、MySQL 和旧 Electron 结构,与实际 Wails + SQLite 代码不符。
  • AGENTS.mdlc_garage/README.mddoc/PROJECT.md 对结构的描述不一致:前者较旧,后两者基本反映当前布局。
  • doc/功能缺失.md 中部分安全问题已在提交 8cca42f 修复,例如注册角色层级校验、操作日志脱敏、模拟闸机告警,但文档仍把它们写成当前漏洞。
  • doc/项目进度.md 更新日期早于最近代码提交,完成状态与后续新增的中央缴费机、设备接入模块没有完全同步。

修复方案:

  1. lc_garage/doc/PROJECT.md 作为唯一项目说明,以 lc_garage/README.md 作为快速开始文档。
  2. 将根目录 PROJECT.md 标记为历史文档或删除,避免新成员误用 MySQL/server 启动方式。
  3. doc/功能缺失.md 增加“已修复/仍存在”分栏、代码版本和验证命令;删除已完成项的当前时态描述。
  4. 每次领域功能合并时同步更新 项目进度.md、流程文档和测试记录,并在 CI 检查文档中的路径是否存在。

4.2 双前端目录需要明确归属

Wails 使用 frontend,但 web 仍保留完整 Vue 源码和 Vite 配置。双目录会导致修复只落在一处、构建结果与开发结果不一致。

修复方案:短期在 READMEwails.json 中明确 frontend 为唯一构建源;中期归档或删除 web,若必须兼容则用脚本从唯一源生成,不允许手工双写。

5. 前端已确认缺陷

5.1 报表异常处理引用未定义变量

frontend/src/view/report/enter.vue:222-224 的异常处理调用 t.value.getListFail,文件中没有对应的 t 定义。接口失败时会再次触发 ReferenceError,原始错误信息被覆盖。

修复方案:改为已有的 $t/语言包访问方式,或定义统一的 useI18n 实例;补充请求失败分支测试。

5.2 登出失败时本地凭据清理策略不统一

frontend/src/pinia/modules/user.js:91-98 只有黑名单接口返回成功才清理 token;而 frontend/src/utils/request.js:147-162 的 401 处理依赖用户确认。

修复方案:登出无论服务端结果如何都清理本地 token;401 统一立即清理并跳转登录,弹窗只用于提示,不应让失效凭据继续留存。

6. 推荐实施顺序

顺序 优先级 工作包 完成标准
1 P0 路由、上传、Swagger、监控和设备接口安全边界 匿名访问测试通过;上传不可猜测读取;生产 Swagger/监控默认关闭
2 P0 默认凭据、密钥和配置校验 首次启动强制改密;仓库不含可用生产密钥;非法端口/路径拒绝启动
3 P0 SQLite WAL、锁等待、备份恢复 并发写压测通过;备份可校验;恢复演练有记录
4 P0 启动失败和进程退出语义 迁移/监听失败返回非零并写清晰诊断,不出现 nil error panic
5 P0 支付订单、回调幂等和财务对账 成功/失败/不确定/退款/冲正可追溯,重复通知不重复收费
6 P1 道闸、读卡器、打印机现场闭环 ACK、超时、重试、离线、落杆和打印补偿均有集成测试
7 P1 月卡、交接班、报表和数字票过期 事务、并发、退款、班次和跨表对账规则明确并覆盖测试
8 P1 摄像头、设备告警和 LED 设备状态、事件、恢复和余位推送可在现场验收
9 P2 文档收敛、双前端归档和前端性能 唯一开发入口,文档路径与状态可由 CI 校验

7. 验收与持续检查

发布前至少执行:

cd D:\lq\Smart Parking\lc_garage
$env:GOCACHE = "D:\lq\Smart Parking\lc_garage\build\gocache-ci"
go test ./... -count=1

cd frontend
npm run build

另外需要单独保留以下验收记录:真实闸机开/关及断网、真实打印机短写和重打、摄像头重复识别、POS/中央缴费机回调幂等、SQLite 备份恢复、管理员和操作员越权测试。只有代码、权限、自动化测试和现场流程同时通过,相关功能才应标记为“已完成”。