80f5c4f0fcf35ab4658de773969f6f6a6d3c8297
用户 2026-10-02 的反馈(原话):
「显示不齐全,应该显示本人的上一代,这一代,和下一代的所有人…以本人为中心去搜索,
只要有关系的,都检索出来进行展示」
「夫妻之间有一条横线…这对夫妻下面所有的子女,都应该从夫妻之间的这个横线出来,
而不是从这对夫妻的其中一个出来,这样可能会出现一个 bug,就是如果从一个出来,
例如从父亲出来,母亲登录进去竟然看不到自己的孩子」
「数据仍然不全,差很多」
根因(实测,不是猜):第三方库 family-chart **只画了 20 人里的 9 人**。
_tooling/_fb_kin_cover_probe.py 的硬数据:
画出的:祖父/祖母/父亲/母亲/我/妻子/哥哥/儿子/女儿(9)
没画的:伯父、伯母、岳父、岳母、嫂子、堂兄、堂嫂、舅子、侄子、堂侄、外甥(11)
库的算法只画「树根的祖先链 + 后代 + 树根的兄弟姐妹 + 各人配偶」,
**横向亲戚(伯父那一支)与姻亲旁支(妻子的兄弟)永远进不来** ——
换树根也救不了(换到最高祖先,"妻子的兄弟"照样不在树里)。
「母亲看不到孩子」还有第二层原因:孩子只登记了父亲时,母亲那一侧根本没有边。
改法(不再依赖库的树算法):
· app/Kinship::familyMap() —— 以「我」为中心的两轮贯穿检索,带 seen 防环:
父母(-1 代)/ 子女(+1 代)/ 配偶(同代)/ 每一层的配偶
/ 配偶的父母与子女(姻亲旁支由此进来)/ 兄弟姐妹的子女(侄甥)
→ 上一代、这一代、下一代的**所有有关系的人**都在名单里。
· app/Kinship::householdChildren() —— 子女按**父母所在的户**归堆,
而不是按"某个人的 children"。于是孩子只登记了一位父母时,
照样挂到这对夫妻的户上(语义:这孩子是我们俩的)。
· templates/kin/tree.php —— 自己排版:每代一行、按「户」水平排开;
夫妻两张卡之间画短横线;子女一律从**这条横线的中点**垂下来
(x = (左卡中心 + 右卡中心) / 2,与"谁登录"无关)。
· 拖拽/缩放保留(用户明确要),改用原生 d3.zoom;不再引 family-chart。
验证(只跑这一个模块,按用户要求):
· _tooling/_fb_kin_v15.py —— 22 项全过:
✔ 20/20 全员画出(== 从「我」出发可达的人数)
✔ 7 对夫妻都有横线;7 个有子女的户**下垂线全部落在横线中点**
✔ 用户点名的场景一:删掉「母亲→儿子」这条边(模拟只登记父亲)后,
下垂线**仍然**从夫妻横线中点出来,孩子仍在图上
✔ 用户点名的场景二:给母亲开账号、**用她的手机号登录**,
家谱里能看到自己的孩子,且与父亲视角画的是同一批人
✔ 截图存档(全图 / 母亲视角 / 窄屏)
· _tooling/_fb_kin_v15_falsify.py —— 反向验证 2/2 抓住:
注入「从其中一张卡出来」→「从横线中点出来」变红
注入「只走直系血亲」→「每个人都被画出来」变红
· e2e 550 条全过(家谱段改到 v15 的判据上)
顺带修的既有问题:
· app/Kinship.php 老库升级回填按实际存在的列动态拼(缺列不再 1054 炸断升级)
· _fb_e2e.py 家谱断言改到 kin_v15_nodes(旧解析器在新页面上只会解析出空)
FamilyBook
家书,记录家庭的全部生活,一本用岁月写成的家谱。
把一个家的「人」「日子」「去过的地方、看过的电影」收进同一本书里。
它是什么
一个自托管的家庭生活系统。它不是又一个待办清单,而是这个家的长期档案 —— 十年之后还能翻出孩子第一次观影的票根、那年暑假走过的路线。
围绕三个圈展开:
- 人:家庭成员、亲友通讯录,以及他们之间的共享关系
- 时间:日历、日程、提醒,以及任务的期限
- 事件:观影、旅行、其他活动 —— 一切都落在同一条时间轴上
它在做什么
| 阶段 | 主题 | 内容 |
|---|---|---|
| 0 | 地基 | 名册、账号、登录、权限模型、安装向导 |
| 1 | 通信 | 通讯录、共享给某个成员、CardDAV 服务端 |
| 2 | 时间 | 日历本、重复日程、提醒、CalDAV 服务端 |
| 3 | 归一 | 观影与旅行迁入统一事件模型 |
| 4 | 任务 | 任务管理,期限自动映射成日历事件 |
| 5 | 回看 | 统计、年度家书、时间轴 |
当前进度:阶段 0 起步,仓库里只有图标与脚手架。
技术选型
- PHP 7.4+(无框架、无 Composer,上传到站点目录即可运行)
- MySQL 5.7+ / 8.0(
utf8mb4) - 前端为原生 HTML / CSS / JavaScript,无构建步骤
⚠️ 注意 CalDAV / CardDAV 是双向协议,和单纯的 .ics 文件导出不是一个量级的东西。
部署
- 把代码放到站点根目录;
- 复制
config.example.php为config.php,填写数据库与app_key; - 访问站点根,按引导页确认 PHP 版本、扩展、配置、数据库连接四项都通过。
config.php 不入库(已在 .gitignore 中忽略),其中包含数据库口令与加密密钥。
⚠️ app_key 一旦开始记录数据就不能再改(换掉即解不开已有数据),
并且它必须单独备份 —— 密钥丢失等同于数据永久丢失。
隐私
身份证号、手机号属于敏感个人信息,一律加密存储。 (就家庭自用而言,身份证号其实没有多少必须存的场景,启用前请三思。)
图标
见 assets/icons/。概念是「这本书就是家」:屋顶即一本摊开的书,
屋顶下纸做的墙上,三行横线是这个家写下的日子。
开源协议
Languages
PHP
81.6%
JavaScript
9.3%
CSS
9.1%