集合:树洞帖子(posts)
1. 目的与使用场景
- 承载树洞社区内容,支持发帖、草稿自检、风控审核、行动卡生成与温和守护。由
/api/treehole/posts、风险提示服务、行动卡同步、埋点treehole_post_publish使用。
枚举值:
- anonymity_mode:
anon(完全匿名)、pseudonym(匿名昵称) - topic:
general(综合)、relationship(关系)、study(学习)、emotion(情绪)、other(其他) - risk_level:
L1(一般)、L2(关注)、L3(需要干预)、L4(紧急危机) - status:
draft(草稿)、pending_review(待审核)、published(已发布)、removed(已删除)、archived(已归档) - risk_flag:
none(无风险)、watch(观察中)、escalated(已升级)、crisis(危机)
2. Schema 定义
| 字段 | 类型 | 必填 | 默认值 | 约束/校验 | 说明 | 隐私分级 |
|---|---|---|---|---|---|---|
| _id | string | 是 | - | TCB 自动 | 主键 | P2 |
| _openid | string | 是 | - | TCB 自动 | 作者 openid | P2 |
| user_id | 指针id | 是 | - | 指向 users._id | 用户 | P2 |
| alias_name | string | 否 | - | 长度 ≤ 20 | 匿名展示名 | P1 |
| anonymity_mode | string | 是 | anon | 枚举(anon,pseudonym) | 匿名模式 | P1 |
| content | string | 是 | - | 长度 ≤ 4000 | 正文(预处理脱敏) | P3 |
| content_vector_id | string | 否 | - | - | 语义索引用向量 ID | P2 |
| tags | array | 否 | [] | - | 主题标签 | P1 |
| topic | string | 否 | general | 枚举(general,relationship,study,emotion,other) | 话题分类 | P1 |
| mood_thermometer | number | 否 | - | 0-100 | 情绪温度 | P3 |
| risk_score | number | 否 | 0 | 0-1 | 风险模型分值 | P3 |
| risk_level | string | 否 | L1 | 枚举(L1/L2/L3/L4) | 风险等级 | P3 |
| risk_factors | array | 否 | [] | 元素为 string | 风险因素 | P3 |
| status | string | 是 | draft | 枚举(draft,pending_review,published,removed,archived) | 状态 | P1 |
| moderation_result | object | 否 | - | {auto:'pass', manual:'pending', risk_level:'L1'} | 审核记录 | P2 |
| action_card_id | 指针id | 否 | - | 指向 tasks._id | 行动卡引用 | P2 |
| self_check_result | object | 否 | - | {etiquette_confirmed, anonymity_choice, risk_aware} | 草稿自检结果 | P2 |
| comment_count | number | 否 | 0 | - | 评论数 | P1 |
| hug_count | number | 否 | 0 | - | 抱抱数 | P1 |
| favorite_count | number | 否 | 0 | - | 收藏数 | P1 |
| report_count | number | 否 | 0 | - | 被举报数 | P2 |
| is_featured | bool | 否 | false | - | 精选状态 | P1 |
| risk_flag | string | 否 | none | 枚举(none,watch,escalated,crisis) | 风险标记 | P3 |
| intervention_triggered | bool | 否 | false | - | 是否触发干预 | P3 |
| guardian_notified | bool | 否 | false | - | 守护者已通知 | P3 |
| content_hash | string | 否 | - | - | 内容哈希(去重) | P2 |
| last_interaction_at | date | 否 | - | - | 最后互动时间 | P1 |
| createdAt | date | 是 | - | 服务端时间 | 创建时间 | P1 |
| updatedAt | date | 是 | - | 服务端时间 | 更新时间 | P1 |
| publishedAt | date | 否 | - | - | 发布时间 | P1 |
| is_deleted | bool | 否 | false | - | 软删 | P1 |
3. 索引与唯一约束
- 单字段索引:
status、risk_flag、topic、risk_level、content_hash - 复合索引:
[status, publishedAt desc]、[risk_flag, createdAt desc]、[user_id, status, createdAt desc]、[topic, is_featured, publishedAt desc] - 唯一性约束:
[content_hash]用于内容去重 - 设计理由:信息流需按发布时间倒序;风控后台按风险级别筛查;用户帖子查询;话题和精选内容推荐;内容去重避免重复发布。
4. 访问控制(TCB 权限)
{
"read": "status == 'published' || _openid == auth.openid || auth.role in ['moderator','counselor']",
"write": "_openid == auth.openid || auth.role in ['moderator']"
}匿名读写采用 openid 控制;审核员和辅导员可查看未发布内容。
- 关系与级联
user_id→usersaction_card_id→tasks(或 action_cards 服务)- 与
comments、reports、sos形成引用 - 删除策略:软删;若被移除则级联将
comments标记不可见但保留审计。 - 反范式:
comment_count、hug_count减少聚合压力;更新时需事务同步。
- 数据生命周期与合规
- 留存:发布内容长期保留;删除/举报通过软删并保留 180 天审计。
- 匿名化:内容存储前通过 NLP 清理身份信息;导出给辅导员时附带风险摘要而非原文。
- 用户导出:仅提供本人发帖原文,需通过身份验证。
- 审计字段:
createdAt、updatedAt、publishedAt、risk_score。
API/云函数契约映射 | 接口/函数 | 读/写 | 使用字段 | 过滤条件 | 排序/分页 | 备注 | |
/api/treehole/postsGET | 读 | alias_name, content, tags, hug_count, comment_count, publishedAt, risk_level |status='published'|publishedAt desc| 树洞信息流 | |/api/treehole/postsPOST | 写 | content, tags, mood_thermometer, anonymity_mode, self_check_result |_openid = auth.openid| - | 发帖/草稿自检 | |/api/treehole/postsPATCH | 写 | status, moderation_result, risk_flag, risk_level |_id匹配 | - | 审核/下线 | | 风险提示服务riskScan| 写 | risk_score, risk_flag, risk_level, risk_factors, intervention_triggered | - | - | AI 风控写回 | | 行动卡云函数createActionCard| 写 | action_card_id, status | - | - | 生成任务 | | 干预服务interventionService| 写 | intervention_triggered, guardian_notified, risk_flag |risk_level in ['L3','L4']| - | 危机干预 |示例文档(≥3条)
{
"_id": "post_900",
"_openid": "oAbcd123",
"user_id": "usr_001",
"alias_name": "小蓝鲸",
"anonymity_mode": "anon",
"content": "最近准备考研,和室友节奏不同有点焦虑,想听听建议。",
"tags": ["考研", "室友"],
"topic": "study",
"mood_thermometer": 38,
"risk_score": 0.35,
"risk_level": "L2",
"risk_factors": ["焦虑", "压力"],
"status": "published",
"comment_count": 5,
"hug_count": 18,
"favorite_count": 3,
"risk_flag": "watch",
"content_hash": "a1b2c3d4",
"publishedAt": "2024-04-05T15:30:00Z",
"createdAt": "2024-04-05T15:00:00Z",
"updatedAt": "2024-04-05T15:30:00Z"
}
{
"_id": "post_901",
"_openid": "oAbcd456",
"user_id": "usr_002",
"anonymity_mode": "pseudonym",
"alias_name": "晨曦",
"content": "今天心情不错,分享一下和辅导员聊天的感受。",
"tags": ["正能量"],
"topic": "emotion",
"mood_thermometer": 75,
"risk_score": 0.15,
"risk_level": "L1",
"status": "published",
"comment_count": 2,
"hug_count": 6,
"favorite_count": 1,
"risk_flag": "none",
"publishedAt": "2024-04-06T09:20:00Z",
"last_interaction_at": "2024-04-06T10:15:00Z",
"createdAt": "2024-04-06T09:05:00Z",
"updatedAt": "2024-04-06T09:20:00Z"
}
{
"_id": "post_950",
"_openid": "oAbcd789",
"user_id": "usr_guard_01",
"anonymity_mode": "anon",
"content": "值班提示:今晚 22 点树洞上线睡眠主题行动卡。",
"tags": ["公告"],
"topic": "other",
"mood_thermometer": 50,
"risk_score": 0.05,
"risk_level": "L1",
"status": "pending_review",
"moderation_result": {"auto": "pass", "manual": "pending", "risk_level": "L1"},
"risk_flag": "none",
"self_check_result": {"etiquette_confirmed": true, "anonymity_choice": "anon", "risk_aware": true},
"content_hash": "e5f6g7h8",
"createdAt": "2024-04-06T08:00:00Z",
"updatedAt": "2024-04-06T08:00:00Z"
}- 常用查询样例(≥3条)
// 信息流第一页
const feed = await db.collection('posts').where({ status: 'published' })
.orderBy('publishedAt', 'desc')
.limit(20)
.get();
// 风控筛查 watch 标记
const riskList = await db.collection('posts').where({ risk_flag: db.command.in(['watch','escalated']) })
.orderBy('createdAt', 'desc')
.limit(100)
.get();
// 用户的草稿箱
const drafts = await db.collection('posts').where({
_openid: auth.openid,
status: 'draft'
}).orderBy('updatedAt', 'desc').get();- 边界与错误码
- 草稿自检失败:NLP 触发高风险返回
E_POST_RISK_HIGH,需调整内容。 - 超过限制:超过 4000 字返回
E_POST_TOO_LONG。 - 内容重复:content_hash 重复返回
E_POST_DUPLICATE_CONTENT。 - 风险升级:L3/L4 级别自动触发干预流程,返回
E_POST_INTERVENTION_TRIGGERED。 - 越权:非作者尝试编辑返回
E_FORBIDDEN。
- 变更影响评估
- 字段变更需同步
/api/treehole/postsDTO、审核后台、埋点treehole_post_publish、risk_signal_escalate。 - 索引调整影响信息流性能与风控延迟。
- 假设与待确认
- 假设
action_card_id直接引用任务集合;待确认是否需要独立行动卡集合。 - 待确认是否需支持多语言或图片贴子字段扩展。