laoyang
|
2e40133d8f
|
v62:影院管理补齐接口(统计 / 年度报告 / 高级搜索)+ 名册带工作经历
用户 2026-10-19:「设置里面的影院管理,这些功能都还没有,应该补充,
就是增加影院呢、修改影院呢、高级搜索、统计、年度报告,这些全部都应该补充进去。」
一、三个新子路由(都是**家族级**,必须在 `$id > 0` 分支之前处理)
GET /api/v1/movies/stats 总览 + 按影院 / 按人 / 按月 / 按年
GET /api/v1/movies/report 年度报告(以登录者为中心,?year= 可切年)
GET /api/v1/movies/search 片名 / 影院 / 人 / 起止日期的组合搜索
⚠️ 全部复用**网页端那一份 `MovieStats`**(overview/byCinema/byPerson/byMonth/
byYear/annual/years/search)—— 统计数字两边必须一致,否则用户会发现
"网页 124 部、App 121 部"。
⚠️ 三个路由都做了 **`$id === 0` 守卫**:`/movies/stats` 不能被当成"id=0 的详情"。
⚠️ `search` 在条件全空时**不查全库**(返回 has_cond=0),与网页 `hasCond` 同行为 —
否则"搜索"等于"列出全部观影"。
二、features 声明 movies_stats / movies_report / movies_search
老端上据此隐藏入口(新端上不用探测,但让能力可发现是这套约定的一部分)。
三、名册带 `jobs`(用户:「名册的列表太空了,应该显示更多内容,例如工作单位、职务」)
新增 `PersonJob::mapFor(array $personIds)` —— **一次 `IN (…)` 批量取回**。
⚠️ 不能在装饰循环里逐人 `PersonJob::list()`:名册上千人就是上千次查询(N+1)。
⚠️ 排序与 `list()` 逐字一致(当前段在前 → 开始时间倒序 → id 倒序),
否则"列表显示的单位"和"详情里第一段"会是两个不同的单位。
⚠️ 端上列表实际用的是 `persons.org` / `persons.title`(本地库有那两列),
`jobs` 是给"接口直出"的场景预备的 —— 两条链路都保留。
验证:_fb_v62_cinema_api.py 45/0(独立副本 + 真 MariaDB);
覆盖影院 CRUD 10 条 + 统计 8 + 年报 7 + 搜索 7 + 名册带 jobs 4;
php -l 全量通过。
线上:本提交对应的代码**已在线上**(13:17 那次部署带上去的,非本次操作),
真机实测统计页显示的是真实数据(横店电影城 4 / 上影影城 3…)。
|
2026-10-19 15:27:08 +08:00 |
|
laoyang
|
ad7f43af68
|
v61:新增账号自助接口(GET /account + POST /account/password)
端上新增「个人设置」页要用:用户 2026-10-19 要求把抽屉里的
「通知消息 / 个人设置 / 修改密码 / 系统设置」都收进"点右上角头像"那一页,
所以端上必须能自己改密码,不能再指着用户去网页改。
GET /api/v1/account → 我的资料 + 账号信息 + 当前设备
POST /api/v1/account/password → 改密码(old_password/password/password2)
规则与网页那条改密码路由逐条对齐(不能端上比网页松):
· 必须验旧密码;
· 两次新密码一致;
· 过 Account::validatePassword()(≥8 位 + 字母数字都要有)。
额外收紧一条:新密码不能与原密码相同(网页没拦,端上拦了没坏处)。
两处刻意为之:
· 改密码**不查写权限**(网页那条路由只要求登录,guest 也能改自己的密码)
—— 加了写权限检查就会出现"网页能改、App 不能改"的权限裂缝;
· 改完**不动现有令牌** —— 用户在自己手机上改密码不该被踹下线。
features 声明补 account / account_password,端上可探测。
验证:_fb_v61_account_api.py 20/0(独立副本 + 自检 + 随机端口 + 真 MariaDB,
覆盖 5 种错误路径 + 改完旧密码登不进/新密码能登/原令牌仍有效);
php -l 全量通过;线上部署已完成。
|
2026-10-19 12:19:06 +08:00 |
|
laoyang
|
97e963e2ee
|
v59 服务端:标语(个人→家庭→默认)/ 最近纪念日 / 真实头像
配合端上「界面六条」,服务端只补三样数据:
① Family::slogan(fam, pid) —— 三层优先级
用户:「如果这个用户自己有标语,他可以写一句自己的标语;如果他有自己的标语,
这个地方就是用户自己自定义的标语。如果他没有标语,就用我们给他的这个标语。」
优先级:persons.slogan → families.motto → Family::DEFAULT_SLOGAN。
DEFAULT_SLOGAN = '一家人用岁月写成的一本书'(用户明确指定,别再改)。
与网页端 templates/home.php 的 heroSlogan 同一套规则,两边永远一致。
/login 与 /me 都返回 slogan —— 每次启动都会打 /me,所以网页端改了 slogan
手机下次启动就跟上,不必为此另加接口。
② /home 新增 recent_days —— 首页「最近纪念日」
用户:「未来最近的三个纪念日,包括每个人的生日,以及手动填写的各个纪念日。」
= Anniversary::upcoming(fam, pid, 370) 取前 3。
· 为什么是 370 天而不是网页端概述卡那样的 30 天:只取 30 天时,
一个"刚过完生日"的家庭会**一个都取不到**,模块直接空着 ——
而用户要的是一个永远的倒计时。取满一年保证"接下来的三个"一定有。
· 数据源 all() = 派生生日 + 自建纪念日(正好覆盖用户说的两样,
不必再去 Birthday:: 那套单独取一遍,否则迟早口径不一)。
· 每条带 days(倒计天数)、source(custom / birthday_solar / birthday_lunar),
顺序由服务端排好(最近的在前),端上不再排一遍。
③ 真实头像
用户:「右上角的头像应该是真实的。」
· /home 新增 me_avatar(当前登录者的 avatar_url());
· /login 的 person 增加 avatar_url。
avatar_url() 负责按线上存储驱动决定走 /uploads 还是 OSS 直链 ——
端上不自己拼路径(拼错了就是永远破图)。
验证:_fb_home_api.py 60/0(新增 16 条:recent_days 真数据/天数/排序/≤3 条、
me_avatar、slogan 三层优先级实测 —— 给 persons#1 写一句个人 slogan,
必须优先返回他那句);php -l 通过;部署脚本增「第59批形态」9 条。
真机实测:抽屉显示「修身,齐家」= 杨永全自己的 slogan(个人优先生效)。
|
2026-10-18 20:14:50 +08:00 |
|
laoyang
|
9348dd3796
|
v58:变更指纹接口(端上增量同步的服务端一半)
用户 2026-10-18:首次全量、之后增量同步;进来先展示本地数据,一边同步
服务器最新数据一边更新(附件走后台队列)。
服务端只补一件事:GET /api/v1/changes —— 每个模块返回一个变更指纹,
端上只做相等比较,不相同才拉。
指纹三件套 COUNT(*) : MAX(id) : MAX(updated_at):
- 61 张表里只有 16 张有 updated_at,单用它抓不到新增与删除;
- 只有行数则抓不到"改已有行"(靠端上 24h 强制全量兜底,响应带 stale_after_ms)。
CHANGE_TABLES 里 home 故意不在(派生页,端上跟着别的模块重拉);
kin 与 roster 同源(persons/relations/nicknames),名册一变家谱跟着拉。
必须带令牌(Api::me() 开头):指纹本身不算机密,但没理由让匿名者试探
"家里有没有新数据"。
验证:_fb_changes_api.py 33/0(新增/修改/删除各自改变指纹、12 模块齐全、
无令牌 401、两设备拿到同一个 all、被踢令牌 401);本地 e2e 1519/0;
部署静态断言补「第58批形态」8 条;全量流水线 PUSH_RC=0。
|
2026-10-18 16:01:08 +08:00 |
|
laoyang
|
ebaed21920
|
v57:令牌升级为「设备会话」(24h 滑动续期 / 每账号 10 台 / 网页端远程退出)
用户 2026-10-17 定的模型:
· 一次登录 = 一台设备一条会话;同一台设备重登,旧令牌立即作废
· 24 小时滑动续期(一直联网就不用每天输密码);离线超 24h 只锁界面、不删数据
· 网页端「个人设置 → 设备管理」能看见都有谁在登录,并能把丢了的那台踢掉
· 每账号最多 10 台,超了让用户先踢旧的
服务端配套:
· api_tokens 加 device_id / device_name / platform / app_version / last_ip
+ idx_api_device;历史令牌回填 legacy-<id>(不回填 = 踢不掉的幽灵会话)
· ApiToken:issueDevice / listDevices / revokeDevice / revokeOthers / revokeCurrent
+ 滑动续期(剩余不足 4h 才写库);verify 同时返回数字键与关联键(三处调用方在用)
· 新增 /api/v1/logout、/api/v1/devices;ping 报 features.device_session
· 登录不再读 days(0 = 永不过期会绕过 24h 这条线);超限回 409 且**不动任何一行**
· 老客户端兜底固定槽位 auto-unknown(随机设备号会撞满 10 台把账号锁死)
· Schema 34 → 35
顺带:首页近期任务/往年的今天(Home::memories)、名册派生字段口径统一。
验证:设备会话探针 56/0、设备管理渲染 22/0、登录全链路 30/0、反向验证 12/0、
e2e 1519/0、静态断言本地空跑 357/0、线上 /api/v1/{ping,devices,logout} 复核通过。
|
2026-10-18 03:34:47 +08:00 |
|
laoyang
|
13a5d08696
|
v45 API 补录:手机号登录换令牌 + 我的名册 / 家谱接口 + 出口层敏感字段脱敏
🔴 为什么现在才提交(这是「补录」,代码早已上线并验证):
v45 第三/第四批当时,同一工作区里有**并行的鸿蒙端工作流**正在改这个文件
(手机号登录换令牌、media.php 的 ?token=)。按「绝不把别人正在写的裹进
自己的提交」的纪律,那次只提交了自己的 5 个文件,本文件被**故意留下**。
此后文件静止约 25 小时、端上工作流也已收尾 ⇒ 现在补录,让仓库与线上一致
(线上 md5 = 本地 md5,deploy 是从工作树打包的,所以线上一直是这份)。
① `POST /api/v1/login` —— 手机号 + 密码 → API 令牌
原先 App 只能「先去网页签发令牌、再手动粘贴」,能用但没法给别人用。
与网页登录有意不同:不建会话(API 无状态);限流落**文件**
(`sys_get_temp_dir()/fb_login_<sha256(ip|phone)>.json`,60s 窗口 / 5 次)
而不进 $_SESSION;失败**统一**提示(不区分「没这个人」与「密码错」,
否则接口成了手机号是否已注册的探测器);有效期用**服务端时间**算。
成功时顺带 `Calendar::seedDefaults()`(全新安装的兜底)。
② `GET /api/v1/roster` —— 「**我**名册里的人」(我加的 + 别人分享的)
与 `/people`(全家 801 人 = 通讯录底账)区分开:App 名册页要用这个,
否则一屏 800 人且是「别人的通讯录」。组装**照抄 Web 端 index.php 的
people 分支**(同一套类/判据):Person::roster → Kinship::label /
Nickname::display / PersonQuery::phonePlain / PersonQuery::birthdaysOf /
PersonTag::mapFor / Pinyin::initials,外加标签云与标签词表。
⚠️ 复用这些类而非另写,否则会「网页搜得到、App 搜不到」。
③ `GET /api/v1/kin` —— 家谱(以我为中心的关系图)
用 `Kinship::familyMap($fam,$pid,$people,2,2)`,与 Web 端 kin/tree.php
同一套 ⇒ 端上与网页的亲属关系必然一致。按代数排序,拍平直接关系字段。
④ 🔴 信息泄露修复:`stripSensitivePerson()`
`Person::all()` / `Person::roster()` 都是 `SELECT p.*`,把
`phone_hash` / `phone_encrypted` / `id_card_encrypted` / `birthday_id_card` /
`birthday_lunar*` 一路吐给 App。前两个是 AES 密文(离线爆破材料),
`phone_hash` 是「手机号是否属于这个家」的判定键。
⇒ 在 **API 出口层**脱敏(列表 / 详情 / 新建 / PATCH 四个出口都套)。
⚠️ **不能改 `Person::all()` 本身**:网页端确实在用(ContactImporter 靠
phone_hash 去重、PersonQuery 靠 phone_encrypted 按手机号搜)
⇒ 网页要、App 不要 ⇒ 差异落在出口层。
线上验证(全绿):GET login→405 / 缺参→422 / 错密码→401「手机号或密码不对」
/ 不存在的手机号→**同样的** 401 与提示 / 连续错→第 6 次起 429 / 名册 800 人 /
标签云 15 个 / 称谓正确(爸爸→父亲…)/ 手机号解密正确 / 生日阴阳历 /
首字母 ypzbb / 6 个敏感字段全去除(列表与详情都验)。
|
2026-10-14 09:41:34 +08:00 |
|
laoyang
|
075ac6bbeb
|
v44 第 44 批:界面 5 条 + 移动端 API v1 全量
界面(用户 2026-10-12 第 1~5 条)
1. 新建日程「日历本」并入 .cs 自绘下拉,颜色画进候选项,三字与下拉同行。
2. 新建日程「开始/结束」改「日期范围:」,删旧日期控件;
重复相关三行仅选重复时出现;删「(含第一次)」与「这段时间算忙碌」。
3. 条目浮层加「地点」、去掉「状态」行;首页红线按分钟定位(原只取整小时);
去掉左侧红点只留红线。
4. 任务页删掉状态说明提示(STATUS_HINT 三值清空)。
5. 新建任务:标题在前树框在后;截止时间改最新日历控件;负责人默认自己;
删冗余提示;「上面要做什么」→「任务名称」;清理括号说明。
移动端 API(用户第 6 条:导航模块除外,其余全量)
- 新增 Bearer 令牌鉴权(api_tokens 表,Schema v32),与登录口令 / DAV 口令三套分立。
- Api.php 内核(鉴权/取参/信封/分页/分发 + _method 覆写)+
ApiHandler.php 17 条资源 + ApiToken.php + api.php 入口。
- 路由:router.php / .htaccess / index.php 三处 /api/ 兜底(部署脚本自动追加线上规则)。
- 个人设置新增「App 接口令牌」卡;docs/API.md 接口文档;
docs/API-QUESTION-LIST.md 自主决策与待确认缺口清单。
验证:本地 e2e 1510/0、v43 真机 33/0、v43 反向 9/0、
v44 真机 41/0、v44 API 63/0、v44 反向 19/0;全流水线 PUSH_RC=0。
|
2026-10-12 15:31:03 +08:00 |
|