# simple-ledger **Repository Path**: fuzhenli/simple-ledger ## Basic Information - **Project Name**: simple-ledger - **Description**: 简簿记(轻量记账,管好日常收支) 个人用户记账的项目,不会商用 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-22 - **Last Updated**: 2026-10-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # simple-ledger · 简单记账 个人记账微信小程序 + 自建后端。数据落自有服务器的 MySQL,**免费、随时导出 CSV/JSON,无平台锁定**——这是本项目的立项动机(商业记账 App 导出收费)。 > 完整设计、部署与安全方案见 [docs/开发文档.md](docs/开发文档.md)(v2.1,已按宝塔服务器环境适配)。 ## 功能(MVP / P0) - **微信登录**:wx.login 静默登录,首次自动建号并初始化预置分类(账户由用户自建),token 过期自动续期无感; - **记一笔**:支出 / 收入 / 转账三态,金额全程整数「分」运算,无浮点误差(0.1 + 0.2 = 0.30); - **流水明细**:按月查看、按日分组倒序、每日小计、当月结余,点击编辑/删除(软删); - **账户管理**:账户全部由用户自建(现金/微信/支付宝/银行卡/信用卡等类型,存量用户可一键清理历史预置账户),余额后端聚合,信用卡负债红字展示; - **分类管理**:预置常用分类,自定义名称/emoji 图标/排序,内置分类仅隐藏; - **月度报表**:收支结余总览、分类占比饼图、近 6 月趋势折线(后端 SQL 聚合); - **CSV 导出 ⭐**:按时间范围导出,Excel 双击打开无乱码,公式注入已转义,转发文件传输助手/剪贴板兜底; - **数据备份**:全量 JSON 导出 + 服务器每日自动备份(宝塔计划任务)。 P1(规划中):预算、搜索、回收站、周期记账、后端 CSV 直下、年度视图。 ## 总体架构 ``` 微信小程序(uni-app, Vue3+TS) 浏览器(PC 导出备份, P1) │ HTTPS / JSON │ HTTPS ▼ ▼ api.fuzhenweb.com (宝塔 Nginx :443,与既有项目共用域名,证书复用) │ 按 location 前缀分流 ├── / → 既有项目(配置零改动) └── /ledger/ → ledger-api(NestJS,仅监听 127.0.0.1:3021) │ ▼ 宝塔 MySQL 实例 · ledger 库(仅本机可达,utf8mb4) ``` ## 仓库结构 ``` simple-ledger/ ├── ledger-api/ # 后端:NestJS + Prisma + MySQL │ ├── prisma/schema.prisma # 数据库唯一事实源(金额 BIGINT 存分) │ └── src/ │ ├── auth/ # 微信登录 / JWT 双 token / 限流 / dev-login(条件注册) │ ├── bills/ # 账单三态 CRUD(软删 + 越权防护) │ ├── categories/ # 分类(内置仅隐藏) │ ├── accounts/ # 账户 + 余额聚合 │ ├── budgets/ # 预算 upsert(0=总预算语义) │ ├── reports/ # 月度/趋势 SQL 聚合(参数化 raw) │ ├── data/ # 全量 JSON 导出 / 清空(二次确认+审计) │ ├── common/ # 日志脱敏、异常过滤器(traceId)、日期工具、预置字典 │ └── prisma/ # PrismaService 全局单例 ├── ledger-mini/ # 小程序:uni-app Vue3 + TS + Vite + Pinia + uCharts │ └── src/ │ ├── pages/ # detail(明细) report(报表) profile(我的) edit(记一笔) accounts categories │ ├── components/ # month-picker / tx-item / chart(uCharts canvas2d 封装) │ ├── api/ # 按域封装的接口层(类型齐全) │ ├── utils/ # request(401单飞刷新) money(分⇄元) csv(BOM+公式注入转义) export-csv │ └── stores/ # Pinia:auth(静默登录)/ dicts(字典缓存) ├── deploy/ # 宝塔部署配套:Nginx location 片段、备份脚本 └── docs/开发文档.md # 完整开发文档(含宝塔实操部署、安全设计、里程碑) ``` ## 技术栈 | 端 | 选型 | |---|---| | 小程序 | uni-app(Vue 3 + TS + Vite)、Pinia、uni-ui(easycom 按需)、uCharts | | 后端 | Node 20、NestJS 10、Prisma 5、MySQL(宝塔实例,≥5.7 建议 8.0)、JWT 双 token、@nestjs/throttler | | 部署 | 宝塔 Nginx 反代(路径 `/ledger/` 区分)+ PM2(宝塔 Node 项目)+ 宝塔计划任务备份 | ## 快速开始(本地开发) 前置:Node ≥ 20、本地 MySQL 8(或 Docker 起一个:`docker run -d --name ledger-mysql -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=ledger -e MYSQL_USER=ledger -e MYSQL_PASSWORD=ledger123 -p 127.0.0.1:3306:3306 mysql:8.0`)。 ### 后端 ledger-api ```bash cd ledger-api cp .env.example .env # 填 DATABASE_URL / JWT 密钥 / 微信凭证 npx prisma migrate dev --name init # 建表 npm run start:dev # http://127.0.0.1:3021/ledger/v1 ``` 验证: ```bash curl http://127.0.0.1:3021/ledger/v1/ping # {"ok":true,...} # 未配置微信 AppID 时,可在 .env 设 AUTH_DEV_BYPASS=true 后: curl -X POST http://127.0.0.1:3021/ledger/v1/auth/dev-login \ -H 'Content-Type: application/json' -d '{"username":"dev"}' ``` > `AUTH_DEV_BYPASS=true` 只应在本地/测试开启;生产环境该路由**不注册**(404)。 ### 小程序 ledger-mini ```bash cd ledger-mini npm install npm run dev:mp-weixin # 产物 dist/dev/mp-weixin ``` 微信开发者工具 → 导入项目 → 目录选 `dist/dev/mp-weixin` → 填入小程序 AppID(`src/manifest.json` 的 `mp-weixin.appid` 也要填)→ 详情 → 本地设置 → 勾选**「不校验合法域名」**(联调期)。 真机预览时把 `ledger-mini/.env.development` 的 `VITE_API_BASE` 改成开发机局域网 IP。 ## 测试 ```bash cd ledger-api && npm test # Jest:账单三态校验、越权防线(updateMany 必带 userId)、内置分类保护 cd ledger-mini && npm test # Vitest:分⇄元无浮点误差、CSV BOM/公式注入转义 ``` ## 部署(宝塔服务器) 完整步骤见 [docs/开发文档.md 第 10 章](docs/开发文档.md),要点: 1. 宝塔数据库:新建 `ledger` 库 + `ledger` 账号(仅本地、utf8mb4); 2. Node 版本管理器装 Node 20,`npm ci && npm run build && npx prisma migrate deploy`; 3. 宝塔「Node 项目」托管:启动文件 `dist/main.js`,端口 3021,`.env` 权限 600; 4. 站点 api.fuzhenweb.com 配置文件中加入 `deploy/nginx-ledger.conf` 的 location 片段,`nginx -t && nginx -s reload`; 5. 验收:`curl https://api.fuzhenweb.com/ledger/v1/ping` → `{"ok":true}`,且老项目接口回归正常; 6. 计划任务每日备份 ledger 库(兜底脚本 `deploy/ledger-backup.sh`)。 上线检查(安全红线): - [ ] 生产 `.env` 中 `AUTH_DEV_BYPASS` 为 false(dev-login 返回 404); - [ ] 服务只监听 127.0.0.1:3021(`ss -lntp` 复核); - [ ] 3306 对公网不可达(`nmap -Pn -p 3306 `); - [ ] `.env` 未入 Git(`git ls-files | grep .env` 为空)。 ## 安全设计速览(详见开发文档第 12 章) - 所有数据访问强制绑定 JWT 身份(`where: { id, userId }`),越权一律 404; - Prisma 全参数化查询(含 `$queryRaw` 标签模板),无字符串拼接 SQL; - 全局 DTO 校验(whitelist + forbidNonWhitelisted),金额/枚举/长度白名单; - 双 token(access 2h / refresh 30d),密钥仅存服务器环境变量; - 登录限流 10 次/分/IP(trust proxy 取真实 IP);日志脱敏、异常只暴露 traceId; - CSV 公式注入转义(`= + - @` 前缀加 `'`)+ UTF-8 BOM; - MySQL 仅本机可达、应用账号最小权限;软删除 + 每日备份。 ## 里程碑 | 阶段 | 状态 | |---|---| | M0 基建适配 | ✅ 双端工程搭建、构建与单测通过 | | M1 后端骨架 | ✅ 登录/JWT/限流/账单/分类/账户/预算/报表/导出接口 | | M2 前端骨架 | ✅ 登录/记一笔/明细闭环 + 账户/分类管理 + 报表图表 | | M3 报表与预算 | ✅ 后端聚合已实现;前端预算页随 F09(P1)迭代 | | M4 导出与备份 | ✅ CSV 导出/JSON 备份已实现;服务器每日备份待部署时配置 | | M5 上线 | ⏳ 待域名备案通过后按部署章节执行 |