11 KiB
WorthPath 首版设计
2026-10-04 更新:当前仅支持完整 ZIP v9 备份,不支持任何单文件 JSON 或旧 ZIP。本文旧版结构说明作为历史记录,现行权限与验证以 本次更新 和 MCP 接入 为准。
本轮账户分组、定时计划、收支日历、迁移步骤与验证边界见 更新说明。
NestJS API、React/Vite 前端和 MySQL;同源 /api,开发环境由 Vite 代理。
用户拥有持有项目 Position(account/asset/debt)、汇率及登录会话。账户独立保留 asset/liability 属性;信用卡与贷款固定为负债。债务可链接到多个同用户项目,链接不参与求和。资产账户允许负的原币余额;独立资产及债务本金仍非负,负债按 side 减去。
Revision 保存按业务日期生效的绝对金额,每次金额更新新增记录,sequence 在数据库中单调分配以确定同日顺序;按业务日期和顺序读取,日趋势使用当日最后余额。错误记录须明确调用更正接口。历史前值和变化额按业务日期重新计算,避免更正早期记录后余额与趋势不一致。未来日期不允许。初始余额也写入历史。金额 DECIMAL(24,8),汇率 DECIMAL(24,12),API 使用十进制字符串;计算使用 Decimal,前端仅图形坐标使用 Number。
趋势按日期重放金额和当时可用汇率。汇率导致的变化和余额导致的变化分别归因;没有可用汇率时总额标记不完整,绝不默认为 1。归档项目仍参与统计,归档仅停止编辑,避免归档导致财富凭空消失。
认证采用 bcrypt 密码哈希和 HttpOnly 随机会话 Cookie;数据库只保存会话令牌 SHA-256 摘要。所有资源查询由会话用户范围限定。写入默认要求准确的 WEB_ORIGIN;本地穿透测试允许设置 WEB_ORIGIN=* 接受任意合法 HTTP/HTTPS 来源(仍拒绝缺失来源),生产模式禁止通配符。登录限速;生产必须 HTTPS 并启用安全 Cookie。
备份采用 version=3 ZIP(多个可读 JSON 文件),包含项目、历史、关系、币种、本位币、汇率和导入来源,不包含用户认证数据。首版导入只追加完整的新项目并重映射 ID;项目 ID 和 importedFromId 识别重复,用户 + importedFromId 有唯一索引,项目修改后仍拒绝原备份重复导入;不同 ID 的同名项目允许共存。汇率冲突拒绝;已有本位币不自动更改,空空间恢复备份本位币。完整验证后以 Serializable 事务写入,不修改已有项目。总览和导出使用数据库事务读取一致的数据视图。
页面:登录、首次改密与管理员账号管理、总览、账户/资产/债务列表及详情与编辑、历史、本位币/汇率设置、备份与导入。空数据无演示金额。
数据库使用 Prisma 可追踪 SQL 迁移,部署仅 migrate deploy,禁止 db push/reset。扩展家庭共享时可以引入空间和成员权限,现阶段严格按用户隔离。
代码边界:auth.ts 负责身份与 Cookie;portfolio.ts 负责持有项目、历史和关系;calculation.ts 是无数据库依赖的十进制计算;rates.ts 负责公共汇率获取、失败状态和个人设置;backup.ts 负责格式验证与原子恢复;database.ts 管理数据库生命周期;validation.ts 集中定义输入约束。前端 api.ts 定义服务访问及数据类型,App.tsx 组合各功能流程,共用金额编辑和历史展示,CSS 定义桌面侧栏及手机底栏布局。
时间:业务时间按北京时间精确到分钟,数据库 DATETIME(3) 保存对应 UTC 时间,显示按 Asia/Hong_Kong;旧日期记录迁移为原业务日的 00:00,不推测实际操作时刻。汇率仍使用 DATE。历史按时间及 sequence 排序,趋势按业务日汇总当日最后余额。创建和更新时间使用 UTC 时间戳。汇率定时检查在 API 进程内执行;更新尝试状态和认证限速当前在内存中,重启后重新初始化。多实例部署时需改为共享限速和独立调度任务。
隐私及设置:Position.hidden 对账户、资产和债务统一生效。默认列表、详情、历史及总览均在服务端过滤隐藏项目,净资产按显示范围计算。登录密码核验成功后仅当前 Session 获得 5 分钟查看权限,到期前端清除敏感视图,服务端每次请求检查授权期限;手动锁定和退出可立即撤销。备份始终包含该用户全部项目(包括隐藏项目)。showSidebar 和 idleMinutes 为用户设置,默认显示侧栏、30 分钟无操作退出;0 关闭定时退出,最大 1440 分钟。真实交互触发节流的活动请求,后台加载不延长会话;服务端检查 lastActivity,前端计时器退出登录并清除页面数据,保留浏览器标签页。侧栏隐藏后顶部导航保留设置入口。
安全清空:先通过认证下载备份,在当前 Session 记录备份内容摘要及 10 分钟有效期。下一步必须输入精确短语“确定清空”。Serializable 事务中重新校验当前数据摘要;变化后必须重新下载。清空仅删除当前用户的项目(级联历史/关联)及汇率,保留登录身份和个人设置,撤销该用户所有会话的查看及备份确认状态。汇率请求返回后再核对当前币种,避免清空期间正在执行的网络请求重建旧汇率。
备份现使用 version=3 ZIP:manifest.json 保存格式版本、导出时间及各数据文件 SHA-256;settings/currencies/accounts/assets/debts/history/links/rates 分别保存完整数据。业务时间与 hidden 保留。旧版 v1/v2 JSON 文件仍可上传,v1 缺少 hidden 时视为未隐藏。恢复仍只追加,按业务时间和 sequence 重建顺序;空空间恢复本位币和界面/退出偏好。取消项目数、历史数、关联数和汇率数上限;文件上传最多 512 MB,ZIP 解压总计 1 GB,拒绝未知/重复路径、缺失文件、加密 ZIP、摘要不符和格式错误,不向文件系统解压。预览文件暂存在系统临时目录,15 分钟有效,确认导入令牌绑定当前用户及会话,导入/失败/过期后清理。数据库事务最长 5 分钟以容纳较大恢复。手动汇率入口和写入 API 已删除,既有历史汇率保留。
账户图标模块
Icon 存储 name、ownerId、shared、SHA-256 和规范静态 PNG 的 MediumBlob,不存储 source;内置图标来源保留在资源清单中。配置 ICON_STORAGE_DIR 后,上传及备份恢复同时将图片按 SHA-256 文件名持久化,启动时分批补齐旧图标,读取时校验文件并从数据库修复缺失或损坏内容。Docker 将 /app/data/icons 绑定到宿主机 /opt/worthpath/data/icons,数据库内容继续用于兼容与自包含 ZIP 备份。内容文件可以被多条图标记录共用,删除数据库记录不自动删除文件。Position.iconId 外键 SetNull,多个账户共享同一图片。所有图标接口使用已验证身份,读取/检索/赋值均限定 shared=true 或 ownerId=当前用户,响应不返回 ownerId。个人上传默认私有;共享发布须中文名称和明确公开确认。拒绝 SVG、动图、损坏图片、超限像素/文件,重编码移除元数据。内置图标固定 ID 追加初始化;在线请求不会发送用户财务数据。
当前备份要求完整 icons 数组,ZIP v9 将图标内容放入 icons.json;内容校验和解码在导入事务前完成,图标在事务内以当前用户私有范围重建,账户关联重映射。清空删除私有图标,公开共享图标不因发布者清空而消失。用户删除时图标 ownerId SetNull,不影响他人已引用的公共图标。
转账及显示偏好
Transfer 归属于 User,关联转出/转入 Position(启用资产账户)及两条 Revision ID。金额、到账金额和额外手续费使用 Decimal(24,8),记录双方原币和业务分钟;账户关系用于配对展示,Transfer 本身不再次计入总额。服务端 Serializable 事务同时创建配对绝对余额及转账记录;请求 UUID 支持相同内容重试。历史修正限制防止改变已配对转账的基准余额。
User.hiddenMenus 保存受枚举校验的菜单键,settings 不可隐藏;User.showNotes 默认 true,仅控制客户端显示,财务备注和导出保持完整。ZIP v5 新增 transfers.json,追加恢复时映射账户及配对历史 ID,空空间恢复显示偏好,已有空间保留当前设置。
2026-10-02 记录编辑更新:允许更正转账之前的独立余额历史。replay.ts 重放涉及项目的历史,绝对余额保留为锚点,配对资金往来与定时支出按增量更新;整笔修改/删除与两侧余额在同一事务提交。单侧配对历史禁止独立更正;2026-10-03 更新后,从任一侧删除会原子删除完整配对记录。日历读取保存后的账户历史重算。完整边界见 更新说明。
2026-10-03 修复:历史重放允许没有绝对余额锚点时从零计算增量,空历史项目金额为零;备份校验、转账和计划支出使用相同规则。账号凭据变更锁定用户行、验证当前密码、更新凭据并在同一事务撤销旧会话和创建新会话;无需新增字段。/auth/me 返回完整隐藏授权状态和会话时间。前端 mutation 更新数据版本,以当前页面重新读取数据,旧视图请求通过 generation 检查丢弃。见 更新说明。
2026-10-03 负债账户溢缴更新:负债账户存储正数欠款、负数溢缴;前端显示和输入取相反符号。统计将负债账户的负余额按汇率转换为正资产,正欠款计入负债,两类分别汇总。独立资产和借入借出债务仍要求非负本金,旧数据和 API 金额含义保留。详见 溢缴更新说明。
2026-10-03 分组排序:User.accountGroupOrder 保存每个用户的账户分组顺序,空值沿用当前默认顺序。前端共享排序上下文,账户卡片、筛选及所有 AccountPicker 使用同一顺序;只显示当前可见分组,保存保留未出现在当前视图的既有偏好。settings 与备份使用相同分组名称和唯一性验证。新增可选 JSON 字段通过带中文注释的增量迁移应用;JSON/ZIP 空空间恢复偏好,已有空间保留当前设置。见 更新说明。
2026-10-03 设置与交互:User.sessionHours 控制 1 至 720 小时的绝对会话有效期,requireHiddenPassword 控制隐藏项目再次验证,overviewCards 保存总览卡片键。设置、JSON/ZIP 备份和带注释的迁移同步;PUT schedules/:id 在计划锁内验证权限并更新未来安排。前端将设置分类、计划原生弹窗、可访问的右上角提示及账户卡片点选快捷转账集中提供。详见 更新说明。
快速记账标记与统计开关(2026-10-04)
Position.lastRepaymentMonth 和 lastBookedDate 分别记录 UTC+8 最后已还款月份与已记账日期,可空且仅保存最后一次人工标记。页面根据当前业务年月/日期显示状态,不通过定时任务删除旧值。标记接口使用用户归属、隐藏可见性、行锁及期望状态检查;网页使用 updatedAt 防止覆盖新操作。资产快速统计开关仅修改 included,不覆盖其他项目元数据。ZIP v9 保存新字段,金额历史不受标记影响。详细操作、接口和验收见 快速记账更新。