Skip to content

Anchorite-no/ExpensePro

Repository files navigation

ExpensePro 💰

一款全栈 AI 个人记账助手,集成 Google Gemini 实现小票图片智能识别与自动记账。

React Backend AI Database

✨ 功能概览

  • AI 智能记账 — 上传消费小票图片,Gemini AI 自动识别商家、金额、日期、分类,支持批量识别
  • 交互式数据看板 — 堆积面积图、每日明细、分类占比饼图,多维度筛选
  • 用户系统 — JWT 认证,数据隔离
  • 深色/浅色主题 — 自适应切换
  • 自定义分类 — 添加、删除、排序消费分类
  • 响应式设计 — 桌面端与移动端适配

🔐 双版本架构

ExpensePro 支持两种部署模式,同一套代码,通过环境变量切换:

功能 开源版(默认) 私有版
注册方式 开放注册 邀请码注册
AI Key 用户自行配置 服务端统一管理,前端不可见
数据加密 客户端 E2E 加密(管理员无法查看)

通过 .env 中的三个开关控制:

INVITE_CODE=your-invite-code    # 留空=开放注册
SERVER_AI_KEY=AIzaSy...          # 留空=用户自行输入 Key
ENCRYPTION_ENABLED=true          # 留空=不加密

加密说明:启用 E2E 加密后,titlecategorynote 字段在用户浏览器端加密后传输存储,服务端和数据库只存密文。amountdate 不加密以保留排序和统计功能。

🛠️ 技术栈

技术
前端 React 19 + Vite 7 + TypeScript + Recharts
后端 Node.js + Express 5 + Drizzle ORM
数据库 MySQL 8.0
AI Google Gemini API (2.0 Flash / 2.5 Flash)

📁 项目结构

ExpensePro/
├── client/                # React 前端 (Vite)
│   └── src/
│       ├── components/    # UI 组件
│       ├── context/       # Auth Context (含 Master Key 管理)
│       ├── utils/         # 加密工具 (crypto.ts)
│       ├── App.tsx        # 主应用
│       └── App.css        # 全局样式
├── server/                # Express 后端
│   └── src/
│       ├── db/            # Drizzle Schema & 连接
│       ├── crypto.ts      # 服务端加密工具
│       └── index.ts       # API 入口
├── docker-compose.yml     # Docker 一键部署
├── Dockerfile             # 多阶段构建
├── .env.example           # 环境变量模板(Docker 和本地通用)
├── start.bat              # Windows 本地启动脚本
└── package.json           # 根目录启动脚本

🚀 部署指南

环境变量配置

所有部署方式都需要配置环境变量。

Docker 部署:复制根目录的 .env.example 并填入实际值:

cp .env.example .env

```env
DB_PASSWORD=your_secure_password
DB_NAME=expense_pro
JWT_SECRET=change_me_to_a_secure_secret_key
AI_BASE_URL=https://generativelanguage.googleapis.com/v1beta

# 私有版功能开关(留空则不启用)
INVITE_CODE=
SERVER_AI_KEY=
ENCRYPTION_ENABLED=

# 代理(可选)
# HTTP_PROXY=http://host.docker.internal:7890
# HTTPS_PROXY=http://host.docker.internal:7890

# 时区
TZ=Asia/Shanghai
 
# Reverse proxy trust:
# loopback = trust only a local host proxy (safe default)
# 1        = trust one proxy hop (for a proxy container on the same Docker network)
# false    = disable forwarded header trust
TRUST_PROXY=loopback

本地开发:复制 .env.example 中的通用配置到 server/.env,并改用 DATABASE_URL 格式(见模板中的注释)。


方式一:Docker 部署(推荐)

适合服务器部署,一键启动应用和数据库。

前置条件

启动

# 构建并启动(后台运行)
docker compose up -d --build

# ⚠️ 首次启动必须初始化数据库表结构
docker compose exec app npx drizzle-kit push

应用将在 http://127.0.0.1:3001 启动。 默认 Compose 仅绑定到本机回环地址,避免绕过 Nginx/HTTPS 直接暴露 Node 端口。

常用命令

# 查看日志
docker compose logs -f app

# 停止服务
docker compose down

# 停止并清除数据(⚠️ 会删除数据库数据)
docker compose down -v

方式二:本地代码部署

适合开发调试或没有 Docker 的环境。

前置条件

1. 安装 MySQL 并创建数据库

CREATE DATABASE expense_pro CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

2. 配置环境变量

参考根目录 .env.example,在 server/ 目录下创建 .env

DATABASE_URL="mysql://root:你的数据库密码@localhost:3306/expense_pro"
PORT=3001
JWT_SECRET=随机密钥

# 私有版开关(可选)
INVITE_CODE=
SERVER_AI_KEY=
ENCRYPTION_ENABLED=

3. 安装依赖

npm install
cd client && npm install
cd ../server && npm install

4. 初始化数据库

cd server
npx drizzle-kit push

5. 启动

# 方式 A:一键启动
npm start

# 方式 B:手动分别启动
cd server && npm run dev    # 后端 3001
cd client && npm run dev    # 前端 5173

访问 http://localhost:5173


方式三:Docker + 域名 + Nginx 反向代理

适合服务器上已有其他 Docker 服务运行、需要通过域名访问的场景。

整体架构

用户浏览器
  ↓ https://expense.yourdomain.com
Nginx(宿主机或 Docker 容器,监听 80/443)
  ↓ proxy_pass http://127.0.0.1:3001
ExpensePro Docker 容器(监听 3001)
  ↓
MySQL Docker 容器(3306 仅内部访问)

步骤 1:启动 ExpensePro

cd ExpensePro
# 编辑 .env 后启动
docker compose up -d --build

此时 ExpensePro 在 localhost:3001 运行。

步骤 2:配置 Nginx 反向代理

如果宿主机已安装 Nginx,在 /etc/nginx/conf.d/ 创建配置:

# /etc/nginx/conf.d/expense.conf
server {
    listen 80;
    server_name expense.yourdomain.com;

    location / {
        proxy_pass http://127.0.0.1:3001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket 支持(如未来需要)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # 上传图片较大,增加 body 限制
        client_max_body_size 20m;
    }
}
# 测试配置
sudo nginx -t
# 重载
sudo nginx -s reload

步骤 3:DNS 解析

在域名服务商(如 Cloudflare、阿里云 DNS)添加 A 记录:

类型 名称 TTL
A expense 你的服务器 IP 自动

步骤 4:HTTPS(推荐)

使用 Certbot 自动签发 Let's Encrypt 证书:

# 安装 certbot
sudo apt install certbot python3-certbot-nginx

# 自动签发并配置 Nginx
sudo certbot --nginx -d expense.yourdomain.com

# 自动续期(每天检查)
sudo systemctl enable certbot.timer

完成后即可通过 https://expense.yourdomain.com 访问。

如果 Nginx 也运行在 Docker 里

如果你的 Nginx 也是 Docker 容器(如 nginx-proxy 或 Traefik),需要让它和 ExpensePro 在同一个 Docker 网络:

# docker-compose.yml 中添加
services:
  app:
    # ... 现有配置 ...
    environment:
      - TRUST_PROXY=1
    networks:
      - nginx_network   # 加入 Nginx 所在网络
      - default

networks:
  nginx_network:
    external: true       # 引用已存在的 Nginx 网络

然后 Nginx 容器的反向代理配置中,用容器名(而非 127.0.0.1):

proxy_pass http://expensepro-app-1:3001;

📄 License

MIT


Made with ❤️ by Anchorite

About

AI-powered personal expense tracker with receipt image recognition. Built with React 19, Express 5, Drizzle ORM, MySQL, and Google Gemini AI.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors