Files
YwxAppThink/addon/iot/view/frontend/index/index.html
T
yangwx 18101cf11a feat: 上线前安全加固与发布工程化;appmall 由插件迁移为独立应用
安全(P0)
- 发布包签名:新增 scripts/package_keygen.php、scripts/package_verify.php、
  ywxapp\service\PackageVerifier;FrameworkService::apply() 解压前强制验签
  (ywxapp.framework_package_verify,默认开启)
- JWT 收紧:config/jwt.php 移除公开默认密钥,JwtService::assertStrongSecret()
  校验非空 / 长度≥32 / 已知弱值;.env.production.example 键名由 JWT_SECRET_KEY 修正为 JWT_SECRET
- /api/v1/Article:免登录白名单收窄为只读接口,写操作字段白名单 + assertOwner() 越权校验
- 开发者令牌:查找接口不再回显明文、统一失败文案 + 限流
- TemplateInstaller:文件名白名单 + realpath 归一化 + 目录内断言,修复 Zip Slip;补 use ZipArchive
- 后台登录:接入验证码、失败锁定与登录限流(config/ratelimit.php)
- 缓存 / Session 驱动可由 .env 覆盖(CACHE_DRIVER / SESSION_TYPE),集群部署改 redis
- paycenter 支付日志开关改为 PAY_LOG,不再跟随 APP_DEBUG

工程化 / 交付
- 新增 CHANGELOG.md 与 .env.production.example;composer.lock 入库锁定依赖版本
- 插件离线安装 CLI 增加 --uid,后台上传安装透传 uid,付费插件授权校验可通过
- 授权拒绝文案区分「未携带 uid」与「未找到有效授权」,便于排障
- .gitignore 放行 .env.production.example / .env.addon.example / .gitattributes / public/.htaccess

结构
- appmall 由 addon/appmall 迁移为独立应用 app/appmall(市场 / 开发者中心 / 审核 / 分润)
2026-10-22 00:53:39 +08:00

181 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>YwxApp IoT 物联网平台 · 能力总览</title>
<style>
:root{
--bg:#0b1220; --bg2:#101a2e; --card:#121e33; --line:#1f3050;
--txt:#e7eefc; --sub:#8fa3c8; --acc:#3b82f6; --acc2:#22d3ee;
--ok:#34d399; --warn:#fbbf24;
}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--txt);font-family:"PingFang SC","Microsoft YaHei",system-ui,sans-serif;line-height:1.7}
.wrap{max-width:1080px;margin:0 auto;padding:0 24px}
code{font-family:Consolas,Menlo,monospace;font-size:.92em;background:#0a1526;border:1px solid var(--line);border-radius:4px;padding:1px 6px;color:var(--acc2)}
/* ---------- hero ---------- */
.hero{position:relative;padding:80px 0 60px;background:
radial-gradient(ellipse 60% 50% at 70% 10%,rgba(59,130,246,.18),transparent),
radial-gradient(ellipse 40% 40% at 20% 80%,rgba(34,211,238,.10),transparent),
linear-gradient(180deg,#0d1526,var(--bg));border-bottom:1px solid var(--line)}
.badge{display:inline-block;font-size:12px;letter-spacing:2px;color:var(--acc2);border:1px solid var(--line);border-radius:99px;padding:3px 14px;margin-bottom:18px;background:rgba(34,211,238,.06)}
.hero h1{font-size:40px;font-weight:700;letter-spacing:1px}
.hero h1 em{font-style:normal;background:linear-gradient(90deg,var(--acc),var(--acc2));-webkit-background-clip:text;background-clip:text;color:transparent}
.hero p{color:var(--sub);font-size:16px;max-width:640px;margin:14px 0 26px}
.live{display:flex;flex-wrap:wrap;gap:14px}
.live .item{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:10px 18px;min-width:130px}
.live .k{font-size:12px;color:var(--sub)}
.live .v{font-size:22px;font-weight:700;color:var(--acc2);font-family:Consolas,monospace}
.live .v.g{color:var(--ok)}
.refresh{color:var(--sub);font-size:12px;margin-left:auto;align-self:center}
/* ---------- section ---------- */
section{padding:56px 0;border-bottom:1px solid var(--line)}
h2{font-size:24px;margin-bottom:6px}
h2 span{color:var(--acc);margin-right:8px;font-family:Consolas,monospace}
.sub{color:var(--sub);font-size:14px;margin-bottom:28px}
/* 能力卡片 */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(310px,1fr));gap:16px}
.cap{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:22px;transition:border-color .2s}
.cap:hover{border-color:var(--acc)}
.cap .ico{font-size:24px;width:46px;height:46px;display:flex;align-items:center;justify-content:center;border-radius:10px;background:linear-gradient(135deg,rgba(59,130,246,.2),rgba(34,211,238,.12));margin-bottom:14px}
.cap h3{font-size:16px;margin-bottom:8px}
.cap p{font-size:13px;color:var(--sub)}
.cap p b{color:var(--txt);font-weight:600}
/* 优势行 */
.adv{display:grid;grid-template-columns:repeat(auto-fill,minmax(480px,1fr));gap:14px}
.adv .row{display:flex;gap:14px;background:var(--card);border:1px solid var(--line);border-radius:10px;padding:16px 18px}
.adv .n{flex:none;width:26px;height:26px;border-radius:50%;background:linear-gradient(135deg,var(--acc),var(--acc2));color:#fff;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:center;margin-top:3px}
.adv h4{font-size:14px;margin-bottom:4px}
.adv p{font-size:12.5px;color:var(--sub)}
/* 链路图 */
.flow{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:26px;overflow-x:auto}
.flow .chain{display:flex;align-items:stretch;gap:0;min-width:720px}
.node{flex:1;border:1px solid var(--line);border-radius:10px;padding:14px 10px;text-align:center;background:var(--bg2)}
.node .t{font-size:14px;font-weight:600}
.node .d{font-size:11px;color:var(--sub);margin-top:4px}
.arrow{flex:none;width:56px;display:flex;align-items:center;justify-content:center;color:var(--acc);font-size:18px}
.flow .note{margin-top:16px;font-size:12.5px;color:var(--sub)}
/* 快速开始 */
.steps{counter-reset:s}
.step{position:relative;padding:0 0 22px 44px}
.step::before{counter-increment:s;content:counter(s);position:absolute;left:0;top:0;width:30px;height:30px;border-radius:50%;background:linear-gradient(135deg,var(--acc),var(--acc2));color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px}
.step h4{font-size:15px;margin-bottom:4px}
.step p{font-size:13px;color:var(--sub)}
footer{padding:34px 0;color:var(--sub);font-size:12px;text-align:center}
footer b{color:var(--txt)}
@media(max-width:720px){.hero h1{font-size:30px}.adv{grid-template-columns:1fr}}
</style>
</head>
<body>
<!-- ============ HERO ============ -->
<div class="hero"><div class="wrap">
<div class="badge">YwxApp Addon · IoT v1.0</div>
<h1>自研 <em>MQTT Broker</em> 物联网平台插件</h1>
<p>设备接入 · 实时监测 · 告警通知 · 场景联动 · 固件 OTA · 共享协作 —— 一套 PHP 常驻进程全搞定,无需 EMQX / Mosquitto 外部中间件。</p>
<div class="live">
<div class="item"><div class="k">Broker 在线连接</div><div class="v g">{$stats.online}</div></div>
<div class="item"><div class="k">接入设备</div><div class="v">{$stats.devices}</div></div>
<div class="item"><div class="k">累计消息</div><div class="v">{$stats.recv}</div></div>
<div class="item"><div class="k">时序数据点</div><div class="v">{$stats.points}</div></div>
<div class="item"><div class="k">运行时长</div><div class="v">{$stats.uptime}</div></div>
<div class="refresh">快照刷新于 {$now}</div>
</div>
</div></div>
<!-- ============ 核心能力 ============ -->
<section><div class="wrap">
<h2><span>01</span>核心能力</h2>
<p class="sub">八大能力域覆盖设备全生命周期,从出厂激活到固件升级。</p>
<div class="grid">
<div class="cap"><div class="ico">🔌</div><h3>自研 MQTT Broker</h3><p>纯 PHP 常驻进程实现 MQTT 3.1.1 协议服务端,QoS0/1/2、保留消息、遗嘱、会话恢复全支持。当前累计转发 <b>{$stats.recv}</b> 条消息,保留消息 <b>{$stats.retained}</b> 条。</p></div>
<div class="cap"><div class="ico">📱</div><h3>设备接入三步走</h3><p>出厂预置激活令牌 → 首次联网一次性换领一机一密凭证 → App 扫码 SN + 配对码绑定认领。激活即换发凭证,杜绝裸设备上线。</p></div>
<div class="cap"><div class="ico">🌡️</div><h3>多路传感器监测</h3><p>每设备 <b>3 路总线 × 3 探头</b>(DS18B20 OneWire),位置级温度/温差上报告警。当前已落库 <b>{$stats.points}</b> 个时序点。</p></div>
<div class="cap"><div class="ico">📈</div><h3>历史曲线双接口</h3><p>原始<b>稀疏点</b>(每条带有效期,App 前向填充)+ <b>分钟级聚合</b>(时间加权平均,step/window 可控:最近 30/60 分钟每分钟一点)。</p></div>
<div class="cap"><div class="ico">🔔</div><h3>云端复核告警</h3><p>设备端位图初判 + 云端 <code>capture()</code> 复核落库,防误报防刷屏(窗口抑制)。未读角标 / 已读回执 / App 推送一路打通。</p></div>
<div class="cap"><div class="ico">⚡</div><h3>场景联动 + 分组</h3><p>温度越限 → 下发命令 → 设备执行,全链路 &lt; 秒级。设备分组批量控制,当前 <b>{$stats.scenes}</b> 个场景在跑。</p></div>
<div class="cap"><div class="ico">🤝</div><h3>共享权限模型</h3><p>主人 / 可控制(perm=2)/ 只读(perm=1)三级权限,HTTP API 与 Broker ACL <b>双层校验</b>。当前有效共享 <b>{$stats.shares}</b> 条。</p></div>
<div class="cap"><div class="ico">🚀</div><h3>固件 OTA 远程升级</h3><p>版本管理 + 分批推送 + 进度跟踪,断电续传由固件侧分片请求保障。无需拆机刷写。</p></div>
</div>
</div></section>
<!-- ============ 架构优势 ============ -->
<section><div class="wrap">
<h2><span>02</span>架构优势</h2>
<p class="sub">不是"又一个 MQTT 接入",每一个设计点都对应一次真实踩坑的教训。</p>
<div class="adv">
<div class="row"><div class="n">1</div><div><h4>零外部中间件依赖</h4><p>Broker 内嵌于插件(<code>php think iot start -d</code>),单机即可跑通,Windows 调试 / Linux 生产同构,运维成本≈0。</p></div></div>
<div class="row"><div class="n">2</div><div><h4>稀疏点存储,带宽与体积双赢</h4><p>温变才上报(10s~120s 一条),每条带 <code>iv</code> 有效期,不做服务端插值放大。500 点曲线 ≈ 一张缩略图的体积。</p></div></div>
<div class="row"><div class="n">3</div><div><h4>配置版本对齐机制</h4><p>服务端 <code>cfg_ver</code> ↔ 设备 <code>sync_ver</code> 回执对齐,retained 下发 + 断线重连自动补推,配置永不漂移、永不丢。</p></div></div>
<div class="row"><div class="n">4</div><div><h4>离线可用的配置中心</h4><p>设备配置真源在云端(后台编辑 → retained 下发 → App 共用同一份),设备离线也能读能存,上线即生效。</p></div></div>
<div class="row"><div class="n">5</div><div><h4>安全三道闸</h4><p>设备侧 uuid/secret 一机一密 · 会员侧 mqttTicket 短时票据 · Broker ACL 按身份收敛订阅/发布范围,越权即断连。</p></div></div>
<div class="row"><div class="n">6</div><div><h4>API 按域分组,一眼可辨</h4><p><code>client/</code> 设备管理 · <code>monitor/</code> 监测 · <code>scene/</code> 场景 · <code>ota/</code> 升级 · <code>mqtt/</code> Broker,旧路径兼容别名平滑迁移。</p></div></div>
</div>
<h2 style="margin-top:36px"><span>03</span>数据链路</h2>
<p class="sub">固件 → Broker → 落库 → App,全程秒级。</p>
<div class="flow">
<div class="chain">
<div class="node"><div class="t">固件 (ESP32-C3)</div><div class="d">3 路 OneWire 总线<br>温变触发上报</div></div>
<div class="arrow">→</div>
<div class="node"><div class="t">MQTT Broker</div><div class="d">鉴权 / ACL / QoS1<br>retained 配置下发</div></div>
<div class="arrow">→</div>
<div class="node"><div class="t">落库 + 告警复核</div><div class="d">iot_sensor_point<br>capture() 防误报</div></div>
<div class="arrow">→</div>
<div class="node"><div class="t">场景引擎</div><div class="d">规则匹配 → 命令<br>outbox 可靠投递</div></div>
<div class="arrow">→</div>
<div class="node"><div class="t">App</div><div class="d">实时推送 / 曲线<br>分钟级聚合查询</div></div>
</div>
<div class="note">下行(配置/命令/OTA)统一走 outbox 队列可靠投递,设备 ack 回执闭环;App 侧「读写一律 HTTP API,MQTT 连接只订不发」。</div>
</div>
</div></section>
<!-- ============ 开放能力 ============ -->
<section><div class="wrap">
<h2><span>04</span>开放能力</h2>
<p class="sub">App 端 HTTP 接口按功能域划分、全部经会员鉴权;接口规模由路由表实时统计,能力扩张页面自动更新。</p>
<div class="grid">
{foreach $apiGroups as $group}
<div class="cap"><div class="ico">{$group.ico}</div><h3>{$group.label}</h3><p><b>{$group.count}</b> 个接口 · {$group.blurb}</p></div>
{/foreach}
</div>
</div></section>
<!-- ============ 消息通道设计 ============ -->
<section><div class="wrap">
<h2><span>05</span>消息通道设计</h2>
<p class="sub">命名空间隔离 + 身份裁决,连接层即安全边界——不依赖主题名保密。</p>
<div class="grid">
<div class="cap"><div class="ico">🔒</div><h3>设备私有命名空间</h3><p>每台设备独占自己的主题空间,发布 / 订阅权限由 Broker ACL 按归属实时裁决,越权订阅直接拒绝。</p></div>
<div class="cap"><div class="ico">📮</div><h3>会员通知通道</h3><p>告警 / 共享 / 系统通知按账号隔离实时推送;App 连接「只订不发」,读写一律走鉴权 HTTP API。</p></div>
<div class="cap"><div class="ico">💾</div><h3>retained 设备影子</h3><p>状态与配置以保留消息存储于 Broker,设备离线可查最后状态,上线即自动对齐配置版本。</p></div>
<div class="cap"><div class="ico">✅</div><h3>回执闭环</h3><p>下行命令 / 配置经队列可靠投递,设备 ack 回执对齐版本号,未达即重发自愈。</p></div>
</div>
</div></section>
<!-- ============ 快速开始 ============ -->
<section><div class="wrap">
<h2><span>06</span>快速开始</h2>
<p class="sub">从零到设备上线,三步。</p>
<div class="steps">
<div class="step"><h4>启动 Broker</h4><p>命令行执行 <code>php think iot start -d</code>,常驻进程开始监听 MQTT 端口并每 2 秒写入运行快照。</p></div>
<div class="step"><h4>登记设备</h4><p>后台「设备管理」预登记 SN 与激活令牌 → 设备首次联网完成入云激活,一次性领取设备凭证。</p></div>
<div class="step"><h4>App 绑定监测</h4><p>App 扫码 SN + 输入配对码绑定 → 配置传感器位置阈值 → 曲线 / 告警 / 场景联动全部就绪。</p></div>
</div>
</div></section>
<footer><div class="wrap">
<b>YwxApp IoT Addon</b> · 自研 MQTT Broker · 当前在线 {$stats.online} 台设备 / {$stats.alerts} 条告警记录 · 数据快照 {$now}
</div></footer>
</body>
</html>