Commit Graph
3 Commits
Author SHA1 Message Date
laoyang ed38a40c08 名册每人一份 · 分组两层 · 拖动排序 · 表单合一 · 裁剪可缩放
按用户十点反馈逐条落地(v5,Schema::VERSION = 5):

- 名册改成每人一份:新表 person_roster(owner_id, person_id, group_id,
  sort_order, source)。默认只看「我添加的 + 别人分享给我的」;
  source='seeded' 是升级时从老 persons.group_id 播进来的(先播数据再删列)。
- 排序不再手填:名册页直接拖动卡片(整版提交,一次 applyLayout 落库),
  无 JS 时卡片上的「调整分组」表单照旧可用。
- 分组分两层:管理员在「系统设置」维护公共分组(owner_id=0),
  用户在「个人设置」加自己的分组;显示顺序各人各定、互不影响。
- 名册可共享:把名片分享给别的用户(people/share);添加成员时若系统里
  已有这个人,可直接复用(people/pick),不必重复录入。
- 「编辑成员」与「改我自己的资料」合并为同一张表(templates/people/form.php),
  两个入口 href 完全相同,h1 按改谁切换文案;个人设置页只留
  资料入口 + 称呼 + 我的分组三块,删除 templates/settings/_profile.php。
- 系统设置收进头像下拉,顶栏只剩 首页/家谱/名册。
- 裁剪器加缩放(滑块 1-4x、Ctrl+滚轮、还原):缩放只改视图大小,
  落库的归一化矩形保持不变。
- 权限:管理员可以改任何人的权限(含自己),只拦「最后一位管理员」被降级。
- 去掉首页「我的一句话」后的链接、家谱说明段、以及「还没归到任何分组」提示。

迁移安全:数据回填(PersonRoster::seedFromPersons)先于删列执行、且不进
tryStep 容错;失败步骤记入 settings.schema_upgrade_warning 并在系统设置页提示。
线上已验证:schema_upgrade_warning 为空,person_roster/person_groups.owner_id
就位,persons.group_id / sort_order 已删。

验证:php -l 48 文件;本地 e2e 277/0、老库升级 81/0、桌面几何 108/0、
移动端几何 180/0、交互 96/0;反向验证 38 条注入 + 2 条缩放注入全部命中;
部署静态断言 53/0,站点自检 7/7(--resolve 锁本机走 443,探针真的进 PHP)。
2026-09-30 13:24:26 +08:00
laoyang 1669ab48d0 五项家庭化改造:以个人为中心 · 家谱 · 三种角色 · 附件存储可配置 · 独立页样式
1. 独立页(登录/安装/错误)套上 HTML 骨架 —— 修「首页为什么没有样式」:
   新增 templates/layout-bare.php,View::render 对独立页也走完整 <head> + CSS。
2. 以个人为中心:Kinship::label() 现算称呼、Auth::homeTitle() 出「X的家书」;
   同一批人在不同登录者眼里自动变成公公婆婆 / 岳父岳母(不存一次性称谓)。
3. 附件存储可配置:Storage 门面(local / 阿里云 OSS),库里只存相对键,
   云端失败自动回退本地;设置页可选驱动并填 OSS 参数(照 MovieLog 的方案)。
4. 三种角色:admin / member / guest,访客只读、写操作一律 403;
   accounts.role 枚举扩容,老库靠 Schema::ensure() 自动升级。
5. 家谱:只存相邻两代的边(parent / spouse),其余称呼全部推导 ——
   兄弟姐妹不存边(共同父母 + birth_rank 排行推长子/次女、哥哥/妹妹),
   认不清的人用虚拟人物 is_placeholder 占位,关系天然双向。

顺带修掉本地 e2e 挖出的 8 个线上级 bug(性别写死、长幼方向反、关系方向静默写反、
birth_rank 不从表单取回、隐式可空参数致响应头失效、无文件字段被误判为上传失败、
layout 变量撞车覆盖 $me、世代 0 显示成「下 0 代」)。

验证:kinship 单测 37/0 · HTTP e2e 81/0 · 老库升级专测 14/0 ·
反向验证 11/11(把每个修复改回旧写法,对应断言都会变红)。
2026-09-30 08:13:07 +08:00
laoyang 8eb19267bc 阶段 0 完整版:名册 + 账号 + 安装向导 + 设置(宣纸主题)
这一版把「家」的地基铺完:

功能
- 安装向导 install.php:建四张表 → 建家庭 → 建第一人(兼管理员),装完自删;
  「是否已装」以数据库四张表为准,不以文件是否存在为准
- 家庭名册:成员增删改查、头像上传(居中裁方 512×512 转 JPEG、finfo 校验、
  随机文件名)、生日自动算年龄与倒数天数
- 敏感信息加密存储:手机号双写(SHA-256 哈希用于登录 + AES-256-CBC 密文用于显示)、
  身份证只存密文;页面上永远只显示脱敏后的 138****8000 / 前 6 后 4
- 账号体系:人与账号分离(孩子可入名册但无需密码)、开通/停用/角色、
  防爆破(5 次失败锁 60 秒)、修改密码、最后一个管理员不可移除
- 设置页:家庭名称与座右铭、加密密钥状态
- 宣纸主题 UI:砖红取自图标,扁平、留白充足;移动端顶栏收紧不换行

安全
- 所有 POST 走 CSRF;输出全量 e() 转义;uploads/ 禁执行脚本
- app/ 与 templates/ 加 .htaccess 整体拒绝直连(直接请求模板会 Fatal 并
  把服务器绝对路径打在页面上 —— 这是线上真实抓到过的问题)
- 已安装的 install.php 返回 404;display_errors 线上关闭

工程
- 无框架无 Composer,query-string 路由(index.php?r=模块/动作),不依赖 rewrite
- 静态资源带 mtime+size 版本号,改版后浏览器不会吃旧缓存
- 配套部署与冒烟(_tooling/,不入库):部署脚本容忍 tar 对非属主目录的
  元数据回填失败;冒烟断言「状态码 + 正文无 PHP 错误 + </html> 收尾 +
  无绝对路径泄露 + 断言总数下限」—— 只看状态码会把「200 但正文中间
  Fatal」当成通过,这一版在线上真实抓到过一次
2026-09-30 00:49:53 +08:00