Files
danyang-match/AGENTS.md
T
WorkBuddy b67a56479e fix(miniapp): 修 P0 请求层崩溃(一个下划线致所有请求卡死)+ 组件 WXSS 违规选择器,再补 3 项门禁
═══ 缺陷 1(P0,运行期):utils/api.js 成功回调调用不存在的方法 ═══

控制台:
  TypeError: _this._releaseIdempotencyKey is not a function

根因:类中定义的是 `releaseIdempotencyKey()`,成功回调写成了
`this._releaseIdempotencyKey(...)`(**多一个下划线**)。

**为什么一个字符的笔误是 P0**:该调用位于 `wx.request` 的 success 回调内、
且在 `resolve()` **之前**。抛错 → `resolve` 永不执行 → 该 Promise **永不 settle**
→ 所有页面永远停在 loading,同时 App.onError 刷屏。
即「一次成功请求」本应推进流程,实际把前端整成不可用。

修复不只是改名,而是纠正结构:
- **先 `resolve(body.data)`,再执行收尾动作** —— 收尾逻辑不允许挡在响应路径上;
- 释放动作自带 try/catch + console.warn:释放失败最多是"下次操作没拿到新键",
  不得升级为业务失败。
- 语义未变(勿改):成功→释放(下次同域操作是新的一次);失败→刻意不释放
  (重试复用同一把键,后端才能识别重复投递)。

═══ 缺陷 2(编译期警告):组件 wxss 用了标签选择器 ═══

  Some selectors are not allowed in component wxss ... (components/recommend-card/index.wxss:1:1092)

实测违规 1 处(23 个组件样式文件全扫):`.compact-like image` —— 组件 wxss 只允许类选择器。
改为 `.compact-like__icon` 并**同步在 WXML 补上类名**
(只改 wxss 会让样式静默落空,是另一种"假成功")。

═══ 门禁:15 → 18(既有的全是源码内容断言,抓不到上述两类)═══

- 第15 `wxml-structure-contracts`(上一提交新增,本轮 MIN_GUARDS 基线顺带对齐)
- 第16 `miniapp-self-method-contracts`:扫描 `this._x(` / `self._x(` 等私有调用,
  要求同文件有定义(方法简写 / 类字段 / `this._x = 值` / prototype 四种形态)。
  **判据先自证假阳性**:首版正则不允许 `.` 前缀,把 `this._unsub = store.bind(this)`
  形式误报为未定义(3 个页面);修正并加反向自检样例固化了该坑。
- 第17 `wxss-component-selector-contracts`:组件 wxss 禁标签/ID/属性选择器。
  **作用域刻意只限 miniapp/components/**(page 的 wxss 允许标签选择器,套上去必有误报)。
- 第18 `miniapp-api-client-behavior`:**唯一的行为断言** —— 桩掉 `wx.request` 真跑 api.js,
  验证成功 resolve / 失败 retain 键 / 成功 release 键 / 收尾抛错不影响响应路径 4 组。
  含 1s settle 超时,直接编码"永不 settle"这一失败模式。
- 新增 `scripts/lib/wxss-selectors.mjs` + `scripts/check-wxss-component-selectors.mjs`(CLI)。
- `MIN_GUARDS` 15 → 18;执行器措辞改为「源码结构与关键行为断言」。

═══ 验证 ═══

- `node scripts/run-ui-contracts.mjs` → **PASS 18 / 18**,退出 0;
- 负向注入:未定义私有方法 / 标签+ID+属性选择器 / 多余闭合标签 → 均精准变红,
  且**合法样例(`this._x = 值`、纯类选择器、属性内含 `>`)不被误报**;
  行为守卫的负向自证见下一提交/记录;`UI_GUARDS_MIN=99` 拒绝报绿。
- 文档口径同步:AGENTS.md、STATUS.md(4 处当前口径 + 新增 1.1.0-rc.18 行)、ci.yml 注释。
- **未验证**:微信开发者工具真实编译与真机渲染(本机无该环境)。
2026-09-19 11:40:38 +08:00

211 lines
11 KiB
Markdown
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.
# 善缘丹阳 V1.1 - AGENTS.md
> 本文件为项目最高执行规则摘要,WorkBuddy 每次启动时必须首先阅读。
> 版本:V1.1 | 最后更新:2026-09-16 | 基线:v1.0.0-RC.2
---
# V1.1 客户修订文档共同基线
以下文件共同构成当前 V1.1 需求,不得只读取其中一份:
1. `docs/善缘丹阳 V1.1 WorkBuddy最终主启动提示词(整合版).md`:执行纪律、产品红线、不变量和阶段门禁;
2. `docs/善缘丹阳 V1.1 页面级功能清单与交互流程修订版.md`:页面、功能、状态和用户路径;
3. `docs/superpowers/specs/2026-09-13-reference-driven-dual-client-ui-redesign-design.md`:当前唯一 UI 视觉、组件、响应式和前端验收基线;
4. `docs/善缘丹阳 V1.1 数据库与API增量设计.md`:数据模型、API、事务、幂等和权限契约;
5. `docs/善缘丹阳 V1.1 WorkBuddy 开发执行计划修订版.md`:Phase 顺序和增量实施策略;
6. `docs/善缘丹阳 V1.1 WorkBuddy-Jira 最终开发任务增量清单.md`:任务粒度、依赖和验收条件。
冲突时先服从用户最新明确指令,再由上述文件各自在其专业域内裁决。文档中的“已完成、已部署、✅”是历史进度声明,不是需求本身;只有当前代码、测试和人工验收可以证明完成。
V1.1 是 V1.0 的增量升级。正确的 V1.0 核心按 KEEP 处理,不得因为重新审查而推倒重写;错误首页和活动互选规则必须替换,新增业务按 EXTEND / REFACTOR / REPLACE / ADD 执行。
业务 Phase 唯一执行计划:`docs/善缘丹阳 V1.1 客户需求基线增量开发与修复计划.md`。
当前 UI 重设计唯一总计划:`docs/superpowers/plans/2026-09-13-reference-driven-dual-client-ui-redesign.md`。首批范围(小程序 11 个核心页面 + 管理端框架/工作台)已于 **2026-09-16 通过用户验收(结论:基本达标)**,此前"视觉否决 / REOPENED"的判定随之关闭,UI 契约门禁 **18/18** 全绿(2026-09-16 时为 13 项,此后新增端口与 `/admin/` 子路径一致性门禁;2026-09-19 连补 4 项 —— 第 15 项 **WXML 结构守卫**:此前全绿时小程序实际有两个页面 `service-history` / `service-program` 因多一个 `</view>` **编译失败**;第 16 项 **私有方法调用守卫**:`this._x()` 无定义会抛 TypeError,且该调用位于 `resolve` 之前时会让**所有请求**的 Promise 永不 settle;第 17 项 **组件 WXSS 选择器守卫**;第 18 项 **api.js 请求层行为契约**(桩掉 `wx.request` 真跑)。前三项说明既有门禁全是源码内容断言、没有一条会解析 WXML/WXSS 或符号)。管理端桌面端目视复验仍待用户执行。
---
# 不可改变的核心规则
以下规则继承自 V1.0 核心规则,并扩展至 V1.1 新增业务。
## 用户基础规则(继承 V1.0)
1. **用户永久免费** — 禁止任何 VIP/会员/金币/付费功能
2. **Required 不可自动放宽** — 用户"必须符合"的择偶条件是 Hard Constraint
3. **Mutual Match 后才能聊天** — 陌生人不能私信
4. **Block 优先级最高** — 拉黑后聊天停止、推荐排除、搜索不可见
5. **红娘不可替用户操作** — 只能辅助推荐,不能代 Like
6. **活动单向意向保密** — A 选 B 但 B 没选 → B 不知道
7. **普通工作人员不能查看私人聊天** — 仅案件上下文可有限访问
8. **敏感数据默认拒绝** — 身份证/手机号需特殊权限 + 审计
9. **PostgreSQL 是 Source of Truth** — Redis/前端 Store 不可覆盖 DB
10. **使用模块化单体** — 暂不引入微服务/Kubernetes/Kafka
11. **V1 不引入微服务/K8s** — 仅在后述必要性明确时再考虑
12. **所有未确认数量参数配置化** — 不得硬编码业务常量
13. **新功能不得擅自扩大 V1 范围** — 遵循 Phase 顺序开发
## V1.1 新增硬规则
14. **首页 V1.1 结构固定** — 顶部品牌 + 用户状态 + Banner + 8个核心入口 + 今日推荐 + 善缘公益服务 + 近期公益活动 + 善缘服务站 + 婚恋课堂 + 安全提醒。顺序不可更改,运营不可重排
15. **首页 8 核心入口固定** — 第一排:找对象/公益红娘/公益活动/婚恋咨询;第二排:婚恋课堂/婚前辅导/婚恋反诈/善缘服务站
16. **Banner 仅内部跳转** — 不支持外部 URL 跳转,target_type 仅限 activity/matchmaker/counseling/premarital/service_location/article/internal_page/none
17. **本地资格与实名认证分离** — 本地资格(丹阳户籍/工作/居住)独立于实名认证,不得塞入 user_identities 字段
18. **活动互选二阶段同意** — Activity Mutual Interest 不能直接创建 Match/Chat。必须经过:互选结果 → 双方分别确认开启沟通 → 才创建 Match Episode
19. **活动 Mutual 已有 Match 则复用** — 如果双方已有 active Match,活动互选确认后不创建新 Match,直接引导已有聊天
20. **活动 Mutual 曾 Unmatch 则新建** — 如果双方以前已 Unmatch,本次重新形成沟通时创建新 Match Episode
21. **咨询与红娘业务边界分离** — 婚恋咨询不得塞进红娘 Notes,两者权限、数据范围、服务记录必须分离
22. **Counselor 只能访问 Assigned Service** — 咨询人员默认只看到明确分配给自己的服务,不浏览全平台
23. **Content Editor 零用户数据权限** — 内容编辑员默认无用户婚恋数据访问权限
24. **Service Station Operator 不可浏览全用户库** — 服务站人员只能处理现场预约和指定任务
25. **主办单位关系不自动授予数据权限** — Organization relationship ≠ 用户数据访问权限,权限由 Role+Permission+DataScope 控制
26. **前端 Capability 控制入口** — 用户端各功能入口可见性由服务端 CapabilityService 返回决定,前端不自行拼状态判断
---
# 产品定位
面向丹阳市成年单身人士,由公益组织参与运营,集实名认证、本地资格核验、人工资料审核、双向婚恋匹配、安全沟通、公益红娘、线下公益活动、固定服务阵地、婚恋咨询、婚前辅导、婚恋课堂、婚恋反诈和婚俗新风于一体的本地公益婚恋综合服务平台。
---
# 技术栈
- Backend: Java 21 + Spring Boot 3.x + PostgreSQL + Redis + WebSocket + Flyway + S3-Compatible Private Object Storage
- Miniapp: 微信小程序原生 + TypeScript
- Admin Web: Vue 3 + TypeScript + Vite + Pinia + Element Plus
- Deployment: Docker + Docker Compose + Nginx
---
# API 规范
- Base URL: `/api/v1`
- 统一响应: `{ success, code, message, data }`
- 认证: `Authorization: Bearer <token>`
- 幂等: 关键接口支持 `Idempotency-Key`
- 新增 V1.1 聚合接口: `GET /api/v1/home`(HomeApplicationService 聚合)
---
# 核心 Invariant(V1.0 + V1.1)
## V1.0 不变量
- 未 Mutual 不可聊天
- Required 不可自动放宽
- Block 即时禁止互动
- 工作人员不能替用户 Like
- 成功牵手必须双确认
- 单向活动意向不泄露
- 敏感身份默认脱敏
- 跨组织默认拒绝
## V1.1 新增不变量
- INV-011: 未授权不能查看本地资格佐证
- INV-012: Counselor 只能读取 Assigned Service
- INV-013: Matchmaker 不能读取 Counseling 正文
- INV-014: Activity Mutual 不能直接创建 Match
- INV-015: 双方确认后才创建 Activity Match
- INV-016: Banner 不能任意外链
- INV-017: 首页 8 核心入口顺序固定
- INV-018: ServiceStationOperator 不能浏览全用户库
- INV-019: ContentEditor 不能访问用户婚恋档案
- INV-020: Sponsor 组织关系不自动赋予用户访问权限
---
# 新增领域模块
V1.1 在 V1.0 基础上新增以下领域模块:
```
banner/ — HomeBanner 管理
service_location/ — 善缘服务站
appointment/ — 服务预约
counseling/ — 婚恋咨询与婚前辅导
content/ — 婚恋课堂/反诈内容管理
service_program/ — 专项公益服务项目
local_eligibility/ — 本地资格核验
home/ — 首页聚合 API
```
---
# 新增 Operator 角色
```
service_station_operator — 服务站运营人员
counselor — 婚恋咨询人员
counseling_manager — 咨询管理人员
content_editor — 内容编辑员
```
---
# 开发流程
每阶段必须:
```
读取本阶段规则 → 确认数据模型 → 建立测试 → 实现后端 → 实现前端 → 运行测试 → 验证核心流程 → 更新文档 → 进入下阶段
```
Phase 完成后必须输出 Completion Report,不得自动进入下一阶段。
---
# 版本控制约定(本机环境强制,务必先读)
## 分支命名:禁止使用带 `/` 的嵌套名
本机存在一个**常驻监听进程**,会**即时(< 0.2 秒)删除 `refs/heads/` 下的嵌套子目录**。
2026-09-16 定向实验结果:
| ref 位置 | 结果 |
|---|---|
| `refs/heads/<单段名>`(如 `feat-ui-v11`) | **存活**(连续观测 30s 稳定) |
| `refs/heads/<任意>/<子名>`(嵌套) | **0.2s 内被删除**(连父目录一起) |
| `refs/tags/<任意深度>` | **存活** |
| `.git/` 下非 refs 的普通子目录 | **存活** |
**后果**:分支指针被删后 **HEAD 会悬空**(`ref: refs/heads/<被删分支>`)。此时
任何 `git commit` 会生成**根提交**,切断全部历史;`git status` 还会把全仓库文件标成新增。
**因此标准 Git Flow 的 `feature/`、`fix/`、`ui/` 等带斜杠前缀在本仓库一律不可用**,
必须使用**顶层单段名**(如 `feat-ui-v11`、`ui-acceptance`)。
## 提交后自保(本机环境必做)
```bash
git tag <name> <sha> # tag 不受清理影响,让提交变为可达,免被 gc 回收
git bundle create <file>.bundle <tag-name> # 参数必须是 ref 名;传裸 sha 会报 empty bundle
sleep 2 && ls .git/refs/heads/ && git log --oneline -1 # 回读验证,别信退出码
```
- `git update-ref` **返回退出码 0 不代表持久化成功**,必须回读验证。
- 判断是否有并发进程**不能看 reflog 署名**:本仓库 `git config user.name` 是一个与真实执行工具无关的固定占位值,
所有 reflog 条目都署名同一个名字,与该条目实际由谁产生无关。
- 若发现 HEAD 悬空(`git log` 报 `does not have any commits yet`),按以下方式恢复,
**不要触碰任何工作区文件**:
```bash
git symbolic-ref HEAD refs/heads/<顶层单段分支>
git reset -q # 仅同步索引,不改工作区
git status --short # 应干净
```
---
# 文档
- 主启动提示词: `docs/善缘丹阳 V1.1 WorkBuddy最终主启动提示词(整合版).md`
- Jira 任务清单: `docs/善缘丹阳 V1.1 WorkBuddy-Jira 最终开发任务增量清单.md`
- 开发执行计划: `docs/善缘丹阳 V1.1 WorkBuddy 开发执行计划修订版.md`
- 数据库/API设计: `docs/善缘丹阳 V1.1 数据库与API增量设计.md`
- 前端 UI/UX: `docs/superpowers/specs/2026-09-13-reference-driven-dual-client-ui-redesign-design.md`
- 页面级功能: `docs/善缘丹阳 V1.1 页面级功能清单与交互流程修订版.md`
- 状态跟踪: `docs/STATUS.md`
- 待确认项: `docs/PENDING_DECISIONS.md`
- 任务清单: `docs/JIRA_BACKLOG.md`
- 版本基线: `docs/ARCHITECTURE_BASELINE_V1.1.md`