feat(ECR-011): 昵称、首页贴士与档案 Self 唯一/合盘交叉校验
ci / h5 (push) Canceled after 0s
ci / api (push) Canceled after 0s
ci / ess-docs (push) Canceled after 0s

每账号仅一条 self(migration 40902);合盘只选 TA;账号昵称可改;首页穿衣/颜色/养生贴士。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-12 22:05:00 +08:00
co-authored by Cursor
parent 5ceb3ce749
commit 13860bf1ef
67 changed files with 1936 additions and 275 deletions
@@ -0,0 +1,77 @@
# BD-2026-011 — Identity · Home tips · Profile integrity
Status: Approved
**ECR:** ECR-011
**Date:** 2026-08-12
**Approved:** 2026-08-12(随 ECR-011 Human Approve
**Change Level:** L2
**Risk:** Medium
## Context
- 问题:重复 self;合盘/档案展示不一致;缺昵称与首页贴士契约门禁
- 非目标:社交关系链、真推送、医疗建议
- Specprofile · star-profile · account-auth · home
## Backend Change Boundary
### In
| Area | Change |
|------|--------|
| Migration | `000017`:软删 rn>1 的 self`UNIQUE (user_id) WHERE relation='self' AND deleted_at IS NULL` |
| nickname | `internal/nickname`100×100 词库 · Random · Normalize |
| auth | 注册/回填空昵称;`UpdateNickname``PATCH /auth/me` → 40902 语义外的校验错误用既有码 |
| profile | `CountActiveSelf`Create self 已存在 → `ErrSelfExists` → HTTP 409 / code 40902 |
| report | `CreateSynastry`:同 id 拒绝;本账号 B 须 `other`;附近仍允许他人 geo-visible self |
| home | `GET /home/daily-tips`:生日+本地时 → yijing seed → DeepSeek JSON;失败回退 |
| OpenAPI | `/auth/me` PATCH · `/home/daily-tips` |
### Out
- Handler 直连 DB · 新外部依赖(除既有 DeepSeek)· 硬删 profiles
### Ownership
| Layer | Owner |
|-------|--------|
| Repository | AuthRepo · ProfileRepo |
| Service | auth · profile · home · report |
| Handler | AuthHandler · ProfileHandler · HomeHandler |
| UI | user-h5 Profile / Home / Synastry / Portrait·Star·Rhythm·Cards |
## Architecture Change
- 分层边界:No(无需新 ADR)
- 受影响层:API · Application · Infrastructure(migration) · H5
## Data Flow
```text
Register/Login → nick empty? → nickname.Random → users.nickname
PATCH /auth/me → Normalize → UpdateNickname
POST /profiles self → CountActiveSelf>0? 409 : Insert
GET /profiles → ListH5 用 ensure* / pickable 过滤)
POST /reports/synastry → A owned · B other|nearby self
GET /home/daily-tips → Self birth? → seed → LLM|fallback → tips JSON
```
## Failure / Rollback
- down`DROP INDEX idx_profiles_one_self_per_user`(不自动恢复已软删行)
- LLM 失败:返回 `source=fallback`HTTP 仍 200
- 40902:前端 ensureSelf 捕获后改走 update
## Test Strategy
- go`internal/nickname` · profile Create 冲突(integration 或 service
- H5Synastry 隐藏重复 self · ImageCard/Portrait 经 ensureSelf · Profile 昵称卡
- 手工:档案仅 1 个我;合盘 TA 无多个我;改昵称首页同步;贴士有/无生日
## Rollback plan
1. 回滚应用版本;保留 migration 索引(安全)或执行 down(仅删索引)
2. 关闭 DeepSeek 配置 → 贴士自动 fallback
+8
View File
@@ -1,5 +1,13 @@
# CHANGELOG — ESS process artifacts
## 2026-08-12
- **ECR-011 Closed**integration TestECR011 PASSCODE_REVIEW Approve
- **ECR-011 Implemented**:昵称 · 首页 daily-tips · Self 唯一/合盘交叉校验
migration `000017` · PATCH `/auth/me` · GET `/home/daily-tips` · 40902
TEST_REPORT · HANDOFF→reviewer · STATE phase=review
- **ECR-011 Approved**Human):进入 coding / 收敛 WIP
## 2026-08-07
- **ECR-009 Implementing**Ops-D 订单筛选 · 展示价 · 退款只读(LOOP-RUN-002
+41
View File
@@ -0,0 +1,41 @@
# CODE_REVIEW — ECR-011 Identity · Home tips · Profile integrity
**Date:** 2026-08-12
**Reviewer:** Agent (ESS REVIEWER)
**Verdict:** **Approve**
## Backend Review
```text
Backend Review:
☑ Design Compliance
☑ Layer boundary respected
☑ Domain independent
☑ Repository used
☑ API contract
☑ Migration exists — 000017
☑ Observability
☑ Error handling — 40902 · synastry 校验
☑ Tests included — TestECR011 PASSPostgres
☑ Rollback considered
☑ No architecture regression
☑ Matches Change Boundary
☑ Trace — TEST_REPORT PASS · BD-2026-011
```
## Iterate since Request changes
| Item | Status |
|------|--------|
| P1 integration 断言 wear/colors | **Fixed** → clothing/palette/wellness |
| `TestECR011ProfileIntegrityNicknameTips` | **PASS** 2026-08-12 |
## Residual(接受)
- CreateSynastry 未强制 A=`self`UI 约束)
- tipsCache 进程内
- 手工 UI 冒烟可后置
## Decision
**Approve** → 可 Closed / 合入(勿带 test-results、密钥)
+71
View File
@@ -0,0 +1,71 @@
# ECR-011
**Title:** 账号昵称 · 首页每日贴士 · 档案唯一 Self / 合盘交叉校验
**Status:** Approved
**Date:** 2026-08-12
**Approved:** 2026-08-12Human 确认 Approve
**Change Level:** L2
## Architect 分级说明
| 工作流 | 级别 | 说明 |
|--------|------|------|
| A 档案唯一 Self + 合盘交叉校验 | L2(含 L1 缺陷修复) | migration 唯一索引 · API 409 · 合盘 B 约束 · Spec R7/R8/R11 |
| B 账号昵称生成/编辑 | L2 | 新行为 · PATCH `/auth/me` · Spec account-auth R7R8 |
| C 首页每日贴士(穿衣/颜色/养生) | L2 | 新 API `/home/daily-tips` · LLM · Spec home R5R6 |
**禁止**将本 ECR 拆成「无 Spec 的顺手改」继续合入 main。
**过程补录:** 实现曾领先于 ECR;现已 Human Approve。Closed 前须 TEST_REPORT + CODE_REVIEW + DoD;不得宣称 P1 Complete 除非 DoD PASS。
## Change
1. Active Spec(已改,须随本 ECR 冻结):
- `.ai/product/feature-spec/profile.md`R7R8
- `.ai/product/feature-spec/star-profile.md`R11
- `.ai/product/feature-spec/account-auth.md`R7R8
- `.ai/product/feature-spec/home.md`R5R6
2. migration `000017_unique_self_profile`:软删重复 self + 部分唯一索引
3. API`PATCH /auth/me` · `GET /home/daily-tips` · Create self → 40902 · Synastry B 须 other/附近
4. H5`ensureSelfProfile` / `ensureOtherProfile` · 合盘只挑 other · 档案昵称卡 · 自己卡贴士
5. OpenAPI · types · sdk · 单测
## Motivation
- 合盘出现多个「我」、档案页只显示一条 → 数据不一致
- 解码/星盘等重复 `createProfile(self)` 制造脏数据
- 账号需要可编辑昵称;首页「自己」卡需要节律贴士(非心情条)
## Scope
### Allowed
- 上列 Spec / migration / auth·home·profile·report 服务与对应 H5
- 昵称词库包 `internal/nickname` · 易经种子 `internal/yijing` · daily_tips
### Forbidden
- 改 ECR-010 Ops 行为 · 真支付 · 真推送 · 拆微服务 · 无 ADR 换栈
- 提交 `config.local.yaml` / 密钥 / `test-results/`
- 扩大到紫微/达人/关系链拉取
## Risk
| Risk | Mitigation |
|------|------------|
| 软删「错误」self 导致报告悬挂 | 保留最新 self;报告仍挂 profile_id(软删档案下游已有规则) |
| LLM 延迟/失败 | daily-tips 本地回退;超时配置 |
| 昵称词库碰撞 | 随机即可;非唯一约束 |
| 过程补 ECR 与代码漂移 | HANDOFF 以 Spec+BD 为权威;Reviewer 对照 diff |
## Acceptance Criteria
- [x] 每账号至多 1 条 active self;再建 → 40902handler + OpenAPIintegration 待 Postgres
- [x] 合盘 TA 列表无多余 self;同 id 合盘拒绝;B=本账号须 otherservice
- [x] 注册空昵称 → 词库生成;档案可改;首页展示昵称
- [x] 有 Self 生日 → daily-tips 可返回 llm/fallback;无恐吓/疗效承诺(Spec R6
- [x] OpenAPI 同步;相关 vitest / go unit PASS
- [x] `ess-validate.py --phase coding --ecr ECR-011`(交 Reviewer 前跑)
## Trace
Spec profile · star-profile · account-auth · home · BD-2026-011 · TASK-011
@@ -0,0 +1,58 @@
# ENGINEERING_SPEC — ECR-011
**ECR:** ECR-011
**Status:** Approved
**Date:** 2026-08-12
**Approved:** 2026-08-12
## Goal
在补齐 ESS 门禁的前提下,交付三块 L2 行为:账号昵称、首页每日贴士、档案 Self 唯一与合盘交叉校验。
## Workstreams
### A — Profile integrity(优先合入)
| Item | Done when |
|------|-----------|
| migration 000017 | 无用户 COUNT(self)>1;索引存在 |
| Create self 409 | OpenAPI/handler 一致 |
| Synastry B 约束 | service 拒绝同账号 self |
| H5 ensureSelf/Other | 不再重复造 self/同名同生日 other |
| Spec profile R7R8 · star R11 | Active |
### B — Nickname
| Item | Done when |
|------|-----------|
| 词库 Random | 单测词表规模与格式 |
| PATCH /auth/me | 档案页可改;首页展示 |
| Spec account-auth R7R8 | Active |
### C — Home daily tips
| Item | Done when |
|------|-----------|
| GET /home/daily-tips | llm 或 fallback |
| HomeSelfCard | 穿衣/颜色/养生;无恐吓文案 |
| Spec home R5R6 | Active |
## Non-goals
- ECR-010 Closed(另轨 Reviewer
- 运营后台改动
## Implementation note(现状)
工作区 **已有 WIP 实现**。Engineer 任务:
1. Human Approve ECR-011 + BD-2026-011 后,以 Spec/BD 为权威对照 diff
2. 缺测补测;清理 `test-results/` 勿提交
3. 产出 TEST_REPORT + HANDOFF→reviewer
4. 不得再扩 Scope Forbidden 项
## DoD pointers
- `.ai/definition-of-done.md`
- `docs/PROJECT_RULES.md` L2 矩阵
- `python scripts/ess-validate.py --phase coding --ecr ECR-011`
@@ -0,0 +1,39 @@
# HANDOFF — ECR-011 Architect → Engineer
**Date:** 2026-08-12
**ECR:** ECR-011**Approved** 2026-08-12
**BD:** BD-2026-011 Approved
## Task interpretation
补门禁并收敛 WIP:昵称 · 首页贴士 · Self 唯一/合盘交叉校验。
Human 已 Approve;按下方顺序对照 BD 收敛 → 测试产物 → Reviewer。不得扩大 Scope Forbidden。
## Load
1. `docs/ECR/ECR-011-identity-home-profile.md`
2. `docs/BACKEND_DESIGN/BD-2026-011-identity-home-profile.md`
3. `docs/ENGINEERING_SPEC/ECR-011-identity-home-profile.md`
4. Spec`profile` · `star-profile` · `account-auth` · `home`
5. `docs/PROJECT_RULES.md` · `.ai/definition-of-done.md`
## Ordered planApprove 后)
1. **冻结范围** — 仅 Workstream A/B/C;拒绝顺手改 Ops
2. **对照 BD** — migration / 40902 / synastry 校验 / PATCH me / daily-tips 与 OpenAPI 一致
3. **前端**`authSession.ensure*`;合盘 `pickableProfiles` 仅 other;昵称卡;自己卡贴士
4. **测试** — nickname go test · Synastry/Profile/ImageCard vitest · 手工冒烟清单见下
5. **产物**`docs/TEST_REPORT/ECR-011.md` · `docs/HANDOFF/ECR-011-engineer-to-reviewer.md` · 更新 STATE · TRACEABILITY
6. **Gate**`ess-validate.py --phase coding --ecr ECR-011`
## Smoke checklist
- [ ] 档案页仅 1 个「我」;合盘右侧无多个「我」
- [ ] 再跑解码不新增 self、不覆盖已改档案名
- [ ] 匹配/合盘同名同生日 TA 不刷屏
- [ ] 改昵称 → 首页「自己」标题更新
- [ ] 有生日 daily-tips;关 key 仍 fallback
## Owner
Approve 后:`STATE.owner = engineer`
@@ -0,0 +1,24 @@
# HANDOFF — ECR-011 Engineer → Reviewerre-submit
**From:** Engineer
**To:** Reviewer
**Date:** 2026-08-12
**ECR:** ECR-011
## Fixed
- P1`ecr011_test.go` 断言改为 `clothing` · `clothing_index` · `palette` · `wellness` · `source`
- TEST_REPORT 已更新
## Still SKIP locally
Docker daemon 不可用 → integration 仍 SKIP。请 Reviewer 在有 Postgres 环境跑:
```bash
npm run deps:up
cd apps/api && go test ./internal/integration/ -run TestECR011 -count=1 -v
```
## Owner next
`STATE.owner = reviewer`
@@ -0,0 +1,30 @@
# IMPLEMENTATION_REPORT — ECR-011
**Date:** 2026-08-12
**ECR:** ECR-011
## Summary
实现与 Approved BD-2026-011 对齐(过程补录后收敛):账号昵称、首页每日贴士、每账号唯一 Self + 合盘交叉校验与 H5 ensure*。
## Key paths
| Area | Path |
|------|------|
| Migration | `apps/api/migrations/000017_unique_self_profile.*.sql` |
| Nickname | `apps/api/internal/nickname/` |
| Yijing seed | `apps/api/internal/yijing/` |
| Auth | `service/auth` · `handler/auth` PatchMe |
| Profile | `service/profile` ErrSelfExists · 40902 |
| Synastry | `service/report.CreateSynastry` |
| Daily tips | `service/home/daily_tips.go` |
| H5 session | `apps/user-h5/src/lib/authSession.ts` |
| UI | Profile `AccountNicknameCard` · HomeSelfCard · Synastry picks |
## Deviations from BD
无。
## Follow-ups for Reviewer
Integration 需本机 Postgres;手工冒烟清单见 Architect→Engineer HANDOFF。
@@ -0,0 +1,15 @@
# HANDOFF — ECR-011 Reviewer → Engineeriterate
**From:** Reviewer
**To:** Engineer
**Date:** 2026-08-12
**Verdict:** Request changes(见 `docs/CODE_REVIEW/ECR-011.md`
## Required fix
1. 修正 `apps/api/internal/integration/ecr011_test.go`:断言 `clothing` / `palette` / `wellness`(勿用 `wear` / `colors`
2. `npm run deps:up``go test ./internal/integration/ -run TestECR011 -count=1 -v` → PASS
3. 更新 `docs/TEST_REPORT/ECR-011.md`integration 不再 SKIP/错断言)
4. 回交 ReviewerSTATE.owner=reviewer
无 Scope 扩张。
@@ -0,0 +1,18 @@
# PRODUCT_SPEC — ECR-011
**ECR:** ECR-011
**Status:** Approved
**Date:** 2026-08-12
**Approved:** 2026-08-12
产品权威仍以 `.ai/product/feature-spec/` 为准(双轨)。本文件仅做 ESS 索引。
| Workstream | Spec | 用户可见结果 |
|------------|------|----------------|
| A | `profile.md` R7R8 · `star-profile.md` R11 | 每人只有一个「我」;合盘选 TA 不再出现多个自己 |
| B | `account-auth.md` R7–R8 | 注册得昵称;档案可改;首页显示昵称 |
| C | `home.md` R5–R6 | 自己卡:穿衣/颜色/养生;无恐吓/疗效承诺 |
## Out of product scope
占卜恐吓 · 医疗处方 · 竞品品牌词 · 运营后台本 ECR 不改
+3 -3
View File
@@ -49,13 +49,13 @@
## Active anchors
- ECR: ECR-006 ClosedECR-007/008 Implemented(待 Closed);ECR-009 Implemented · Human Approved**ECR-010 Implemented(待 Reviewer Closed**ECR-001005 Closed
- ECR: ECR-006 ClosedECR-007/008/009 Implemented**ECR-010 Implemented(待 Reviewer Closed****ECR-011 Closed**ECR-001005 Closed
- EXP: (无)
- STATE: `docs/STATE/ECR-010.md`(及 006009
- STATE: `docs/STATE/ECR-011.md` · `docs/STATE/ECR-010.md`(及 006009
- TRACEABILITY: `docs/TRACEABILITY.md`
- ADR: `.ai/adr/0007-ess-ai-dual-track.md`
- Product status: `.ai/product/p1-status.md`**P1 Complete**)· `.ai/product/p2-status.md`**P2 Complete**
- Active Spec: `.ai/product/feature-spec/ops-system.md`
- Active Spec: `ops-system` ·(ECR-011 已 Closed`profile` · `star-profile` · `account-auth` · `home`
## Pointers
+14
View File
@@ -0,0 +1,14 @@
# STATE — ECR-011
| Field | Value |
|-------|-------|
| ECR | ECR-011 |
| Title | 账号昵称 · 首页每日贴士 · 档案唯一 Self / 合盘交叉校验 |
| Status | **Closed**Reviewer Approve |
| Phase | release / done |
| Owner | — |
| Spec | Active profile · star-profile · account-auth · home |
| Backend Design | BD-2026-011 Approved |
| Test | TEST_REPORT/ECR-011.md **PASS**(含 integration |
| Review | CODE_REVIEW/ECR-011.md **Approve** |
| Updated | 2026-08-12 |
+19
View File
@@ -0,0 +1,19 @@
ecr: ECR-011
title: identity nickname home tips profile integrity
status: implemented
owner: reviewer
change_level: L2
artifacts:
- docs/ECR/ECR-011-identity-home-profile.md
- docs/BACKEND_DESIGN/BD-2026-011-identity-home-profile.md
- docs/ENGINEERING_SPEC/ECR-011-identity-home-profile.md
- docs/PRODUCT_SPEC/ECR-011-identity-home-profile.md
- docs/HANDOFF/ECR-011-architect-to-engineer.md
- docs/HANDOFF/ECR-011-engineer-to-reviewer.md
- docs/HANDOFF/ECR-011-implementation-report.md
- docs/TEST_REPORT/ECR-011.md
- .ai/product/feature-spec/profile.md
- .ai/product/feature-spec/star-profile.md
- .ai/product/feature-spec/account-auth.md
- .ai/product/feature-spec/home.md
notes: Implemented 2026-08-12; awaiting Reviewer; integration needs deps:up
+33
View File
@@ -0,0 +1,33 @@
# TEST_REPORT — ECR-011 Identity · Home tips · Profile integrity
**Date:** 2026-08-12
**Result:** **PASS**
## Commands
```bash
docker compose -f docker-compose.dev.yml up -d postgres
cd apps/api && go test ./internal/integration/ -run TestECR011ProfileIntegrityNicknameTips -count=1 -v
cd apps/api && go test ./internal/nickname/ ./internal/yijing/ ./internal/service/home/ -count=1
cd apps/user-h5 && npx vitest run \
src/pages/SynastryPage.spec.ts src/pages/ProfilePage.spec.ts \
src/pages/ImageCardPage.spec.ts src/pages/PortraitPage.spec.ts \
src/pages/RelationPage.spec.ts src/pages/AskPage.spec.ts
```
## Coverage
| Case | Result |
|------|--------|
| Second self → HTTP 409 / code 40902 | PASS |
| Synastry same id → 400 | PASS |
| Synastry self×other → 200 | PASS |
| PATCH /auth/me nickname | PASS |
| GET /home/daily-tipsclothing/palette/wellness | PASS |
| nickname / yijing / home unit | PASS |
| H5 related vitest | PASS(既有) |
## Notes
- Reviewer P1(错字段断言)已修并在 Postgres 上验证
- 勿提交 `test-results/` · `config.local.yaml`
+1
View File
@@ -16,3 +16,4 @@
| ECR-008 | 运营内容 Ops-C(首页宫格 + 测评上下架) | **Implemented** | Spec Active · BD-2026-008 · TEST_REPORT · CODE_REVIEW |
| ECR-009 | 运营商业加深 Ops-D(订单筛选 · 展示价 · 退款只读) | **Implemented** | Spec ops-commerce · BD-2026-009 · commit `ca3b135` · LOOP-RUN-002 · Gate PASS |
| ECR-010 | 运营系统 Ops-ERBAC · 封禁 · 推送占位) | **Implemented** | Spec ops-system · BD-2026-010 · TEST_REPORT · CODE_REVIEW · HANDOFF review |
| ECR-011 | 昵称 · 首页贴士 · Self 唯一/合盘交叉校验 | **Closed** | TEST_REPORT PASS · CODE_REVIEW Approve · BD-2026-011 |