R30 不是一个单体项目,而是由四个可独立开发和交付的代码库,加上一组数据库、缓存、媒体、日志和设备通信服务共同组成。阅读架构时,需要区分源码里已经存在的实现与后续维护时应强化的边界。

物理项目与交付物

代码库 主要技术 源码职责 交付物与运行方式
R30Admin Vue 2.5、Element UI、Vuex、Axios、ECharts 平台运营、设备、供应链、账号、角色、菜单与资源管理 Webpack 构建后的静态管理站
R30UNI uni-app、Vuex 商户登录、门店、设备绑定、广告管理、数据看板和消息 H5、小程序或 App 构建产物
R30API PHP、ThinkPHP 6、多应用模式 鉴权、业务规则、广告与设备数据、媒体编辑、统计及 MQTT 通信 独立 PHP API 服务和命令进程
R30OfficialWebsite HTML、CSS、JavaScript、jQuery 产品、合作、新闻、联系信息等公开内容 不依赖登录态的静态官网

官网属于展示面,不应与业务后台共用会话、发布目录或故障域。真正形成业务闭环的是 R30Admin、R30UNI、R30API 和智能终端。

总体拓扑

flowchart TB
  Admin[R30Admin
平台运营后台] --> WA[web_admin] Uni[R30UNI
商户多端应用] --> SA[shop_manage] Site[R30OfficialWebsite
公开静态官网] --> Visitor[访客] WA --> Core[R30API 共享业务与数据访问] SA --> Core ICE[ice
素材编辑与导出] --> Core Market[market_data
市场数据接口] --> Core Core --> DB[(MySQL
业务事实)] Core --> Cache[(Redis
会话 / 心跳 / 统计)] Core --> Media[OSS / MTS
素材存储与转码] Core --> Search[Elasticsearch / 日志服务] Core --> MQ[MQTT Broker] MQ --> Device[智能广告终端] Device --> SA

R30API 应用边界

ThinkPHP 多应用目录不是简单的 URL 前缀,而是四类调用方的信任边界。

应用 主要接口与模块 调用方 权限特点
web_admin 管理员、角色、菜单、资源、代理、首页统计 R30Admin 平台级登录与 RBAC,能够跨商户治理
shop_manage 用户登录、门店、设备、广告、分类、通知、MQTT 心跳 R30UNI 与设备回调 以代理或商户数据范围为主,不能访问其他商户数据
ice 场景、字体、素材、画布配置、视频导出与素材搜索 内容编辑器 大文件和转码任务需要独立限流与超时策略
market_data 统计与广告数据 数据看板或外部页面 读多写少,应限制查询范围和返回规模

目前控制器中直接调用模型、Redis 和云服务的情况较多。维护时可以逐步把设备状态、广告投放、媒体处理和权限规则提取到明确的领域服务中,使不同入口复用同一规则,而不是复制查询和状态判断。

前端职责

R30Admin

后台已经形成三组主要模块:

  • 运营与供应链:设备导入、设备列表、二维码、代理与设备关系;
  • 权限中心:管理员、角色、菜单、资源与资源分类;
  • 运行验证:首页统计和设备测试,用于判断设备是否能接收指令。

后台只负责提交配置和展示结果。设备绑定、角色授权等关键约束仍需由 API 校验,不能依赖路由隐藏或按钮权限。

R30UNI

多端项目的页面覆盖登录注册、商户与门店、设备绑定与详情、广告上传和下架、产品分类、收藏、消息、客服和数据可视化。它主要调用 shop_manage,统计页面还会调用 market_data。

多端应用发布到不同平台时,应把 API 地址、应用标识和渠道配置放在构建环境中;业务 Token 可以保存在平台安全存储中,但设备连接凭据不能下发给普通商户端。

领域模块

从控制器和数据实体可以把核心业务划分为五个领域:

领域 主要对象 关键规则
身份与权限 管理员、角色、菜单、资源、商户用户 平台管理员与商户账号隔离,授权同时约束页面和 API
商户与设备 代理、门店、设备、绑定关系 一台设备在同一时刻只有一个有效归属,解绑需保留历史
内容与广告 分类、广告、广告位、Banner、兴趣与收藏 素材状态、广告位容量和投放关系需要独立建模
媒体编辑 场景、字体、素材、画布配置、导出记录 原文件、编辑配置和最终播放文件分别保存版本
运行与统计 心跳、在线时长、通知、市场数据 在线状态是计算结果,原始心跳和业务统计不能混为一张表

数据、缓存与搜索

MySQL

MySQL 保存需要追溯的业务事实,包括账号权限、代理与门店、设备档案、广告和广告位、媒体编辑场景、通知与统计记录。设备当前在线状态可以缓存,但设备归属、广告版本和投放关系必须有持久化记录。

Redis

源码中存在两类 Redis 用途:一类保存登录 Token、收藏和短期业务状态;另一类承接 MQTT 心跳、离线集合、在线设备集合、在线时长和统计计数。心跳数据更新频繁,适合 Redis;需要长期报表时,应定时汇总到数据库,而不是永久依赖易失缓存。

后台命令会扫描心跳和离线集合并修正设备状态。该命令应以单实例或分布式锁运行,避免多个进程重复汇总。

媒体与检索

  • OSS 保存图片、视频和编辑器素材;
  • MTS 负责视频转码,API 只记录任务和输出位置;
  • Elasticsearch 可承载素材或业务检索,不应作为唯一事实来源;
  • 日志服务记录设备通信和云服务异常,日志中需要过滤 Token、连接凭据与用户隐私。

设备通信

HTTP 与 MQTT 在系统中承担不同任务:

  1. 商户或运营后台通过 HTTP 写入广告、设备和门店配置;
  2. API 在数据库中形成可追踪的业务状态;
  3. MQTT 向指定设备发送轻量通知或命令;
  4. 设备通过心跳和回调报告在线时长、执行结果与异常;
  5. API 更新 Redis 中的实时状态,并把需要审计的数据落入 MySQL。

设备 Topic 必须按设备身份授权,不能让任意客户端订阅全量设备消息。MQTT 消息中适合传任务编号、版本和摘要,较大的素材与详细配置应通过签名 HTTP 地址获取。

鉴权与数据范围

  • web_admin 使用平台管理员会话,并结合角色、菜单和资源实现 RBAC;
  • shop_manage 使用商户或代理会话,查询条件必须带入其可管理的门店与设备范围;
  • MQTT 入口根据设备标识和连接身份校验 Topic 权限;
  • ice 上传与导出接口需要文件类型、大小、存储路径和任务频率限制;
  • market_data 对外提供统计时,需要控制时间跨度、分页与聚合成本。

前端传入的代理编号、门店编号或设备 IMEI 只能作为查询线索,最终数据范围必须从服务端会话推导。

部署与故障域

建议把运行单元拆成以下边界:

运行单元 扩缩容特点 主要故障影响
三个静态前端 可由 CDN 或静态 Web 服务托管 页面不可访问,不应影响设备继续播放缓存内容
HTTP API 无状态扩容,会话放入共享缓存 后台操作和设备查询失败
心跳与汇总命令 单实例或加锁运行 在线状态和统计延迟,不应阻塞普通 API
媒体转码 异步执行、限制并发 新素材延迟,不影响已发布素材
MQTT Broker 按连接数和消息吞吐独立容量规划 新命令与心跳中断,设备应继续执行本地有效计划
MySQL / Redis 分别承担事实与实时状态 数据写入或在线状态不可用,需要降级和告警

当前架构债务与改进顺序

  1. 配置治理:把 Broker、云服务和连接凭据全部移入环境变量或密钥服务,并轮换源码中曾出现的固定凭据;
  2. 领域服务:从控制器提取设备、广告、媒体和统计服务,减少跨入口重复逻辑;
  3. 状态机:为素材转码、广告投放和设备任务建立明确状态及幂等键;
  4. 异步化:媒体转码、批量投放、日志和报表汇总进入队列或独立任务;
  5. 可观测性:用任务编号、设备编号和请求 ID 串联 API、MQTT、转码与终端日志;
  6. 兼容性升级:Vue 2、旧版 Axios 和 PHP 运行基线需要单独制定升级计划,避免与业务迁移同时进行。

这些改进不会改变四仓结构,但会让每个故障都能被限制在清晰边界内。单次广告如何下发与回传,可继续阅读内容下发与回传流程。

站内搜索

没有找到内容!