Files
mama-box/AGENTS.md

14 KiB
Raw Blame History

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), 不再硬编码;当前指向 https://mp.yizhezhe.com/mama-box-preview/(用户确认),默认/兜底仍是 /mama-box/。它同时是 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 共享助手,别的 H5 应用也引用它:环境判定 / 读授权结果 / requestProfile / goMall / reportLocation。改动等于改所有接入方,务必保守
mama-box.css 样式
assets/ 图片/资源。⚠️ assets/img/ 下文件名 = 文件内容 md5 的前 12 位(md5sum 新图 取前 12 位),内容寻址:换图即换 URL,天然不会被上一版图缓存顶住。别起描述性名字 —— 全目录 35 张都按这个规则(2026-09-22 换顾问二维码时实测确认)
js/core.js ⚠️ 本仓库内已无任何引用(MPA 原型带过来的遗留)。新代码不要基于它,改前先确认没有隐藏引用

3. 发布

git push origin main                      # 完成后在服务器:
cd /opt/app/mama-box && git fetch && 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 顶部 <!-- V:YYMMDDNN 缓存版本标记… -->
  • 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 前,必须由有权限的人先把这几个文件提交进仓库,否则接口会丢。
  • 边界:只限这张卡。孕期盲盒的数字(已收集、本周开盒人数)一律真实;任何别处都不得引用这里的模拟数字,前端也不得在接口失败时自造数字兜底。
  1. 跳其它 H5 应用 / 调第三方接口一律同源:只写相对路径 /<slug>/,不写域名(2026-10-09 用户定)
  • 背景:小程序 web-view 只放行业务域名 mp.yizhezhe.com,直连 taidong.douba.top(或任何 *.douba.top)会被拦; 首页直接 fetch 别的域名还会跨域。所有第三方 H5 都由 mp 前置机(8.145.39.61)nginx 反代过去,路径不变。
  • 写法:const XXX_URL = '/<slug>/';、接口 '/<slug>/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/<slug>/ 测:
    • 200 → 直接用相对路径;
    • 404 → 说明 mp 还没反代这个目录(不是「小程序白名单没加」,别等别人)。去 mp 的 /etc/nginx/conf.d/default.conf 把 slug 加进「第三方 H5 应用统一反代」那条 location ~ ^/(...)/(页面和 /api 都在目录下时一条就够), 再加一行 location = /<slug> { return 301 /<slug>/; }。改前 cp -a 备份,nginx -t 通过才 nginx -s reload, 之后对比 mp 和 taidong 两边同一路径的内容应一致,并复查 /mama-box/、/mama-box-preview/、/api/mp/... 仍 200。 ⚠️ 这台机同时跑正式站,改 nginx 前先告诉用户。
    • 应用的页面或接口不在 /<slug>/ 目录下(比如接口在根路径 /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 是官方脚本,不在此列。
  1. 任何 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 没加载时的兜底。wx-auth.js 用绝对地址 https://mp.yizhezhe.com/mama-box/js/wx-auth.js 引入。
  • 首页带 return_url 跳过去的应用(档案 / 婴儿房 / 商城)返回时回 return_url 即可(它就是当时的首页地址);没带 return_url 时的兜底也要走 goHome(),别 history.back()。
  • 本仓库自己:首页内部不要用 goHome()(那是给别的应用回来用的);wx-auth.js 里 DEFAULT_HOME 是唯一允许写死首页的地方。
  • 2026-10-09 普查(48 个目录):主返回写死 /mama-box/、已通知各自会话改的有 数胎动 taidong、孕检日历 chanjian-rili、待产清单 daichan-qingdan、 体重 yunqi-tizhong、血糖 yunqi-xuetang、数宫缩 gongsuo-pinlv;laixin、laixin/youju、yunqi-nengbuchi、shengao-tizhong 已先调 goHome(写死仅兜底)。 新接应用前照此检查:curl -s https://mp.yizhezhe.com/<slug>/ | 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. 自测

无构建、无自动化测试。改完:

node --check js/app.js          # 语法

真机/微信开发者工具里走一遍:身份注入是否正常、宫格跳应用是否带身份、分享卡片地址、授权回填、 退出小程序再进是否能回到上次应用。相关接口契约与验证清单见 box_app/AGENTS.md §6。