权限与隐私模型
族谱里有大量敏感的个人信息(生卒、婚姻、子嗣)。云族纪是私有部署、只给自家人用,但"自家人"内部也不是人人都能看到全部——比如嫁过来的配偶、外族人、还没认证的登记节点。
这一页讲清楚一个核心能力:同一棵家族树,不同的人打开,看到的是不同的版本。
三层权限,前端隐藏不算安全
系统在三个层面做权限,越往下越是权威:
① 数据库 schema 权限
规定每张表"谁能直接通过前端查询/写入",挡住最外层的越权直连。
│
▼
② 云函数手写校验(真正的安全边界)
每个写操作在服务端重新判断:你是不是本族管理员、是不是本人、
有没有这家人的访问凭证……不满足直接拒绝。
│
▼
③ 前端 UI 显隐(只是体验,不是防线)
按钮、菜单按角色显示/隐藏,但它只负责"别让你点到",
绝不能假设"看不到按钮就安全"。2
3
4
5
6
7
8
9
10
11
12
关键原则:前端 isAdmin 只决定按钮显隐,服务端校验才是最终裁决。 就算有人绕过界面直接请求云函数,没有权限依然会被服务端挡下。敏感字段(比如认领校验的答案)在数据库层就设为"任何人都不可读",只在服务端内部使用。
家族开放档位:开放 / 半开放 / 封闭
每个家族可以设置自己对外族的开放程度,共三档:
| 档位 | 外族人能看到什么 |
|---|---|
| 开放 | 整棵树都能看 |
| 半开放 | 只看得到和自己"沾亲"的近亲窗口,其余裁掉 |
| 封闭 | 完全看不到,直接拒绝访问 |
判定一个人能不能看某家族时,按唯一的优先级顺序:本族管理员 → 本族成员 → 针对这个人的特批名单 → 家族默认档位。
半开放的"近亲窗口"
半开放不是简单地"只给前几代",而是以请求者在这个家族里的关系锚点为中心动态算出来的:
- 一个人可能因为婚姻、因为母亲,在目标家族里有一个或多个"锚点";
- 从每个锚点向上找到父辈,再向下取若干代子嗣,这些人的并集就是他的实名可见窗口;
- 为了让树不断裂、保持唯一真实根,窗口里每个人的父链会一路补到始祖,但链条上不属于窗口的人会被匿名成"?"骨架节点——树的形状还在,个人信息全部抹掉;
- 窗口之外的旁支,干脆不返回。
于是外族人看到的是一棵"近亲有名有姓、远支只剩轮廓"的树,既保留了"我和这家人是什么关系"的上下文,又不暴露无关成员的隐私。
分身匿名:可以只藏住某一个身份
利用分身体系,一个真人能单独控制自己在某个家族里的那个分身是否实名:
- 匿名后,该分身节点的姓名、头像、性别、生日、生平全部清空,画布上显示为"?";
- 但节点位置、挂靠关系、连线全部保留,树的结构不会因为某人匿名而散架;
- 系统强制每人至少保留一个实名分身,避免完全隐身;
- 本人始终能看到自己匿名分身的真实信息,匿名只对"别人"生效。
数据出口净化:让匿名节点无法被反推
光在界面上打码是不够的——如果返回的数据里还带着真实 id,懂技术的人能顺着 id 把"?"背后是谁拼出来。因此族谱树在离开服务端前会统一过一道净化:
- 他人视角下,匿名节点的真实 id 被替换成伪 id,家族归属和关系字段被清空;
- 指向匿名节点的血缘引用,换成一种"语义锚点":同一个匿名人仍然被识别为同一个人(连线不断、称呼还能算),但无法映射回任何真实 id;
- 指向实名节点的引用则保留真实 id,避免"同一个人的匿名位和实名位"被交叉反推。
这一层保证了:即使有人抓包拿到原始返回数据,也无法把"?"还原成具体的人。
特批名单:精确到某个人
家族默认档位是"对所有人一视同仁"的,但总有例外——某个亲家想多看一点,或某个关系疏远的人想收紧。特批名单支持针对具体某个人单独设置:
- 访问档位(开放/半开放/封闭);
- 内容档位(连配偶位都不显示 / 只显示配偶 / 配偶和外亲子女都显示)。
特批条目优先于家族默认,既可以为某人放宽,也可以为某人单独加锁;它存在独立的、所有人都不可直接读的表里,避免"能登录就能拉到一份名单"。
归档与撤销
族谱数据不可再生——一位老人的生卒信息一旦误删,可能就永远找不回来了。所以系统的设计底线是:危险操作不做物理删除,而是归档留痕。
- 添加、修改、删除成员、认领合并、批量导入……每类写操作都会生成一条归档记录,里面保存被影响数据行的完整快照和改动清单;
- 撤销 = 按快照和补丁把数据恢复到操作前的状态,不留残余垃圾;
- 批量导入支持整批撤销,一次导入的几十上百人可以整体回退;
- 删除的成员在短时间内以"虚影"形式留在画布上,管理员或本人可以一键恢复;超时后才真正淡出。
这套机制让录入者(尤其是不熟悉软件的长辈)敢于操作——知道无论点错什么都能撤回,而不是每一步都提心吊胆。
