万家袋同时包含互联网交易系统和实体设备控制系统。一次领袋可能涉及用户身份、活动或支付、设备库存、MQTT 指令、机械执行回执和代理收益,因此“接口返回成功”与“设备真实出袋”必须被建模为两个阶段。

代码库与运行单元

项目 技术组成 源码职责 运行方式
wanjiadai ThinkPHP 6.0、多应用、Predis、EasyWeChat、OSS、phpMQTT 用户和代理接口、订单、设备、库存、回调、统计、权限与结算 PHP API 服务,加定时或命令进程
wanjiadai_admin Vue 2.5、Element UI、Vuex、ECharts 商品、订单、代理、设备、库存、财务、流量、分享和权限后台 Webpack 构建的静态管理站
wanjiadai_express Node.js、Express、MQTT、PM2 特定设备协议适配、HTTP 指令、MQTT 消息和状态回调 独立常驻设备桥接进程

管理后台和 API 是典型 Web 系统;设备桥接服务则是长连接和厂商协议适配层,必须独立监控和重启。三者发布节奏可以不同,但订单编号、设备命令编号和回执格式需要保持兼容。

总体拓扑

flowchart TB
  User[扫码用户 / 微信 / 移动端] --> H5[h5 / mobile / wechat]
  Mini[代理与商户小程序] --> MM[mini_manage]
  Admin[wanjiadai_admin
运营管理后台] --> WA[web_admin] H5 --> Core[wanjiadai
共享业务与数据访问] MM --> Core WA --> Core Third[支付 / 广告任务 / 第三方平台] --> Notify[notify / third] Notify --> Core Core --> DB[(MySQL
业务事实与流水)] Core --> Cache[(Redis
会话 / 锁 / 实时状态)] Core --> Bridge[wanjiadai_express
厂商协议桥接] Bridge --> MQ[MQTT Broker] MQ --> Device[环保袋发放设备] Device --> Bridge Bridge --> Notify

API 应用入口

wanjiadai 按调用方和任务类型拆成多个 ThinkPHP 应用。

入口 主要职责 身份与信任边界
h5 扫码、用户登录、设备信息、领袋订单、积分、广告与数据展示 面向普通用户,Token 与设备上下文均需校验
mobile App 用户登录、附近设备、积分和出袋 面向移动应用用户,不继承后台权限
mini_manage 代理资料、商户、设备、补货、收入、钱包与提现 面向代理和商户,数据范围受代理层级约束
web_admin 平台账号、RBAC、代理、设备、供应链、订单、广告与财务 平台运营权限,可跨代理治理但需资源级授权
notify 支付、DSP、MQTT 和不同设备厂商的回调 无用户会话,依赖验签、来源校验和幂等键
wechat、third 公众号、小程序、开放平台授权与代码审核 保存第三方授权关系,凭据不得暴露给前端
statistics、task 设备、钱包、积分统计与异步任务 由内部任务调度触发,不应直接公开访问

不同入口目前共享模型和辅助函数。维护时应把订单、库存、出袋和结算规则放进公共领域服务,入口层只处理身份、参数和响应格式。

管理后台模块

从路由和页面可以识别出以下管理域:

  • 商品与订单:商品、分类、属性、品牌、发货、退货和订单设置;
  • 设备运营:设备、代理商、商家、设备发货、库存预警、补货和出袋测试;
  • 财务与收益:提现审核、代理分润、用户积分和收益记录;
  • 流量业务:广告、群二维码、公众号获客、渠道广告、分享任务、裂变奖励;
  • 权限中心:管理员、角色、菜单、资源及资源分类。

这些页面会产生跨领域操作。例如“给代理发设备”同时改变设备归属和库存,“审核提现”同时改变提现单与钱包余额。此类操作需要数据库事务和不可变流水,不能只更新页面展示字段。

核心领域模型

领域 主要数据对象 应保持的不变量
用户与渠道 用户、公众号关注、应用、二维码、积分记录 同一渠道身份可追溯到平台用户,积分变化都有来源
代理与商户 代理、地址、银行或微信账户、返佣关系 代理层级不能形成环,数据范围沿授权层级向下
设备与库存 设备、位置、在线日志、出袋计数、补货与发货记录 设备唯一归属,当前袋数可由库存流水核对
订单与任务 订单、DSP 请求、MQTT 命令、回调日志 一个业务单只触发一次有效出袋,重试不重复结算
钱包与结算 收益流水、提现单、返佣 余额由流水汇总,审核与打款状态分离
内容与运营 广告、文章、分享任务、积分任务 任务完成证据与奖励发放记录一一对应

鉴权和数据范围

源码中存在三类会话:

  • H5 使用 Authorization 关联缓存中的用户身份,并同时读取设备上下文;
  • 小程序管理端使用独立 Token 关联代理身份;
  • Web 管理后台使用管理员 Token,再通过角色、菜单和资源表校验接口权限。

会话身份解决“你是谁”,查询范围解决“你能看到谁的数据”。代理端接口还必须从当前代理推导可管理的子代理、商户和设备,不能信任客户端传入的代理编号。

设备二维码是公开入口,只能定位设备,不能直接授予出袋权限。服务端还需要检查设备状态、位置、库存、用户资格和本次订单状态。

数据与缓存

MySQL

数据库保存账号、代理关系、设备档案、订单、库存记录、积分、收益和提现等可审计事实。对于扣减袋数、确认出袋和分配收益,应在一个明确的事务边界内写入,并保存业务单号与设备命令编号。

Redis

Redis 承担登录 Token、短信校验、短期任务状态、锁、用户 IP 或实时设备信息。缓存可以加速查询和防止并发重复处理,但不能成为订单、钱包和库存的唯一数据源。

建议给关键缓存统一前缀、TTL 和失效规则,并将“未命中”与“业务不存在”区分开。订单幂等最好同时依赖数据库唯一约束,而不是只依赖短期缓存锁。

对象存储与日志

OSS 保存图片、二维码和运营素材;日志服务记录第三方回调与设备异常。上传接口需要校验文件类型、大小和对象路径,回调日志必须脱敏,不能记录支付密钥、设备密码、完整 Token 或用户隐私。

设备协议桥接

wanjiadai_express 对外提供出袋、状态查询、广告更换和设备激活等 HTTP 能力,再把业务请求转换为设备厂商协议或 MQTT 消息。设备结果反向通知 notify 入口,由业务 API 更新命令、订单、库存与收益。

桥接层需要承担以下职责:

  1. 把统一业务命令转换为厂商 Topic 和报文;
  2. 为每条命令携带唯一 cmdid,并关联原始订单;
  3. 订阅设备结果与在线状态,验证消息来源;
  4. 对超时、重复消息和无法解析的报文进行记录;
  5. 重启后恢复订阅,不依赖进程内存保存唯一状态。

源码中还存在多个设备或流量渠道适配逻辑。适配器应该返回统一结果,例如“已受理、明确成功、明确失败、状态未知”,业务层不直接理解各厂商私有字段。

同步请求与异步事实

一次领袋包含两条时间线:

  • 同步链路:用户请求、资格校验、订单创建、命令受理;
  • 异步链路:MQTT 下发、设备执行、回执、库存确认、收益分配。

同步接口应快速返回任务编号。设备没有及时回执时,订单进入“确认中”,而不是直接判失败。支付回调、广告任务回调和设备回执都可能重复到达,每个处理器必须使用渠道流水号或业务单号保证幂等。

部署与故障域

运行单元 依赖 故障时的表现 恢复重点
管理后台静态站 API 运营页面不可用 不影响已创建订单和设备回执
ThinkPHP API MySQL、Redis、外部渠道 无法创建订单或查询状态 无状态扩容,先恢复事务写入
Node 设备桥接 MQTT、厂商接口、回调 API 命令不能下发或回执延迟 PM2 守护、健康检查、重订阅
MQTT Broker 设备与桥接连接 设备实时通信中断 连接告警、离线补偿、客户端重连
第三方渠道 支付、微信、广告平台 资格或支付结果延迟 回调重试、主动查询、对账任务
定时统计任务 数据库、Redis 看板和收益统计延迟 加锁运行,可从事实流水重算

当前架构债务与改进顺序

  1. 立即治理密钥:源码中存在固定设备或消息服务参数,应迁移到环境变量或密钥服务并完成轮换;
  2. 统一设备适配器:将不同厂商的命令、回执和错误码映射到统一协议;
  3. 建立订单状态机:明确资格确认、命令下发、执行成功、失败、未知和补偿状态;
  4. 完善库存账本:当前数量与库存流水双轨校验,补货、出袋和人工修正都保留原因;
  5. 拆出领域服务:逐步减少控制器直接操作模型、缓存和第三方 SDK;
  6. 增加链路观测:用订单号、cmdid、设备号和渠道流水串联日志与告警;
  7. 制定依赖升级计划:PHP 7.1 基线、Vue 2 和旧版前端依赖需要独立评估,不与业务重构一次完成。

具体的一次扫码请求如何跨越这些组件,可继续阅读扫码领袋与设备出袋流程。

站内搜索

没有找到内容!