每日回忆(Daily Recall)#
每天问几道关于「昨天」的题,同一个日子隔几天再问一次,用跨天答案的差异观察记忆漂移。 定位是可开源的本地优先工具:零后端、零账号,数据只在浏览器 localStorage 里。 起点是「我记忆力差,想练一练」——但真正的价值在于它顺手产出了记忆漂移的证据和一份自动日记。
速查#
| 项 | 值 |
|---|---|
| 稳定版 | https://memory.hsfp.cn |
| 测试版 | https://memory_dev.hsfp.cn |
| 开源仓库 | https://github.com/glwhappen/daily-recall(public,MIT,v1.0.0 tag = 纯静态版) |
| 代码 | /root/memory |
| 应用容器 | daily-recall(:4470→3000)、daily-recall-dev(:4471) |
| 数据库 | daily-recall-db(宿主 :4472)、daily-recall-db-dev(:4473),PostgreSQL 17 |
| 统一登录 | Authentik 应用 daily-recall,issuer https://auth.hsfp.cn/application/o/daily-recall/ |
| 反代 | NPM proxy-host id=189(生产)/ 188(测试),复用证书 id=11 *.hsfp.cn |
| 栈 | Next.js 15 服务端 + 手写 CSS + pg(无 ORM、无 UI 库、无认证框架) |
| 测试 | 63 个单测 + 题库校验,npm test |
| 部署配置 | /root/memory/.env(不提交),密钥与 OIDC 凭据都在里面 |
四个核心设计(容易做错的地方)#
题目模板化 + 按目标日期锚定。题库里不写死「昨天」,而是
{日期}占位符 +offsets列表; 作答记录的唯一键是(题目 ID, 目标日期, 偏移天数)。 于是「9-20 出门了吗」能在 9-21(昨天)、9-22(前天)、9-27(一周前)各问一次。⚠️ 易错点:同一天被问两次发生在不同的
today,不是同一次buildCandidates()调用里。 在 9-21 那天,offset=2 指的是 9-19 而不是 9-20。我写测试时就在这里错过一次。作答记录不可变。用户核对记忆时追加一条带
revisionOf的新记录,绝不覆盖原始答案。 否则「他第一次答错了」这个信号会被删掉,记忆漂移率就算不出来。 实测确认:复核后记录数 7→8,待办 3→2。不一致分三类,不是一类(这是项目区别于普通刷题 App 的地方):
conflict事实互相矛盾 → 报警decay以前记得、后来忘了 → 正常遗忘,画曲线不报警upgrade越久反而越清晰 → 最可疑,通常是把别的事记混了(虚构记忆)
按回忆距离分档看覆盖率。总覆盖率会掩盖「昨天全记得、一周以上全忘」这个最关键的特征。 加权覆盖率只在混合偏移时有区分度——全是同一个偏移时它恒等于普通覆盖率(因为它是比例)。
常用命令#
cd /root/memory
npm run dev # 开发
npm test # 48 个单测 + 题库校验
npm run build # 静态导出到 out/
docker compose up -d --build # 生产 :4470
docker compose -f docker-compose.dev.yml up -d --build # 预览 :4471题库是 questions/zh-CN.yaml(57 题 / 8 分类),改完必须跑 npm test——
校验在构建期执行,坏题会让构建直接失败。出题规范见项目内 docs/question-guide.md。
v2:服务端、账号、反馈(2026-09-28)#
三个开关都由部署者配置,不配任何东西仍然可用(降级回纯本地模式):
| 开关 | 开法 | 关掉后 |
|---|---|---|
| 服务端 | 配 DATABASE_URL | 数据只在浏览器里 |
| 注册登录 | AUTH_ENABLED | 有同步能力但不要账号 |
| 题目反馈 | FEEDBACK_ENABLED | 隐藏 👍👎 |
关键设计:
同步就是集合并集。作答记录不可变 + UUID 主键,所以客户端把本地全量丢给服务端就行, 不需要 diff、不需要冲突处理。客户端和服务端调用的是同一个
mergeAnswers。点踩 = 个人屏蔽,不等于下线题目。「别再问我这个」是个人边界,只影响自己; 「这题对所有人都不好」才需要管理员在后台介入。点踩后当场跳过并补一道新题,保证题数不变。
后台下线写数据库,不改 YAML。题库文件是 Git 管理的唯一事实源、容器里也只读; 改了会在下次部署时丢掉。后台另给「同步回仓库」清单。
认证自建不引框架:OIDC 授权码 + PKCE + 用 Node 内置 crypto 验签,约 200 行。
OIDC 接入(auth.hsfp.cn)#
Provider + Application 已用 Authentik API 建好(见 Authentik接入指南 里两个 API 建 Provider 的坑)。
配在 .env 的 OIDC_ISSUER / OIDC_CLIENT_ID / OIDC_CLIENT_SECRET。
管理员用 ADMIN_GROUPS=authentik Admins 判定,人员变动不用改部署。
踩坑#
本机
npm install不装 devDependencies:新项目npm install后只有 25 个包,tsc/vitest都不在。必须用npm i --include=dev。npm config get omit显示空、NODE_ENV也没设,原因不明——这台机器上所有新项目都会踩,先记住这个解法。NPM 建反代必须显式写
http2_support: true,漏了会随机返回421 Misdirected Request, 详见 nginx-proxy-manager使用手册。agent-browser不能用默认 session:default之前连过 9223,会一直尝试连 CDP 并失败。 用一个新 session 名(如--session recall)才会自起本地 Chrome;9223 没开时也只能这样。Next.js build 会自动改
tsconfig.json(往include里塞.next/types/**/*.ts),属正常。offsets 要按记忆类型定:估计型(屏幕时长、刷手机时长)和细节型(上衣颜色)衰减极快, 配上 14/30 天只会让人一路点「不记得」,既挫败又污染远期那一档的统计。已收窄 6 道题。
待办#
英文题库
questions/en.yaml(UI 文案已双语,题库仍只有中文)service worker 让断网可用(现在只有 manifest,能装到主屏但离线打不开)
用真实「不记得率」反向校准每道题的 offsets,取代现在的人工判断
跨天校验的判定口径(迭代了三轮,别退回旧写法)#
要报给用户的判断错了就是在误导人,所以这里反复调过:
按作答时间取首末两次比较→ 在导入/合并的乱序数据上会把方向判反。用「问得最远」那次的距离做门槛→ 「昨天」和「前天」问同一天只差一天, 却因为最远那次是 3 天前而判成可疑。当前:用「问得最近」和「问得最远」的两次比;
upgrade(越久反而越清晰) 要求两次提问的距离差 ≥ 2 天;距离差不足或偏移相同则不入列表(没信息量)。decay(正常遗忘)不加门槛——遗忘曲线宁可多收数据。
相关:我的服务 · Docker与容器运维手册 · nginx-proxy-manager使用手册 · 提示词
<!-- project: path:/root/memory -->
讨论 0
还没有人说话。
登录登录后可以参与讨论