# 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 | | geo_lat | float null | 附近的人 | | geo_lng | float null | | | geo_visible | bool | default false;开启后可被附近列表看到 | | gender | text null | | | relation_type | text null | partner/family/friend… when other | | created_at | timestamptz | | ### synastry_invites | column | type | notes | |---|---|---| | id | uuid PK | | | token | text unique | 分享路径 `/synastry/invite/:token` | | host_user_id | uuid FK→users | | | host_profile_id | uuid FK→profiles | | | expires_at | timestamptz | | | guest_user_id | uuid null | | | guest_profile_id | uuid null | | | report_id | uuid null FK→growth_reports | accept 后写入 | | 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 | | ### moods(P2 可先建表空用) | column | type | notes | |---|---|---| | id | uuid PK | | | user_id | uuid FK | | | day | date | | | score | int null | | | note | text null | | ### memory_items(P3) | column | type | notes | |---|---|---| | id | uuid PK | | | user_id | uuid FK | | | kind | text | | | payload | jsonb | | | created_at | timestamptz | | ### admin_accounts(Ops-A · ECR-006) | column | type | notes | |---|---|---| | id | uuid PK | | | username | text unique | | | password_hash | text | bcrypt | | status | text | active/disabled | | created_at | timestamptz | | | updated_at | timestamptz | | ### admin_sessions | column | type | notes | |---|---|---| | id | uuid PK | | | admin_id | uuid FK→admin_accounts | | | token | text unique | opaque | | expires_at | timestamptz | | | created_at | timestamptz | | ### admin_audit_logs | column | type | notes | |---|---|---| | id | uuid PK | | | admin_id | uuid FK | | | action | text | e.g. membership.grant | | target_type | text | user/order/… | | target_id | text | | | meta | jsonb | | | created_at | timestamptz | 只追加 | ### analytics_sessions(Ops-B · ECR-007) | column | type | notes | |---|---|---| | session_id | text PK | 客户端 session_id | | device_key | text | | | user_id | uuid FK null | | | started_at | timestamptz | | | ended_at | timestamptz null | | | exit_page | text null | | | duration_ms | int null | | ### analytics_events | column | type | notes | |---|---|---| | id | uuid PK | | | session_id | text FK→analytics_sessions | | | user_id | uuid FK null | | | name | text | page_view / page_leave / … | | page_path | text null | | | props | jsonb | 白名单键;无 PII | | client_ts | timestamptz | | | received_at | timestamptz | 只追加 | ### home_tools(Ops-C · ECR-008) | column | type | notes | |---|---|---| | id | uuid PK | | | row_index | smallint | 1 \| 2 | | sort_order | int | | | path | text | 站内相对路径 | | icon | text | HomeToolIcon 白名单 | | label | text | ≤16 字 | | badge | text null | | | badge_tone | text null | hot \| new | | enabled | bool | | | updated_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 admin_accounts 1──* admin_sessions admin_accounts 1──* admin_audit_logs users 1──* analytics_sessions 1──* analytics_events home_tools(运营配置宫格) scales.status published|draft ```