docs: freeze YuXinGu lexicon, journey, and P1 engineering sources

Establish product language contract, user journey with dual growth engines,
ERD/OpenAPI/Go boundaries, and H5 routes (/profile, /portrait, /relation,
/membership) before P1 implementation.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-02 16:12:10 +08:00
co-authored by Cursor
parent 2fb1dfee14
commit dd94e57277
40 changed files with 1283 additions and 800 deletions
+4 -3
View File
@@ -1,6 +1,7 @@
# Domain docs
# Domain
| File | Purpose |
|---|---|
| [../domain.md](../domain.md) | Ubiquitous language — terms only |
| [domain-map.md](domain-map.md) | Bounded contexts, aggregates, ER sketch |
| [../domain.md](../domain.md) | Tech ↔ 用户名 |
| [domain-map.md](domain-map.md) | Bounded contexts(冻结) |
| [erd.md](erd.md) | P1 表结构草案(冻结) |
+31 -172
View File
@@ -1,183 +1,42 @@
# Domain Map — 愈心谷(DDD 视角
# Domain Map — 冻结(P1 工程真源
给后端 / DB / OpenAPI / SDK 用的**能力域与实体图**。
词汇以 [../domain.md](../domain.md) 为准;产品范围以 [../product/feature-map.md](../product/feature-map.md) 为准。
竞品能力对照:[../product/cece-feature-map.md](../product/cece-feature-map.md)。
AI 生成表结构或 API 时:先落本图中的 Context / Aggregate,再写 migration;禁止发明未列出的聚合根名。
变更本文件或 ERD 需简短 ADR。词汇:[../domain.md](../domain.md) · ERD[erd.md](erd.md) · API`proto/openapi.yaml` · Go 边界:[../architecture/go-services.md](../architecture/go-services.md)
---
## 1. Bounded Contexts
## Bounded Contexts
| Context | Aggregates | P1 | Owner package |
|---|---|---|---|
| Identity | User, Session, DeviceIdentity | Yes | `internal/service/user` |
| Profile | Profile | Yes | `internal/service/profile` |
| Discovery | Portrait, Scale, ScaleResult, GrowthReport | Yes | `portrait`, `scale`, `report` |
| Relation | RelationInsight | Yes **必做** | `relation` |
| Ask | AskThread, AskMessage, AskQuota | Skeleton | `ask` |
| Companion | Mood, SolarTerm | Shell | `companion` |
| Memory | MemoryItem | P2/P3 | `memory` |
| Commerce | Subscription, Membership, Order, Payment, DeepAccess | Yes mock | `order`, `membership` |
| Consult | — | P3 | — |
---
## Context diagram
```
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Identity │──▶│ Profile │──▶│ Discovery │
│ (User) │ │ Life Archive│ │ Decode/Scale│
└─────────────┘ └──────┬───────┘ └──────┬──────┘
│ │
▼ ▼
┌──────────────┐ ┌─────────────┐
│ Relationship │ │ Ask │
│ Match │ │ Companion │
└──────┬───────┘ └──────┬──────┘
│ │
▼ ▼
┌─────────────────────────────────┐
│ Commerce │
│ Subscription / Order / Unlock │
└─────────────────────────────────┘
┌──────────────┼──────────────┐
▼ ▼ ▼
ContentFeed GrowthShare Consult(*)
(* later)
Identity → Profile → Discovery(Portrait/Scale/GrowthReport)
↘ RelationInsight ← P1 双引擎
↘ Ask (+ Memory later)
↘ Companion
Commerce(DeepAccess/Membership)
```
| Context | 职责 | MVP |
|---|---|---|
| **Identity** | Visitor/User/Session | Yes |
| **Profile** | Self/Other 生命档案 | Yes |
| **Discovery** | Decode、Scale、Report 生成 | Yes |
| **Relationship** | Match | Yes |
| **Ask** | 档案上下文对话、额度 | Skeleton |
| **Companion** | SolarTerm、Mood | Skeleton |
| **Commerce** | Subscription、Membership、Order、Unlock、Payment | Yes (mock) |
| **Content** | Feed 配置 | Static OK |
| **Growth** | Share 卡片元数据 | Minimal |
| **Consult** | 真人顾问 Marketplace | No |
| **Recommendation** | 推荐 | V1 rules |
---
## 2. Aggregates & Entities(命名强制)
## Invariants
### Identity
| Type | Name | Notes |
|---|---|---|
| Aggregate | **User** | 注册主体 |
| Entity | Session | token 会话 |
| Entity | DeviceIdentity | Visitor 匿名 |
### Profile(生命档案)
| Type | Name | Notes |
|---|---|---|
| Aggregate | **Profile** | `relation`: self \| other |
| VO | BirthInput | datetime/place optional later |
| VO | RelationType | partner/family/friend/… |
### Discovery
| Type | Name | Notes |
|---|---|---|
| Aggregate | **Report** | type: decode \| match \| … |
| Domain Svc | DecodeEngine | 可复算;结果入 Report |
| Aggregate | **Scale** | 量表定义 |
| Entity | ScaleQuestion | |
| Aggregate | **ScaleResult** | 作答 + 计分 |
### Relationship
| Type | Name | Notes |
|---|---|---|
| Aggregate | **Match** | 引用两个 Profile;产出 Report 或嵌入 |
### Ask / Companion
| Type | Name | Notes |
|---|---|---|
| Aggregate | **AskThread** | 挂 profile_id |
| Entity | AskMessage | role user/assistant |
| Entity | AskQuota | 与 Membership 联动 |
| Aggregate | **Mood** | 日维度打卡 |
| Read Model | **SolarTerm** | 日历内容;可配置表 |
### Commerce
| Type | Name | Notes |
|---|---|---|
| Aggregate | **Subscription** | 计划 SKU |
| Aggregate | **Membership** | 用户权益状态 |
| Aggregate | **Order** | 订阅或 Unlock |
| Entity | Payment | mock / 渠道 |
| Entity | Unlock | order → report 解锁 |
### Content / Growth(薄)
| Type | Name | Notes |
|---|---|---|
| Entity | FeedItem | 运营配置 |
| VO | SharePayload | 分享卡字段 |
### ConsultLater
| Type | Name | Notes |
|---|---|---|
| Aggregate | Consultant | |
| Aggregate | ConsultOrder | |
| Entity | ConsultSession | |
---
## 3. 关键关系(ER 草图)
```
User 1──* Profile
Profile 1──* Report
Profile 1──* AskThread
User 1──* ScaleResult
User 1──0..1 Membership
User 1──* Order
Order 0..1── Unlock ──▶ Report
Profile ── Match ── Profile
User 1──* Mood
```
权益规则:**Membership / Unlock 只由服务端判定**;客户端不可信任。
---
## 4. Context → 代码落点
| Context | Go | H5 |
|---|---|---|
| Identity | `internal/service/user` | login / mine |
| Profile | `service/profile` | decode form, mine |
| Discovery | `service/report`, `service/scale` | decode, explore, report |
| Relationship | `service/match` | match |
| Ask | `service/ask` | ask tab |
| Companion | `service/companion` | companion tab |
| Commerce | `service/order`, `membership` | paywall, mine |
包名只用 `domain.md` 词汇:`user` `profile` `report` `order` `membership` `scale` `ask` `mood`
---
## 5. 测测域 → 愈心谷域 映射
| 测测概念 | 愈心谷 |
|---|---|
| 星盘档案 | **Profile**(生日+体质相关输入) |
| 测测 AI | **Ask** |
| 真人 1v1 | **Consult**(后置) |
| MBTI 等 | **Scale** |
| 缘分合盘 | **Match**(合规叙事) |
| 今日运势 | **SolarTerm** + 生活建议(替换) |
| 会员 | **Subscription / Membership** |
| AI 玩法广场 | **[No] MVP** |
| 心情打卡 | **Mood** |
| 沙盘/心情小镇 | **[No]** |
---
## 6. 生成顺序(给 AI
1. 改范围 → 更新 `product/feature-map.md` MVP 标记
2. 新实体 → 本文件 + `domain.md` 词条(若新词)
3. migration → `playbooks/new-table.md`
4. API → `playbooks/add-api.md` + OpenAPI
5. 页面 → `playbooks/new-page.md` + design contract
下一步可选:单独 `apps/docs/erd.md` 或 migrations 初稿(本任务不强制)。
1. GrowthReport 完整字段仅当 Membership active **或** DeepAccess 存在。
2. Ask 必须绑定 `profile_id`Self 或 Other)。
3. RelationInsight 引用两个 Profile;禁止无档案的「合婚」式空算。
4. 客户端不可信任本地「已深度版」标志。
5. 禁止吉凶/运势类字段名进入 schema(如 `luck_score`)。
+172
View File
@@ -0,0 +1,172 @@
# ERD — P1 Schema(冻结草案)
实现时用 migration 落地;列名可微调但**表/聚合关系不得偏离**。
类型:Postgres。敏感:生日等属 Profile,需可删账号级联。
---
## Tables
### users
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| created_at | timestamptz | |
| status | text | active/deleted |
### device_identities
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| device_key | text unique | Visitor |
| user_id | uuid null FK→users | 升级后绑定 |
### profiles
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| user_id | uuid FK→users | |
| relation | text | self \| other |
| display_name | text | |
| birth_date | date | required P1 |
| birth_time | time null | optional |
| birth_place | text null | optional |
| gender | text null | |
| relation_type | text null | partner/family/friend… when other |
| created_at | timestamptz | |
### scales
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| slug | text unique | |
| title | text | 探索测试标题 |
| status | text | published/draft |
### scale_questions
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| scale_id | uuid FK | |
| sort | int | |
| body | jsonb | 题干与选项 |
### scale_results
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| user_id | uuid FK | |
| scale_id | uuid FK | |
| profile_id | uuid FK | |
| answers | jsonb | |
| result | jsonb | 探索结果摘要(可公开字段) |
| created_at | timestamptz | |
### growth_reports
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| user_id | uuid FK | |
| profile_id | uuid FK | |
| type | text | portrait \| relation \| … |
| summary | jsonb | **基础版**,始终可按规则返回 |
| detail | jsonb | **深度版**,服务端按权益剥离 |
| created_at | timestamptz | |
### relation_insights
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| user_id | uuid FK | |
| profile_a_id | uuid FK | usually self |
| profile_b_id | uuid FK | other |
| summary | jsonb | 对比标签等基础 |
| report_id | uuid null FK→growth_reports | 深度建议所在报告 |
| created_at | timestamptz | |
### ask_threads
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| user_id | uuid FK | |
| profile_id | uuid FK | 当前解读对象 |
| created_at | timestamptz | |
### ask_messages
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| thread_id | uuid FK | |
| role | text | user \| assistant |
| content | text | |
| created_at | timestamptz | |
### memberships
| column | type | notes |
|---|---|---|
| user_id | uuid PK FK→users | |
| plan | text | month/quarter/year |
| status | text | active/expired |
| expires_at | timestamptz | |
| ask_quota_left | int | |
### orders
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| user_id | uuid FK | |
| kind | text | membership \| deep_access |
| amount_cents | int | |
| status | text | created/paid/failed |
| created_at | timestamptz | |
### payments
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| order_id | uuid FK | |
| channel | text | mock \| wechat… |
| status | text | |
| raw | jsonb null | |
### deep_accesses
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| user_id | uuid FK | |
| report_id | uuid FK→growth_reports | |
| order_id | uuid FK | |
| created_at | timestamptz | |
### moodsP2 可先建表空用)
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| user_id | uuid FK | |
| day | date | |
| score | int null | |
| note | text null | |
### memory_itemsP3
| column | type | notes |
|---|---|---|
| id | uuid PK | |
| user_id | uuid FK | |
| kind | text | |
| payload | jsonb | |
| created_at | timestamptz | |
---
## Relationship sketch
```
users 1──* profiles
users 1──* scale_results
users 1──* growth_reports
users 1──0..1 memberships
users 1──* orders 1──* payments
growth_reports 1──* deep_accesses
profiles ── relation_insights ── profiles
users 1──* ask_threads 1──* ask_messages
```