Skip to content

集合:树洞帖子(posts)

字数
1622 字
阅读时间
8 分钟

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 定义

字段类型必填默认值约束/校验说明隐私分级
_idstring-TCB 自动主键P2
_openidstring-TCB 自动作者 openidP2
user_id指针id-指向 users._id用户P2
alias_namestring-长度 ≤ 20匿名展示名P1
anonymity_modestringanon枚举(anon,pseudonym)匿名模式P1
contentstring-长度 ≤ 4000正文(预处理脱敏)P3
content_vector_idstring--语义索引用向量 IDP2
tagsarray[]-主题标签P1
topicstringgeneral枚举(general,relationship,study,emotion,other)话题分类P1
mood_thermometernumber-0-100情绪温度P3
risk_scorenumber00-1风险模型分值P3
risk_levelstringL1枚举(L1/L2/L3/L4)风险等级P3
risk_factorsarray[]元素为 string风险因素P3
statusstringdraft枚举(draft,pending_review,published,removed,archived)状态P1
moderation_resultobject-{auto:'pass', manual:'pending', risk_level:'L1'}审核记录P2
action_card_id指针id-指向 tasks._id行动卡引用P2
self_check_resultobject-{etiquette_confirmed, anonymity_choice, risk_aware}草稿自检结果P2
comment_countnumber0-评论数P1
hug_countnumber0-抱抱数P1
favorite_countnumber0-收藏数P1
report_countnumber0-被举报数P2
is_featuredboolfalse-精选状态P1
risk_flagstringnone枚举(none,watch,escalated,crisis)风险标记P3
intervention_triggeredboolfalse-是否触发干预P3
guardian_notifiedboolfalse-守护者已通知P3
content_hashstring--内容哈希(去重)P2
last_interaction_atdate--最后互动时间P1
createdAtdate-服务端时间创建时间P1
updatedAtdate-服务端时间更新时间P1
publishedAtdate--发布时间P1
is_deletedboolfalse-软删P1

3. 索引与唯一约束

  • 单字段索引:statusrisk_flagtopicrisk_levelcontent_hash
  • 复合索引:[status, publishedAt desc][risk_flag, createdAt desc][user_id, status, createdAt desc][topic, is_featured, publishedAt desc]
  • 唯一性约束:[content_hash] 用于内容去重
  • 设计理由:信息流需按发布时间倒序;风控后台按风险级别筛查;用户帖子查询;话题和精选内容推荐;内容去重避免重复发布。

4. 访问控制(TCB 权限)

json
{
  "read": "status == 'published' || _openid == auth.openid || auth.role in ['moderator','counselor']",
  "write": "_openid == auth.openid || auth.role in ['moderator']"
}

匿名读写采用 openid 控制;审核员和辅导员可查看未发布内容。

  1. 关系与级联
  • user_idusers
  • action_card_idtasks(或 action_cards 服务)
  • commentsreportssos 形成引用
  • 删除策略:软删;若被移除则级联将 comments 标记不可见但保留审计。
  • 反范式:comment_counthug_count 减少聚合压力;更新时需事务同步。
  1. 数据生命周期与合规
  • 留存:发布内容长期保留;删除/举报通过软删并保留 180 天审计。
  • 匿名化:内容存储前通过 NLP 清理身份信息;导出给辅导员时附带风险摘要而非原文。
  • 用户导出:仅提供本人发帖原文,需通过身份验证。
  • 审计字段:createdAtupdatedAtpublishedAtrisk_score
  1. API/云函数契约映射 | 接口/函数 | 读/写 | 使用字段 | 过滤条件 | 排序/分页 | 备注 | | /api/treehole/posts GET | 读 | alias_name, content, tags, hug_count, comment_count, publishedAt, risk_level | status='published' | publishedAt desc | 树洞信息流 | | /api/treehole/posts POST | 写 | content, tags, mood_thermometer, anonymity_mode, self_check_result | _openid = auth.openid | - | 发帖/草稿自检 | | /api/treehole/posts PATCH | 写 | 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'] | - | 危机干预 |

  2. 示例文档(≥3条)

json
{
  "_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"
}
  1. 常用查询样例(≥3条)
javascript
// 信息流第一页
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();
  1. 边界与错误码
  • 草稿自检失败:NLP 触发高风险返回 E_POST_RISK_HIGH,需调整内容。
  • 超过限制:超过 4000 字返回 E_POST_TOO_LONG
  • 内容重复:content_hash 重复返回 E_POST_DUPLICATE_CONTENT
  • 风险升级:L3/L4 级别自动触发干预流程,返回 E_POST_INTERVENTION_TRIGGERED
  • 越权:非作者尝试编辑返回 E_FORBIDDEN
  1. 变更影响评估
  • 字段变更需同步 /api/treehole/posts DTO、审核后台、埋点 treehole_post_publishrisk_signal_escalate
  • 索引调整影响信息流性能与风控延迟。
  1. 假设与待确认
  • 假设 action_card_id 直接引用任务集合;待确认是否需要独立行动卡集合。
  • 待确认是否需支持多语言或图片贴子字段扩展。

贡献者

The avatar of contributor named as Cai Hongyu Cai Hongyu

文件历史

撰写