# AGENTS.md · mama-box(兜爸心选 H5) > 在本仓库工作前先读。**跨仓库的权威约定在 `box_app/AGENTS.md`**(`/home/jone/workspace/box_app/AGENTS.md`)—— > 三仓布局、身份契约、接口命名、部署与踩坑总表都在那里;本文件只写本仓库特有的部分。 --- ## 1. 这是什么 微信小程序里的**首页 H5**:小程序首页壳(`crmeb/pages/index/index.vue`)用 web-view 加载本站。 ⚠️ 2026-10-09 起首页地址**由 box_app 后台动态配置**(`GET /api/mp/public/home/config` → `result.url`), 不再硬编码,默认/兜底仍是 `/mama-box/`。 ⚠️ 2026-10-10 用户定:**正式版改名 `/mama-box-v2/`**(main 分支 → 服务器 `/opt/app/mama-box-v2`),后台把小程序首页 url 配到这里, 避免拿 `/mama-box-preview/` 当正式用的歧义。三个目录:`/mama-box-v2/` 正式(main)、`/mama-box-preview/` 预览(preview)、 `/mama-box/` 旧正式(停在 v26092219,只作 goHome 兜底,别再往里发)。正式/预览的行为差异全靠 `location.pathname` 判 `/mama-box-preview/`(不恢复上次应用、允许 demo=1 / fpdemo=1),v2 走正式逻辑。它同时是 **H5 应用宫格**入口(30+ 第三方应用的门面)。 - 纯静态站点:**无框架、无构建、无测试**,`index.html` 一个页面用 `.screen` 切换多个屏。 - 仓库 `jone/mama-box`;本地 `/home/jone/workspace/mama-box`;生产 `/opt/app/mama-box`(nginx alias 托管,非 box_app 挂载)。 - 原型参考(只读,别当改动目标):`/home/jone/workspace/dailiang-app-03`。 ## 2. 文件地图 | 文件 | 作用 | | --- | --- | | `index.html` | 单页多屏的全部结构 + 样式引用/脚本引用(1550+ 行) | | `js/app.js` | **全部业务逻辑**(3000+ 行):屏切换、远程数据、宫格、授权、跳转、last_app | | `js/wx-auth.js` | ⚠️ **2026-10-10 起已迁出本仓**:共享助手(环境判定 / 读授权结果 / `requestProfile` / `goMall` / `reportLocation` / `goHome`)唯一来源是 **box_app 仓 `common/wx-auth.js`**,各应用从 **`/common/wx-auth.js?v=…`** 引用;nginx 对旧路径 `/mama-box(/-v2)/js/wx-auth.js` 做了精确匹配永久兼容。改它去 box_app 仓改,别在本仓重建副本(会再次分叉) | | `mama-box.css` | 样式 | | `assets/` | 图片/资源。⚠️ `assets/img/` 下**文件名 = 文件内容 md5 的前 12 位**(`md5sum 新图` 取前 12 位),内容寻址:换图即换 URL,天然不会被上一版图缓存顶住。别起描述性名字 —— 全目录 35 张都按这个规则(2026-09-22 换顾问二维码时实测确认) | | `js/core.js` | ⚠️ **本仓库内已无任何引用**(MPA 原型带过来的遗留)。新代码不要基于它,改前先确认没有隐藏引用 | ## 3. 发布 ```bash # 先预览:改动推 preview → 服务器预览目录更新,用户确认后再上正式 git push origin preview cd /opt/app/mama-box-preview && git fetch && git reset --hard origin/preview # 正式(2026-10-10 起是 /mama-box-v2/):preview 合进 main 后 git push origin main cd /opt/app/mama-box-v2 && git fetch && git reset --hard origin/main # 静态站,无需重启 # /opt/app/mama-box(旧正式)不再发布,只作 wx-auth.js goHome 的兜底落点 ``` ⚠️ ~~例外:`js/wx-auth.js` 手拉旧目录~~ **2026-10-10 已废止**:共享库迁到 **`/common/wx-auth.js`**(box_app 仓 `common/`,nginx 托管), 旧路径 `/mama-box(/-v2)/js/wx-auth.js` 由 nginx 精确匹配**永久兼容**,第三方无需改标签、旧目录无需再手拉文件。 改共享库的流程:改 **box_app 仓 `common/wx-auth.js`** → push → `cd /opt/app/box_app && git reset --hard origin/main`(静态,无需重启)。 nginx:`root /opt/app` + `Cache-Control: no-cache` + `etag on` —— 缓存靠 ETag,所以**改完必须 bump 版本号**。 **版本号规则(必做)**:改了 `js/*.js` 或 `mama-box.css` 时,两处同步 bump,且 commit message 带版本: - `index.html` 顶部 `` - `js/app.js` 顶部 `var VER = 'YYMMDDNN';` `YYMMDD` = 当天日期,`NN` = 当日两位序号(从 `01` 起)。例:`v26092202`。 ## 4. 硬约定 1. **身份只从 URL 读**:宿主把 `#openid=…&unionid=…` 注入进来,用 `hashParam(name)` 读 (它同时读 hash 与 query,并会剥掉历史 bug 粘上的 `?t=`)。`openid` 是唯一身份键。 2. **拿不到 openid 就显示提示条**(`showIdNotice`),**不要造假数据**:宿主拿不到身份时不会加载本页; 真出现空身份要让人一眼看出来,而不是显示 `--`/演示值。 3. **跳其它 H5 应用一律走 `jumpApp(url, identifier)`**(或档案页的 `goArchiveH5()`):它负责 带身份(query)、上报分享地址、上报 last_app,再 `location.href`。**禁止裸 `location.href` 跳应用**。 4. **不要在本仓库写死应用名单**:能不能出现、叫什么、链接是什么,全部由 box_app 后台 App 表决定 (`/api/mp/apps?isPublished=1`)。要下架某应用去后台下架,别在前端加过滤(历史教训:`wx-h5-demo` 过滤已按要求移除,别加回来)。 5. **授权走 `wxAuth.requestProfile()`**:它用 `wx.miniProgram.navigateTo` 跳小程序独立授权页并带 `backUrl`; 结果由宿主写回 URL 的 **hash**。**不要用 postMessage 做授权请求**(延迟批量投递,点了没反应)。 6. **分享位置上报 `reportHostLocation()`**:postMessage 非实时(微信攒到后退/销毁/分享才派发), 所以要在**换页/跳转前**主动上报目标地址,宿主的分享卡片才能在分享那一刻拿到正确地址。 7. **换应用前上报 last_app**(`reportLastApp()`,`navigator.sendBeacon`):这是「退出小程序再进能回到上次应用」的 数据来源,新增任何跳应用的入口都要走 `jumpApp()` 以继承这个行为。 8. **返回首页要清 last_app**(`clearLastAppOnBackHome()` → `DELETE /api/mp/public/last-app`): 用户已经从 H5 应用退回首页,首页才是他最后待的地方 —— 不清的话下次冷启动又把他送回刚退出的应用。 ⚠️ **只认「返回回到本页」三种情形**(bfcache 的 `pageshow.persisted`、后退重载的 `navigation.type === 'back_forward'`、从应用页 `location.href` 回来的 `document.referrer`); **绝不能改成「每次加载都清」** —— 宿主恢复会把本页当返回落点加载,误清会毁掉刚用上的记录。 9. **保存资料失败必须提示,不能静默**(2026-09-22「档案以上游为准」): `PUT /profile` 改**预产期/昵称/宝宝小名**时,后端会**先推上游用户中心、成功才落库**,推失败返回 `code=400` 且**不落库**。H5 必须弹提示(`_putProfile` 已按此判断 `res.code`)——静默的话下次加载会被上游值覆盖回去, 用户以为"改了没生效"。改这个接口的调用方时别再把失败吞掉。 10. **产后态必须先判 `postpartum`**(2026-09-22):`/pregnancy` 的产后返回体里 `week` 也是 `null`, `applyRemoteProfile` 与 `syncPregnancy` 都必须**先判 `state.postpartum` 再判 `empty || week == null`**, 否则会给**已经生产**的用户弹「完善孕期信息」引导; 并且 `syncPregnancy()` 之后那条按 `state.week` 重算的链(`syncStaticDates` 等)要一并拦住 —— `week=null` 会让它算出「看着正常但全错」的日期,页面上看不出来。文案集中在 `syncPregnancy` 的产后分支。 11. **首页那 5 张工具卡的数据来自 box_app**(2026-09-22,v26092213 起):`GET /api/mp/public/mama-box/tool-cards` (box_app 封装数胎动平台的 `app-cards`;H5 **不直连上游、不持有 token**)。两条纪律: ① **接口优先、失败回退本地** —— 接口 `ok=false` 或某槽缺失时保留卡上现有值,页面绝不因上游抖动变空; 两个来源并行返回、先后不定,所以用 `cardsOwned` 旗子定优先级(`#kickTodayHome`、`#calNext` 归接口, curve 卡写值后**摘掉 `data-wk`**),**别赌返回顺序**; ② 卡片的**名称与链接仍以 App 表为准**(`MINI_APP_MAP` + `APP_BY_ID`),接口回的 `appId/path` 只作诊断 —— 上游 `app_id` 是 URL slug(`taier-guzhong`),与 App 表 `identifier`(`taierguzhong`)**刻意不同**,别互相推导。 ⚠️ 卡是固定高度 bento,只有 kick / weight 有位置放第二行(`.mc-extra`);给 fweight/cal/curve 加第二行前 先重排那笔高度账(`158+10+64=232`,见 `mama-box.css`)。 12. **⚠️ 第 2 条「不造假数据」的唯一登记例外:首页「此刻,孕妈们在做什么」卡(2026-10-01 起)** - 内容:该卡的总人数 / 今日三项 / 匿名动态在**模拟阶段**为 box_app 按规则生成的模拟数字(`GET /pulse`,确定性哈希、不落库、不进任何报表)。 - 决策人:产品负责人(用户本人),2026-10-01 拍板「前期先用模拟数据,要显示人多;正式页先用模拟,真实数据跟上后替换」;已书面告知虚假宣传风险(《反不正当竞争法》第 8 条)。 - 期限:**最晚 2026-12-31** 复核(≤ 3 个月);真实数据接通后在后台把 `MamaBoxConfig.pulseMode` 改成 `real`(或 `off`),无需发版。 - 2026-10-02 扩展:卡内新增「同周悄悄话」(`GET/POST /whisper`、`POST /whisper/hug`)。mock 模式下真实悄悄话与 box_app 生成的**模拟悄悄话**(id 以 `m_` 开头,确定性哈希、不落库)混排,跟随同一个 `pulseMode` 开关;real 只出真实的。⚠️ 模拟句是「假装有人说过的话」,比模拟数字更敏感,切 real 时务必一并去掉。 - ⚠️ 悄悄话后端(`models/mamaBoxWhisper.py`、`services/mama_box_whisper_serv.py`、`mama_box_router.py` 与 `models/__init__.py` 的改动)是 2026-10-02 **直接改在服务器 `/opt/app/box_app` 上的,没进 git**(当时的账号无 box_app 推送权限;改前备份在 `/opt/app/box_app_bak_202610021000`)。服务器下次 `git reset --hard` 前,必须由有权限的人先把这几个文件提交进仓库,否则接口会丢。 - 边界:**只限这张卡**。孕期盲盒的数字(已收集、本周开盒人数)一律真实;任何别处都不得引用这里的模拟数字,前端也不得在接口失败时自造数字兜底。 12b. **⚠️ 第 2 条的第二个登记例外:孕妈广场「测一测」的「N 人测过」(2026-11-02 起)** - 内容:测一测列表、信息流测试卡、测试开始页显示的「N万人测过」和测一测头卡的「累计 N 万人次参与」,都是前端 `guangchang/ceshi/meta.js` 里 `gcTested(id)` 按测试 id 哈希出的模拟数(1.2万~6万起,好物配置 5 个 11-02 起调为 5万~13万起,每天约 +0.4%),不落库、不进任何报表。 - 决策人:产品负责人(用户本人),2026-11-02 拍板「人数用模拟数字就行,先帮我放上模拟数字」;已书面告知虚假宣传风险(《反不正当竞争法》第 8 条),并建议过改用真实统计。 - 期限:**最晚 2026-12-31** 复核;接真实统计后删掉 `gcTested` / `gcTestedText`,调用处改读接口。 - 边界:只限上述几处;测试结果页、分享图、其他应用不得引用这个数。 - 2026-11-02 扩展:首页「其他妈妈也在搜 → 全部问题」页每条的「N 人看过」(11-02 用户撤掉了「正在看」)(「此刻」总人数 × heat,同首页),以及专题页「相关推荐」的「N 人看过」,同属模拟数,同一期限复核。 - 2026-11-04 扩展:孕期计算器列表页 topic/jisuan 和首页百宝箱(js/kit.js CALC)里 14 个计算器的「N万人算过」(「此刻」总人数 × heat),以及百宝箱「孕期计算器」入口的合计人数,同属模拟数;用户 11-04 确认新增 10 个计算器的人数「保留」。同一期限复核。 12c. **⚠️ 第 2 条的第三个登记例外:孕妈广场帖子下的模拟评论与 1000 个模拟人设(2026-11-02 起)** - 内容:`guangchang/cm.json`(179 篇占位帖子,每篇 22~26 条评论 + 作者回复 + 楼中楼,共约 4100 条)和其中 1000 个人设(昵称 + 头像 `guangchang/av/*.webp` 代码绘制 / 59 张 `assets/img/mom/` 写实照 + 阶段)。全是 AI 写的「假装有人说过的话」,不是真实用户发言,不落库、不进任何报表。 - 决策人:产品负责人(用户本人),2026-11-02 拍板「准备 1000 个头像和名字,每篇评论至少 20 条以上,也会有作者回复」;已书面告知虚假宣传风险(《反不正当竞争法》第 8 条),且比模拟数字更敏感。 - 期限:**最晚 2026-12-31** 复核;真实评论上线后,有真实评论的帖子要先撤掉模拟评论,不得混排冒充。 - 2026-11-02 扩展:104 个专题页底部「大家怎么说」的预置评论 `topic/_shared/cm/.json`(每页 10~14 条 + 楼中楼,共约 1200 条,人设取自同一批 1000 个),由 `topic/_shared/tools.js` 渲染;用户自己发的评论只存本机 `mmbox.tp.v1`,不上传。同一期限复核。 - 边界:只用于占位帖子的详情页评论区;真实投稿(`n.real`)一律不配模拟评论;这 1000 个人设不得出现在投稿审核、排行榜、通知等任何其他地方。 13. **跳其它 H5 应用 / 调第三方接口一律同源:只写相对路径 `//`,不写域名**(2026-10-09 用户定) - 背景:小程序 web-view 只放行业务域名 `mp.yizhezhe.com`,直连 `taidong.douba.top`(或任何 `*.douba.top`)会被拦; 首页直接 `fetch` 别的域名还会跨域。所有第三方 H5 都由 mp 前置机(8.145.39.61)nginx 反代过去,路径不变。 - 写法:`const XXX_URL = '//';`、接口 `'//api/...'`。确实需要完整地址的地方(如 `return_url`、上报 last_app) 用 `location.origin` 或 `new URL(path, location.origin)` 拼,**也不要手写域名**;万不得已写死时只能是 `https://mp.yizhezhe.com/...`。 - **新接一个应用前,先 `curl -s -o /dev/null -w '%{http_code}' https://mp.yizhezhe.com//` 测:** - 200 → 直接用相对路径; - **404 → 说明 mp 还没反代这个目录**(不是「小程序白名单没加」,别等别人)。去 mp 的 `/etc/nginx/conf.d/default.conf` 把 slug 加进「第三方 H5 应用统一反代」那条 `location ~ ^/(...)/`(页面和 `/api` 都在目录下时一条就够), 再加一行 `location = / { return 301 //; }`。改前 `cp -a` 备份,`nginx -t` 通过才 `nginx -s reload`, 之后对比 `mp` 和 `taidong` 两边同一路径的内容应一致,并复查 `/mama-box/`、`/mama-box-preview/`、`/api/mp/...` 仍 200。 ⚠️ 这台机同时跑正式站,改 nginx 前先告诉用户。 - 应用的页面或接口不在 `//` 目录下(比如接口在根路径 `/api/xxx`)→ 别在 mp 上加兜底,先找该应用的会话改成目录内。 - 历史:2026-10-09 一次补了 `chengzhang-dangan`、`muying-xiaoxiao`、`yinger-fang`、`doudou-duihuan` 四个(备份 `default.conf.bak.4proxy-20261009222036`), 首页这 4 个入口同日改为相对路径(v26100906)。例外:微信 JS SDK `res.wx.qq.com` 是官方脚本,不在此列。 14. **任何 H5 应用「返回首页」一律调 `wxAuth.goHome()`,禁止写死首页地址**(2026-10-09 用户定) - 原因:首页地址是后台动态配置的(见第 1 节),写死 `https://mp.yizhezhe.com/mama-box/` 会把用户送回旧首页。 `goHome()`(`js/wx-auth.js` ⑦)先拉 `/api/mp/public/home/config` 再跳,自动续接 openid/unionid;1.5s 超时或接口坏 → 回退 `/mama-box/`。 - 写法:`if (window.wxAuth && typeof wxAuth.goHome === 'function') { wxAuth.goHome(); return; }`, 原来拼身份的写死地址只允许留作 **wxAuth 没加载时的兜底**。 ⚠️ `goHome()` 的身份只认 URL + sessionStorage(`identity()`)。应用若把身份从 URL 抹掉、存在 localStorage 等别处, 站内跳几次后回首页会带空身份 → 调 `goHome()` 前先 `wxAuth.rememberIdentity(openid, unionid)`(数胎动 2026-10-10 首个这么做)。共享库引入地址 2026-10-10 起为 **`/common/wx-auth.js?v=…`**(旧绝对地址由 nginx 兼容层继续可用,已接入应用不必急改)。 - 首页带 `return_url` 跳过去的应用(档案 / 婴儿房 / 商城)返回时回 `return_url` 即可(它就是当时的首页地址);**没带 `return_url` 时的兜底也要走 `goHome()`**,别 `history.back()`。 - 本仓库自己:首页内部不要用 `goHome()`(那是给别的应用回来用的);`wx-auth.js` 里 `DEFAULT_HOME` 是唯一允许写死首页的地方。 - 2026-10-09 普查(48 个目录):主返回写死 `/mama-box/`、已通知各自会话改的有 数胎动 taidong(预览版已改,正式待批)、孕检日历 chanjian-rili(10-10 已上线,复扫通过)、待产清单 daichan-qingdan、 体重 yunqi-tizhong、血糖 yunqi-xuetang、数宫缩 gongsuo-pinlv;laixin、laixin/youju、yunqi-nengbuchi、shengao-tizhong 已先调 goHome(写死仅兜底)。 新接应用前照此检查:`curl -s https://mp.yizhezhe.com// | grep -n "mama-box/'\|goHome"`。 ## 5. 踩坑 - **不要给别的应用追加 `#openid`**:部分应用自带 hash 路由(如 `/baobao-yingji`),追加 hash 会被当非法路由 → 页面未找到。身份一律走 query(`withIdentity()` 已封装)。 - **`bustReload` 重载必须把 hash 拼回去**,否则丢身份、误报「未获取到微信身份」(v26092009 修过)。 - **首屏渲染与异步数据的竞态**:`init()` 负责渲染,远程档案在 `init()` **末尾**才拉(先拉会被 init 覆盖)。新增远程数据请照这个顺序。 - **`resumeLastApp()` 是兜底,不是主恢复**:主恢复在小程序首页壳(冷启动自己读 last-app 直接进容器页)。 本页只在「首页壳取数失败回落加载」或「浏览器直访」时恢复;被宿主加了 `#norestore=1` 时必须**既不跳、也用 sessionStorage 闸门占住**(否则宿主 `?t=` 重载会把返回落点也换成目标应用,back 回不到首页)。 - **改 `js/wx-auth.js` 等于改全生态**:它是所有接入 H5 应用共用的授权助手,先看 `docs/h5-auth-standard.md` 的协议再动。 ## 6. 自测 无构建、无自动化测试。改完: ```bash node --check js/app.js # 语法 ``` 真机/微信开发者工具里走一遍:身份注入是否正常、宫格跳应用是否带身份、分享卡片地址、授权回填、 退出小程序再进是否能回到上次应用。相关接口契约与验证清单见 `box_app/AGENTS.md` §6。