Files
WorthPath/docs/architecture.md
T

48 lines
9.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WorthPath 首版设计
2026-10-02 更新:查询、历史分页、趋势重放、借入借出联动及三语言的当前实现和实测见 [性能与联动验收](performance.md)。以下首版设计中的历史 ZIP v3/v4 说明保留作格式沿革;当前导出为 v7,兼容读取 v3/v4/v5/v6/v7 ZIP 和旧 JSON。
本轮账户分组、定时计划、收支日历、迁移步骤与验证边界见 [更新说明](update-2026-10-02.md)。
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 和可选公开来源;Position.iconId 外键 SetNull,多个账户共享同一图片。所有图标接口使用已验证身份,读取/检索/赋值均限定 shared=true 或 ownerId=当前用户,响应不返回 ownerId。个人上传默认私有;共享发布须中文名称和明确公开确认。拒绝 SVG、动图、损坏图片、超限像素/文件,重编码移除元数据。内置图标固定 ID 追加初始化;在线请求不会发送用户财务数据。
备份逻辑增加可选 icons 数组(旧格式缺失可兼容),v4 ZIP 将图标内容放入 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 更新后,从任一侧删除会原子删除完整配对记录。日历读取保存后的账户历史重算。完整边界见 [更新说明](update-2026-10-02.md)。
2026-10-03 修复:历史重放允许没有绝对余额锚点时从零计算增量,空历史项目金额为零;备份校验、转账和计划支出使用相同规则。账号凭据变更锁定用户行、验证当前密码、更新凭据并在同一事务撤销旧会话和创建新会话;无需新增字段。/auth/me 返回完整隐藏授权状态和会话时间。前端 mutation 更新数据版本,以当前页面重新读取数据,旧视图请求通过 generation 检查丢弃。见 [更新说明](update-2026-10-03.md)。