① 我们对标谁,各学哪半
| 微信小程序(9 亿月活生态) | Telegram Mini Apps | HOOP 取哪边 | |
|---|---|---|---|
| 技术 | 专有 WXML/WXSS,学习曲线陡 | 纯 HTML/CSS/JS,零专有语法 | Telegram 边:H5 游戏管线原样复用,AI 也最会写 |
| 平台独有能力 | 支付 + 社交关系(开发者离不开它的根本原因) | TON 支付 + 频道分发 | 微信边:我们的杀手锏是关系链 / 六度 / 温度 —— 别人抄不走 |
| 数据库 | 云开发(云数据库/云函数/云存储,2018 起,小开发者主流+平台收入) | 不提供,开发者自带服务器 | 微信边:hoopApp.storage = 我们的"云开发"第一块 |
| 审核 | 强制过审才上架 | 基本不审 | 微信边(还没做,复盘 🔴#1) |
| 隐私 | openid 化名,但生态内数据打通 | 拿真 username | 比两家都狠:影子身份数学隔离,见 ⑪ |
一句话结论:微信赢在「平台独有能力灌给 app」,Telegram 赢在「零门槛技术」。
两边的赢面我们都拿:技术零门槛(现成 H5 管线)+ 独有能力(关系链)。
② 总架构(一张图)
┌─ 用户端(App)──────────────────────────────────────────────┐
│ 底栏第二格长按 → 「Apps」页(列表,本地优先缓存) │
│ └→ 全屏壳 MiniappWebViewScreen │
│ ├ 先握手 POST /v1/apps/{id}/launch(影子身份+版本分流) │
│ └ 注入 window.hoopApp 桥(init/user/storage,文档流之前)│
└──────────────────────────┬──────────────────────────────┘
│ 用户 JWT(app 永远拿不到)
┌─ 后端 miniapp 域(Go,独立于 games)────────────────────────┐
│ 目录 miniapps · KV miniapp_kv · 图像 miniapp_media │
│ 版本双指针 live/staging · 留痕 miniapp_promotions · 一房一app │
└───────┬───────────────────────────┬─────────────────────┘
Postgres(云库) R2 对象存储
目录/KV/图像账/留痕 miniapps/{app}/v{N}/index.html
miniapps/{app}/media/{uuid}
为什么 Apps 是独立的域、独立的表(不寄生 games) —— Jeff 拍板 + 数据检验:
games 表有 36 处读方(游戏榜/商城/广告分账/社交条),寄生进去要每处都记得过滤,
漏一处 = Food Guide 出现在游戏榜里,而且不报错。真同构的是托管底座(版本/双指针/留痕/绑房),
不是目录 —— 终局是抽
hosted_bundles 底座表两边共用(记录在案,见 ⑫ 架构债)。③ 开发者旅程(Jeff 2026-08-13 原话 = 产品流程定案)
「首先,我会到开发者中心去,创建我 apps 的项目,平台直接开辟我们 app 内部的空间。
然后,我会看到平台会提供我数据库、我可以上传图片的图像库、我的代码文件夹(可上传),
最后我还会看到版本管理,执行 live 与 staging 按钮。最重要是我有一个 App 工作房。」
| 件 | 状态 | 落点 |
|---|---|---|
| 创建项目 = 开辟空间 | 生产 | POST /v1/dev/apps(第 6 步) |
| 数据库 | 生产 | miniapp_kv + hoopApp.storage(第 4 步) |
| 图像库 | 生产 | miniapp_media + R2(第 5 步) |
| 代码上传 | 生产 | POST /v1/dev/apps/{id}/code(第 7 步) |
| live / staging 按钮 | 生产 | 双指针 + promote + 留痕(第 7 步) |
| App 工作房 | 生产 | miniapps.workroom_id 一房一 app(第 7 步) |
| 开发者中心界面(把按钮画出来) | 待做 | 目前全靠 API;App UI 是下一批(⑬) |
④ 目录与身份
功能
平台的「账本」:有哪些 app、归谁、什么状态。用户打开 app 的那一刻,拿到的是影子身份 —— app 永远不知道你是现实中的谁。
操作
用户侧:Apps 页(GET /v1/apps,只列 active)→ 点开 → POST /v1/apps/{id}/launch
launch 返回:{ app_id, app_user_id: "a_…", sdk_version, capabilities:[], entry_url(按身份分流好版本) }
draft 状态的 app:owner / AI 分身可打开(真机测试),其他人 404 当不存在
代码
| 东西 | 位置 | 关键判据 |
|---|---|---|
表 miniapps | 迁移 000218 / 225 / 230 | id·name·icon·tagline·entry_url·status(active/disabled/draft)·dev_id·live_version·staging_version·workroom_id |
域 backend/internal/domain/miniapp/ | 单文件 miniapp.go | 与 games 零共享代码(等底座抽取) |
影子身份 appUserID() | HMAC 双层派生 | 域前缀 hoop:miniapp:identity: → 同一人在游戏(g_)和小程序(a_)里影子不同,两平台数据拼不上是数学事实 |
| launch 版本分流 | miniapp.go | owner/AI 分身/所挂工作房成员 → staging;路人 → live;canSeeStaging 查不出来按「看不到」处理(错放比错关贵) |
⑤ 数据库(HOOP 云开发第一块 —— 微信云数据库的位置)
功能
每个 app × 每个影子用户,一个 KV 命名空间。小开发者/AI 造的 app 零服务器就能有"记忆"(收藏、进度、用户内容)。
操作(app 里的代码就这么写)
await hoopApp.storage.set('fav', 'Penang'); // 存
const v = await hoopApp.storage.get('fav'); // 取 → "Penang"
await hoopApp.storage.set('fav', null); // 删
代码
| 东西 | 位置 | 关键判据 |
|---|---|---|
表 miniapp_kv | 迁移 000219;PK=(app_id, app_user_id, k) | 隔离是主键结构给的,不是代码自觉 |
端点 GET/PUT /v1/apps/{id}/kv/{key} | 用户 JWT 鉴权 | 影子 id 服务器现算,桥上不传 —— app 连"报自己是谁"的机会都没有 |
| 配额 | 单值 16KB · 每人每 app 128 键 | 58MB 分身会话那课:不设限的存储都会涨到爆;已有键仍可覆盖,只挡开新键 |
桥 hoopKv handler | miniapp_webview_screen.dart | app JS → 壳 → 带用户 JWT 调 API;断网回 {err},app 自己兜底(裸跑军规) |
生产实测:写→读回 / 换人读同键=null(隔离)/ 删→null,四路全过。
⑥ 图像库
功能
每个 app 独立媒体库:传图 → 拿永久地址 → app 里 <img> 直接用。
操作
上传:POST /v1/dev/apps/{id}/media (body=图片字节, Content-Type: image/*)
→ { id, url:"/miniapp-media/{app}/{id}", mime, size }
列表:GET /v1/dev/apps/{id}/media
直出:GET /miniapp-media/{app}/{mid} (公开,无鉴权头 —— WebView 里的 img 用)
代码
| 东西 | 关键判据 |
|---|---|
表 miniapp_media(000225)+ R2 miniapps/{app}/media/{uuid} | 登记失败即删 R2 对象 —— 不留没账的孤儿文件 |
权限 canManage = owner / AI 分身 | 和发布按钮同族判据 |
| 配额:单张 2MB · 每 app 200 张 | 同 ⑤ 的病,同一个药 |
缓存头 immutable | id 即内容,永不变 → 可以放心让 CDN 缓一年 |
⑦ 代码上传与版本管理(live / staging 双指针)
功能
「修改的时候不影响线上」:每次上传产出一个不可变版本快照,库里两个整数决定谁看哪版。 上线/回退 = 改一个整数,零文件搬运、天然原子。这套双指针与游戏平台同构(games 000205 先行验证过)。
操作
传代码:POST /v1/dev/apps/{id}/code (body=index.html)
→ staging_version = max(live, staging)+1 ← 版本号服务器发,客户端不数
自己试:launch 自动把 owner 指到 staging 版
上线: POST /v1/dev/apps/{id}/promote
→ live = staging;留痕(谁/何时/从几到几);首次上线自动 draft→active(=上架)
直出: GET /miniapp-code/{app}/v{N}/ (immutable:版本内容永不变)
代码与判据
| 判据 | 为什么(都是真踩过的) |
|---|---|
| 上传只动 staging,live 一字不碰 | 「上传即上线」正好推翻双轨的意义(games 踩过) |
| 发布按钮绝不改 entry_url | g2048 那颗雷:promote 顺手改写入口 → Pages 游戏一按全球 404。同构照搬防御 |
| 没有测试版就报错,不静默成功 | 假成功比报错贵:让人以为推上去了而线上没动 |
留痕进 miniapp_promotions,留痕失败整笔回退 | 出事那一刻唯一想知道的是「谁推的、何时推的」 |
| 单文件 index.html(≤2MB)或 zip 多文件包(≤20MB 解压 / ≤200 文件 / 根必须 index.html) | 同一端点按 Content-Type 分流;zip 内文本文件逐个过 18+1 条安检(第 9 步已落地) |
⑧ App 工作房(「在群里测」)
功能
一个 app 挂一间工作房;房里所有成员自动看到测试版 —— 名单不是名单,是房间成员本身,进人出人可见范围自动跟(不另建内测名单表,那种表必然和房间漂)。
操作
绑房:POST /v1/dev/apps/{id}/workroom {conversation_id} (空串=解绑)
规则:必须是工作房 + 本人建的;一房一 app(唯一索引 uniq_miniapps_workroom 兜底)⚠️ 复盘 🔴#3:games 的绑房还查「房里除系统消息一条正文都没有」(必须新房),Apps 这边我漏抄了 —— 见 ⑫。
⑨ 用户端(App 里长什么样)
| 东西 | 文件 | 说明 |
|---|---|---|
| 入口 | home_screen.dart 发现槽 mode 2 | 底栏第二格长按菜单「Work/办公」→「Apps」(图标 squaresFour;办公占位页已删) |
| Apps 页 | apps_hub_screen.dart | 列表读 /v1/apps;本地优先(上次目录秒显,断网不白屏);失败态 ErrorRetry 不糊异常串 |
| 全屏壳 | miniapp_webview_screen.dart | 先握手后加载;launch 返回的 entry 优先(版本分流);hoopApp 桥在文档第一行 JS 前注入 → 无 init 竞态;握手失败裸跑降级 |
| 示范 app | 🍜 Malaysia Food Guide | 已认领给 Jeff;页脚显示影子身份 = SDK 桥的看得见的自证 |
⚠️ App 侧改动等下一班 TestFlight;后端全部即时生效。
⑩ SDK 能力面(window.hoopApp)—— 「扶持」的落点
| 能力 | 状态 | 说明 |
|---|---|---|
init() → {app_id, app_user_id, sdk_version, capabilities} | 生产 | 影子身份,先握手后注入 |
user.profile() | 生产 | 只有影子;真名/头像走 consent(000193 地基现成) |
storage.get/set | 生产 | 见 ⑤ |
social.friendsInApp() 你的好友里谁也在用 | 规划 | 只回影子 id 集合;必须过 is_shadowed 闸 |
social.degree() 六度距离 | 规划 | 交友类 app 杀手锏;只给数字不给路径 |
social.invite() 发 app 卡进聊天 | 规划 | 必经用户确认弹层,app 不能静默发 |
pay.charge() 绿能量支付 | 规划 | 钱包/流水表现成;先只开这一种 |
notify.push() | 规划 | 平台节流+审核,绝不给裸推送权 |
能力三道门(从游戏 SDK 学来,每个能力都是服务端闸+用户可见,不是客户端君子协定):
manifest 里声明 → 审核时人看过 → 运行时用户首次触发才授权。capabilities 现在恒空 = 形状先定死,以后逐个亮。
⑪ 隐私闸(和微信最大的不同,品牌线)
- 默认影子身份:app 天生不知道你是谁;游戏/小程序影子分域,拼不上是数学事实
- 关系链 API 全过
is_shadowed闸:暗影好友绝不出现在任何 app 的任何返回里 - 六度只给数字不给路径:路径就是社交图,给了就回不了头
- 真名/头像 = consent 记录在案(谁/何时/同意了什么,000189/000193 现成)
⑫ 复盘:不完善清单(按危险排序,诚实的)
✅ 1. 上架审核已落地(2026-08-15,第 8 步·定规矩第一条)。
draft --promote--> review(版本就绪但不进公开列表)--管理员批--> active;驳回退 draft 可改可重投。
已 active 的再 promote 直接切版本(只审"上架",不卡迭代)。
守门只归 ADMIN_UIDS,故意不给 AI 分身 —— AI 造完自己审自己 = 没有门(生产实测 AI 碰审核接口 403)。
审核队列
GET /v1/admin/apps/review 带 try_url(批前先玩到)。✅ 2. staging 签名已落地(2026-08-15,第 9 步·定空间)。
非 live 版本一律要
?t= 短时签名票(HMAC,1 小时,launch 时只发给 owner/分身/房成员);
没票或票过期 = 404 不解释(不暴露"这版存在")。live 版照旧公开 + immutable 缓存。
生产实测:owner 入口带票、撕票裸访问 404、带票 index/子文件都通。games 同病仍在(那边风险低一档,记在 GAME_STAGING)。🔴 3. 绑房漏了「必须新房」检查。games 查「房里除系统消息一条正文都没有」,Apps 的 bindAppWorkroom 我简化时漏抄 ——
拿一间干着别的活的房来绑,房里人会莫名看到测试版。该补,一小时的活。
🟠 4. 没有 rollback 端点。上线炸了只能再传一版再 promote(能走通但慢)。games 有一键回滚,同构补上即可(注意 games 踩过的两课:回滚也要留痕、别碰 entry_url)。
✅ 5. zip 多文件 + 安检已落地(2026-08-15,第 9 步·定空间)。
同一个上传端点按 Content-Type 分流:单 HTML 照旧;zip 解包(≤200 文件 / ≤20MB 解压防 zip 炸弹 / 路径穿越拒收 / 根必须有 index.html),
文本文件逐个过
developer.ScanForbidden(和 AI 造游戏同一张 18+1 条规则表,单一出处铁律 23)。
接 zip 时把规则表修准了一处:<script src= 只禁外链(相对引用是多文件 app 的正当需求),
顺手补了 ESM import "https://…" 外链这条漏网。生产实测:恶意 fetch 422 / 路径穿越 400 / 外链 script 422 / 正当 3 文件包 200。🟠 6. 开发者中心没有界面。七件套全是 API,人类开发者没法点 —— Jeff 旅程的"我会看到"还看不到。App 侧 hosting 工作台照游戏发布卡纹路镜像一份。
🟠 7. AI 造 app 管线未接 / hoop-app-kit 未建。「从创建第一步开始」的最后一环:/v1/dev/ai/build 换一套 app 版军规 prompt;共享库照 hoop-kit 烘焙模式出姐妹库。首批示范(新闻头条/交友)就用它产,顺便验收管线。
🟠 8. KV 没有键列表/导出;图像库没有总字节配额。开发者看不到自己 app 存了什么(调试盲区);200 张×2MB=400MB/app 上限其实存在但没按字节记账。
🟡 9. 零散欠账:app_card 聊天分享卡(分发闭环)· app 名/tagline 多语言(频道公告那套 i18n 可复用)· 删除/下架流程(照 games「下架=status 一行,可逆不删数据」)· 自带服务器的域名申报(微信经典模式,大 app 要)· KV/媒体随 app 删除的清理策略。
🏗️ 架构债(记录在案,不是忘了):
hosted_bundles 托管底座 —— 现在 miniapps 和 games 各自一套同构的三列+留痕表,是有意的过渡:先各自干净,等两边都稳定后一次迁移共用底座,别在功能高速期动地基。判据写在 MINIAPP_PLATFORM.md ⑦。⑬ 路线图(Jeff 2026-08-15 定框架重排:托盘 = 定规矩 + 定空间)
Jeff:「我们现在是搭建 apps 的托盘!最重要是定规矩、定空间。」
—— 工作房是协作工具,不是托盘地基:已做完(一列+一个端点),降级为边角,不再占路线图主位。
| 步 | 类 | 内容 | 依赖 |
|---|---|---|---|
| 8 | 规矩 | 生产上架审核流:draft→review→active,守门只归管理员 | done 2026-08-15 |
| 9 | 空间 | 生产staging 签名(✅#2)+ zip 多文件 + 上传静态扫描(✅#5) | done 2026-08-15 |
| 10 | 规矩 | 能力三道门:manifest 声明 → 审核看过 → 运行时授权(capabilities 从恒空开始逐个亮) | 8 |
| 11 | 空间 | KV 键列表/导出 + 图像库字节配额(开发者看得见自己的空间) | 无 |
| 12 | 门面 | 开发者中心界面:把七件套画成按钮(🟠#6) | 要出 TF 包 |
| 13 | 生态 | AI 造 app 管线 + 首批示范(新闻头条/交友);SDK social/pay 随三道门开闸 | 8/10 |
| 边角 | — | 绑房新房检查(🔴#3 降级:工作房不在主线)· rollback 端点(🟠#4)—— 顺手清,不占主位 | 无 |
相关:MINIAPP_PLATFORM.md(判据与拍板过程)· GAME_STAGING.md(双轨先行者,含 8 条评审)· GAME_PLATFORM_SPEC.md(影子身份)· GAME_KIT.md(烘焙库模式)· DEVELOPER_PLATFORM.md(审核分成)。 本页由架构线维护;改了实现记得回来改这页 —— 图纸最坏的状态不是没有,是看起来像真相。