内容
# WealthAgent
自主托管的净资产跟踪器,带有 AI 代理界面。通过 [Plaid](https://plaid.com) 连接您的银行和券商账户,在网页仪表盘中查看您的投资组合、交易和资本收益,并让 AI 代理(Claude Desktop、Claude Code 或任何支持 [MCP](https://modelcontextprotocol.io) 的代理)通过 OAuth 保护的 MCP 端点查询和注释相同的数据。
**在线演示 / 主机选项:** [www.texasnetworth.com](https://www.texasnetworth.com)(仅限邀请;请发送电子邮件至 support@texasnetworth.com 获取访问权限)。托管服务运行的所有内容都在此仓库中 — 您可以自己搭建完全相同的堆栈。
## 功能
- **投资组合仪表盘** — 账户、持仓、余额历史、资产配置明细
- **交易记录** — 搜索、标签、备注、保存的搜索、批量编辑
- **资本收益** — 实现收益跟踪,带有用户提供的未知批次成本基数
- **Plaid 同步** — 每日自动刷新;访问令牌静止加密(ChaCha20-Poly1305)
- **MCP 服务器** — `/mcp` 端点,支持 OAuth 2.1(PKCE,动态客户端注册)或个人 API 令牌,AI 代理可以通过它读取/注释您的财务数据,具有范围访问权限
- **仅限邀请的多用户** — Google 登录,由您控制的允许列表
## 技术栈
| 层 | 技术 |
| --- | --- |
| 后端 | Rust(axum,sqlx),Postgres 16 |
| 前端 | React + TypeScript + Vite + Tailwind |
| 边缘 | Caddy(TLS,安全头部,反向代理) |
| 部署 | 单个 VM 上的 Docker Compose |
## 快速开始(本地开发)
前提条件:
- Rust(稳定版),Node 20+,Docker
- 一个 [Plaid](https://dashboard.plaid.com) 账户 — 免费的**沙盒**密钥有效
- 一个 [Google OAuth 2.0 客户端 ID](https://console.cloud.google.com/apis/credentials)(类型:Web 应用程序,授权的 JS 来源 `http://localhost:5173`)
### 1. 启动 Postgres
```sh
docker run -d --name wealth-pg -p 5432:5432 \
-e POSTGRES_USER=wealthagent -e POSTGRES_PASSWORD=dev -e POSTGRES_DB=wealthagent \
postgres:16-alpine
```
### 2. 配置和运行后端
```sh
cd backend
openssl rand 32 > keyfile.local # Plaid 令牌加密密钥(gitignored)
cat > .env <<EOF
DATABASE_URL=postgres://wealthagent:dev@localhost:5432/wealthagent
JWT_SECRET=$(openssl rand -base64 64 | tr -d '\n')
APP_ENCRYPTION_KEY_PATH=./keyfile.local
GOOGLE_CLIENT_ID=<您的 Google 客户端 ID>.apps.googleusercontent.com
OWNER_EMAILS=您@example.com # 您的 Google 电子邮件 — 初始化邀请允许列表
PLAID_CLIENT_ID=<您的 Plaid 客户端 ID>
PLAID_SECRET=<您的 Plaid 沙盒密钥>
PLAID_ENV=sandbox
PLAID_PRODUCTS=auth,transactions,investments
PLAID_COUNTRY_CODES=US
EOF
cargo run # 迁移自动运行;监听 :8080
```
### 3. 运行前端
```sh
cd frontend
npm install
echo 'VITE_GOOGLE_CLIENT_ID=<您的 Google 客户端 ID>.apps.googleusercontent.com' > .env
npm run dev # http://localhost:5173,代理 /api 至 :8080
```
使用您在 `OWNER_EMAILS` 中填写的 Google 账户登录,点击 **添加机构**,并使用 Plaid 沙盒凭证(`user_good` / `pass_good`)链接一个虚拟银行。
### 邀请更多用户
登录受允许列表控制。 使用管理员 CLI 添加人员:
```sh
# 本地开发
cargo run --bin admin -- invite add friend@example.com "大学室友"
# 生产环境(在容器内)
docker compose exec backend entrypoint.sh admin invite add friend@example.com
```
## 生产环境部署
完整的部署手册在 [DEPLOY.md](DEPLOY.md) 中:提供一个 Ubuntu 虚拟机,运行 `ops/bootstrap-vm.sh`(Docker,UFW,强化 SSH),为 [secrets/README.md](secrets/README.md) 中的密钥生成秘密,设置您的 DNS 解析到虚拟机,编辑 `Caddyfile` 以使用您的域名,并运行 `docker compose up -d`。Caddy 自动获取 TLS 证书。通过 `ops/backup.sh` 和 `ops/systemd/` 中的 systemd 单元,设置了加密的异地备份到 Backblaze B2。
首次部署后的部署只需在您的笔记本电脑上运行一个命令:
```sh
DEPLOY_SERVER=wealth@<您的虚拟机 IP> DEPLOY_APP_URL=https://app.example.com ./ops/deploy.sh
```
## 连接 AI 代理
运行后,后端在 `https://<您的应用域名>/mcp` 处提供 MCP,具有两种身份验证选项:
- **OAuth 2.1** — Claude Desktop 和其他 MCP 客户端可以一键连接;应用显示一个具有范围授予的同意屏幕,您可以撤销这些授予。
- **个人 API 令牌** — 在应用的设置 → API 令牌下创建一个,然后使用 `Authorization: Bearer wa_pat_...`。
有关客户端配置示例,请参见 `backend/skills/wealthAgent/skill.md`。
## 隐私加密(操作员盲模式)
设置 `PRIVACY_ENCRYPTION=on`,用户可以选择(通过 `POST /api/privacy/setup`,带有口令短语)对其数据的识别文本进行每用户加密 — 交易描述、商户名称、备注、账户名称和证券身份(股票代码、证券名称、持仓)。其工作原理如下:
- 每个选择加入的用户都会获得一个 X25519 密钥对。公钥保留在数据库中,因此夜间 Plaid 同步**在用户离线时密封新数据** — 加密不需要秘密。
- 私钥仅被**包装**存储:受 Argon2id 密钥的保护,该密钥源自用户的口令短语,以及源自每个 API 令牌原始值的密钥(数据库仅存储哈希值)。解锁 (`POST /api/privacy/unlock`) 将密钥保存在服务器内存中,超时时间为 12 小时。
- 结果:`SELECT * FROM transactions` 在服务器上显示这些字段的密文。操作员无法通过查询数据库或读取磁盘来读取用户购买了**什么**或在**哪里**购买。
诚实的限制:金额、日期、标签和数量保持明文(SQL 聚合依赖于它们),以及哨兵符号(CASH/DEBT/N-A)和 Plaid `security_id`s(持有物插入键 — 可由具有自己 Plaid 凭证的操作员解析);资本利得需要解锁会话,因为 FIFO 批次匹配需要解密的股票代码。恶意操作员仍可以在 Plaid 同步时捕获明文或在活动会话期间转储进程内存 — 这可以防止诚实但好奇的操作员和被盗的数据库副本,而不是完全被破坏的服务器。**没有口令恢复**:丢失口令意味着从银行擦除和重新同步(只有标签/备注/手动成本基数是真正用户生成的)。在选择加入之前创建的 API 令牌无法解密 — 请在解锁时重新创建它们。
## 自托管者的安全注意事项
- 所有秘密都存储在文件中(Docker 机密 / `/etc/wealthagent/secrets/`),而不在仓库中。永远不要提交任何 `.env` 变体。
- 财务行(余额、交易)默认在 Postgres 中为明文;`ops/encrypt-pgdata.sh` 将数据卷移到 LUKS 加密的文件系统上(参见 DEPLOY.md §14),而 `PRIVACY_ENCRYPTION=on` 为识别文本列添加每用户操作员盲加密(参见上文)。
- Plaid 访问令牌在存储时加密;删除一个项目会调用 Plaid 的 `/item/remove`,以便泄露的行不能被重放。
- 会话 JWT 具有短窗口,硬上限为 30 天;OAuth 访问令牌绑定到受众并类型保护。
- 在 `.pre-commit-config.yaml` 中配置了 pre-commit gitleaks 钩子 — 如果您计划贡献,请在克隆后运行 `pre-commit install`。
## 许可证
[MIT](LICENSE)。这不是财务建议,软件不提供任何保证;您正在处理自己的银行凭证和数据。