Docker一键部署Study-Tracker学习追踪系统
🌟 项目特色
- 🎯 智能学习追踪 - 记录学习时间、进度和目标完成情况
- 📊 数据可视化 - 丰富的图表和统计分析功能
- 🏆 成就系统 - 激励用户持续学习的积分和成就机制
- 📱 移动端优化 - 完美适配移动平板设备
- 📱 PWA 支持 - 渐进式 Web 应用,支持离线访问和桌面安装
- 🔄 实时同步 - WebSocket 实时数据更新
- 🛡️ 安全可靠 - JWT 认证、密码加密、XSS 防护
- 🎨 现代化 UI - Tailwind CSS + Alpine.js 响应式设计
- 🐳 Docker 部署 - 一键部署,支持生产环境
- 📖 完整文档 - VitePress 构建的详细文档系统
📋 功能模块
👤 用户管理
- 用户注册、登录、密码重置
- 角色权限管理(管理员、普通用户)
- 用户资料管理和头像上传
- 头像动画系统(20+ 动画效果)
- 用户状态实时显示
📚 学习项目管理
- 创建、编辑、删除学习项目
- 项目分类和标签管理
- 学习进度追踪
- 项目状态管理(进行中、已完成、暂停)
- 项目图片上传和展示
- 项目评分标准设置
⏱️ 学习时间追踪
- 学习会话记录
- 时间统计和分析
- 学习目标设定
- 学习习惯分析
- 专注模式支持
- 学习提醒功能
📈 数据统计与分析
- 学习时间趋势图
- 项目完成率统计
- 个人学习报告
- 数据导出功能(Excel/CSV)
- 自定义时间范围分析
- 学习效率评估
🏆 成就与积分系统
- 学习成就解锁(50+ 成就类型)
- 积分获取和消费
- 积分兑换商城
- 虚拟商品管理
- 兑换记录和审批
- 排行榜系统
🔔 通知系统
- 实时消息推送
- 学习提醒
- 成就通知
- 系统公告
- 通知设置管理
- 未读消息统计
- 钉钉群机器人通知(积分兑换实时推送)
📱 PWA 功能
- 离线访问 - Service Worker 缓存核心资源,支持离线使用
- 桌面安装 - 支持添加到主屏幕,像原生应用一样使用
- 推送通知 - 支持浏览器推送通知(学习提醒、成就通知)
- 应用更新 - 自动检测和提示应用更新
- 响应式图标 - 适配不同设备和屏幕尺寸
- 启动画面 - 优化的应用启动体验
📊 管理后台
- 用户管理
- 系统配置
- 数据统计
- 日志监控
- 成就管理
- 积分规则配置
- SMTP 邮件配置
- 头像动画配置
- 钉钉群机器人配置
🛠️ 技术栈
后端技术
- Node.js - 服务器运行环境
- Express.js - Web 应用框架
- PostgreSQL - 主数据库
- Redis - 缓存和会话存储
- Knex.js - SQL 查询构建器
- Socket.io - 实时通信
- JWT - 身份认证
- bcrypt - 密码加密
- Multer - 文件上传处理
- 钉钉机器人 API - 群机器人消息推送
前端技术
- Handlebars - 模板引擎
- Tailwind CSS - 样式框架
- Alpine.js - 轻量级 JavaScript 框架
- Chart.js - 图表库
- HTMX - 动态内容加载
- Font Awesome - 图标库
- PWA - 渐进式 Web 应用支持
开发工具
- Nodemon - 开发环境自动重启
- PostCSS - CSS 处理
- PM2 - 生产环境进程管理
- Helmet - 安全中间件
- VitePress - 文档系统
部署技术
- Docker - 容器化部署
- Docker Compose - 多容器编排
- Nginx - 反向代理(可选)
- Nginx Proxy Manager - 推荐的反向代理方案
📦 系统要求
开发环境
- Node.js >= 16.0.0
- PostgreSQL >= 12.0
- Redis >= 6.0
- npm >= 8.0
生产环境
- Ubuntu 20.04+ 或 CentOS 7+
- Docker >= 20.10.0
- Docker Compose >= 1.25.0
- Nginx Proxy Manager(推荐)
🔔 钉钉群机器人通知功能
功能概述
系统集成了钉钉群机器人通知功能,当用户进行积分兑换时,会自动发送美观的互动卡片消息到指定的钉钉群,让管理员能够第一时间了解兑换情况。
主要特性
- 🎯 实时推送 - 用户兑换商品后立即发送通知
- 🎨 美观卡片 - 结构化的互动卡片消息,信息清晰
- 👤 用户信息 - 显示兑换用户的详细信息
- 🛒 兑换详情 - 商品名称、数量、积分消耗等
- ⏰ 时间记录 - 精确的兑换时间记录
- 🔗 快捷操作 - 提供"立即审核"和"查看详情"按钮
- 🔒 安全配置 - 支持签名验证和关键词验证
配置步骤
1. 创建钉钉群机器人
- 在钉钉群中点击"群设置" → "智能群助手" → "添加机器人"
- 选择"自定义"机器人
- 设置机器人名称(如:StudyTracker)
- 获取 Webhook URL 和签名密钥
2. 系统配置
在管理后台 → "钉钉配置" 中设置:
- Webhook URL: 钉钉机器人的 Webhook 地址
- 签名密钥: 机器人的签名密钥(可选,推荐启用)
- 关键词: 消息关键词(可选)
- 启用状态: 开启/关闭通知功能
3. 测试连接
点击"测试连接"按钮,验证配置是否正确。
钉钉消息卡片内容示例(可自行接入高级卡片互动)
demo的积分商品兑换详情
👤 用户: demo
📧 邮箱: demo@example.com
🎁 商品名称: XX一日游
🔢 兑换数量: 1
💎 消耗积分: 25000积分
✅ 兑换状态: 待审核
✍️ 是否需要审核: 是
📅 兑换时间: 2025/08/03
⏰ 具体时间: 20:30:45
📎 发送方: https://yourdomain.com
💡 系统提示: 请及时处理兑换申请,确保用户体验!
安全注意事项
- 🔐 签名验证: 强烈建议启用签名验证,确保消息安全性
- 🔑 密钥管理: 签名密钥请妥善保管,不要泄露
- 📝 关键词: 可设置关键词过滤,只接收包含特定关键词的消息
- 🚫 访问控制: 只有管理员可以配置钉钉设置
一、部署过程及项目说明
方法一:本地开发环境(非 Docker)
适用于: 本地开发、调试、自定义配置
1. 克隆项目
git clone https://github.com/laurawu0122/study-tracker.git
cd study-tracker
2. 安装依赖
npm install
3. 环境配置
复制环境配置文件:
cp env.example .env
编辑 .env
文件,配置数据库连接(完整版参见文章下方的配置文件):
# 数据库配置
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your_password
DB_NAME=study_tracker_dev
# Redis 配置
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
# JWT 配置
# ⚠️ 安全提醒:请使用强密钥,不要使用默认值!
# 生成方法见下方 JWT 密钥安全指南
JWT_SECRET=CHANGE_THIS_JWT_SECRET_IN_PRODUCTION_ENVIRONMENT
JWT_REFRESH_SECRET=CHANGE_THIS_JWT_REFRESH_SECRET_IN_PRODUCTION_ENVIRONMENT
# CORS配置
CORS_ORIGIN=http://localhost:3001
CORS_CREDENTIALS=true
DOCS_CORS_ORIGIN=http://localhost:5173
# 钉钉群机器人配置(可选)
# 用于积分兑换实时通知推送
DINGTALK_WEBHOOK_URL=
DINGTALK_SECRET=
DINGTALK_KEYWORD=
DINGTALK_ENABLED=false
4. 数据库设置
确保 PostgreSQL 和 Redis 服务正在运行,然后执行:
npm run db:setup
5. 构建 CSS
npm run build:css:dev
6. 启动开发服务器
npm run dev
服务器将在 http://localhost:3001 启动
7. 启动文档系统(可选)
cd docs
npm install
npm run docs:dev
文档系统将在 http://localhost:5173 启动
8. 测试 PWA 功能(可选)
访问以下页面测试 PWA 功能:
- PWA 测试页面: http://localhost:3001/pwa-test.html
- PWA 调试工具: http://localhost:3001/pwa-debug.html
- 完整测试页面: http://localhost:3001/pwa-test-complete.html
方法二:Docker 一键部署(推荐)
适用于: 生产环境、快速部署、容器化运行
🐳 Docker 开发环境部署
重要说明:
- 🐳 Docker 部署需要
.env
文件 - 用于存储敏感配置(密码、密钥) - 📝 部署脚本会自动创建
.env
文件模板,用户只需编辑配置 - 🔧 环境变量 通过
.env
文件传递给 Docker Compose - 🔒 安全配置 - 数据库密码、Redis 密码、JWT 密钥等敏感信息
部署流程:
- 首次运行 - 脚本会自动从
env.example
创建.env
文件 - 配置密码 - 编辑
.env
文件,设置数据库和 Redis 密码 - 重新运行 - 再次执行
./deploy-prod.sh
完成部署
1. 克隆项目
git clone <your-repository-url>
cd study-tracker
2. 一键部署
# 给部署脚本执行权限
chmod +x deploy.sh
# 执行一键部署
./deploy.sh
部署脚本会自动:
- ✅ 检查系统环境
- ✅ 安装 Docker(如果未安装)
- ✅ 创建必要的目录和文件
- ✅ 生成环境配置文件
- ✅ 启动所有服务
- ✅ 验证服务状态
3. 访问系统
- 主应用: http://localhost:3001
- 文档系统: http://localhost:5173
- 管理后台: http://localhost:3001/admin
4. 测试 PWA 功能
访问以下页面测试 PWA 功能:
- PWA 测试页面: http://localhost:3001/pwa-test.html
- PWA 调试工具: http://localhost:3001/pwa-debug.html
- 完整测试页面: http://localhost:3001/pwa-test-complete.html
🐳 Docker 生产环境部署
1. 准备环境
确保服务器满足以下要求:
- Ubuntu 20.04+ 或 CentOS 7+
- 至少 2GB 内存
- 至少 10GB 磁盘空间
- 开放端口:3001, 5173, 5432, 6379
2. 克隆项目
git clone https://github.com/laurawu0122/study-tracker.git
cd study-tracker
3. 配置环境变量
# 复制生产环境配置模板
cp env.example .env
# 编辑配置文件
nano .env
生产环境配置示例:
# 生产环境配置
NODE_ENV=production
# 数据库配置
DB_HOST=postgres
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your_secure_password
DB_NAME=study_tracker_prod
# Redis 配置
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=your_redis_password
REDIS_DB=0
# JWT 配置
# ⚠️ 安全提醒:生产环境必须使用强密钥!
# 生成方法见下方 JWT 密钥安全指南
JWT_SECRET=CHANGE_THIS_JWT_SECRET_IN_PRODUCTION_ENVIRONMENT
JWT_REFRESH_SECRET=CHANGE_THIS_JWT_REFRESH_SECRET_IN_PRODUCTION_ENVIRONMENT
# 域名配置
DOMAIN=https://yourdomain.com
DOCS_DOMAIN=https://docs.yourdomain.com
# CORS配置
CORS_ORIGIN=https://yourdomain.com
CORS_CREDENTIALS=true
DOCS_CORS_ORIGIN=https://docs.yourdomain.com
# 安全配置
SESSION_SECURE_COOKIES=true
LOG_LEVEL=warn
LOG_SECURITY_EVENTS=true
4. 一键生产部署
# 给部署脚本执行权限
chmod +x deploy-prod.sh
# 执行生产环境部署
./deploy-prod.sh
生产部署脚本会自动:
- ✅ 检查系统环境
- ✅ 验证 Docker 版本兼容性
- ✅ 创建生产环境配置
- ✅ 设置数据持久化
- ✅ 配置安全设置
- ✅ 启动生产服务
- ✅ 验证服务状态
5. 配置 Nginx Proxy Manager
5.1 安装 Nginx Proxy Manager
# 创建 NPM 目录
mkdir -p /opt/nginx-proxy-manager
cd /opt/nginx-proxy-manager
# 下载 docker-compose.yml
wget https://raw.githubusercontent.com/jc21/nginx-proxy-manager/master/docker-compose.yml
# 启动 NPM
docker-compose up -d
5.2 配置主应用代理
- 访问 NPM 管理界面:http://your-server-ip:81
- 默认登录信息:
- Email:
admin@example.com
- Password:
changeme
- Email:
- 添加代理主机:
- Domain Names:
yourdomain.com
- Scheme:
http
- Forward Hostname/IP:
localhost
- Forward Port:
3001
- 启用 SSL: 选择 Let's Encrypt
- 启用 Force SSL: 是
- 启用 HTTP/2 Support: 是
- Domain Names:
5.3 配置文档系统代理
- 添加第二个代理主机:
- Domain Names:
docs.yourdomain.com
- Scheme:
http
- Forward Hostname/IP:
localhost
- Forward Port:
5173
- 启用 SSL: 选择 Let's Encrypt
- 启用 Force SSL: 是
- 启用 HTTP/2 Support: 是
- Domain Names:
5.4 高级配置(可选)
在代理主机的高级设置中:
# 自定义 Nginx 配置
location / {
proxy_pass http://localhost: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";
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
6. 访问生产系统
🐳 Docker 部署注意事项
重要提醒
-
端口配置:
- 主应用端口:3001
- 文档系统端口:5173
- 数据库端口:5432(仅本地访问)
- Redis 端口:6379(仅本地访问)
-
数据持久化:
- PostgreSQL 数据存储在
./data/postgres
目录 - Redis 数据存储在
./data/redis
目录 - 上传文件存储在
./uploads
目录 - 日志文件存储在
./logs
目录
- PostgreSQL 数据存储在
-
CORS 配置:
- 主应用 CORS:
CORS_ORIGIN=https://yourdomain.com
- 文档系统 CORS:
DOCS_CORS_ORIGIN=https://docs.yourdomain.com
- 多域名配置:
CORS_ORIGIN=https://yourdomain.com,https://docs.yourdomain.com
- 主应用 CORS:
-
安全配置:
- 生产环境启用 HTTPS
- 使用强密码和 JWT 密钥
- 启用安全 Cookie
- 配置防火墙规则
-
性能优化:
- 启用 Gzip 压缩
- 配置静态资源缓存
- 使用 Redis 缓存热点数据
- 数据库连接池优化
🗑️ 卸载系统
安全卸载(推荐)
如果不再需要此系统,可以使用卸载脚本安全地清理项目相关资源:
# 给卸载脚本执行权限
chmod +x uninstall.sh
# 执行卸载
./uninstall.sh
卸载脚本会自动清理:
- ✅ 项目 Docker 容器:study-tracker-app-prod、study-tracker-postgres-prod、study-tracker-redis-prod、study-tracker-docs-prod
- ✅ 项目数据卷:postgres_data、redis_data、app_logs、app_uploads
- ✅ 项目网络:study-tracker-network
- ✅ 项目 Nginx 配置:study-tracker 相关配置和 SSL 证书
- ✅ 项目系统服务:study-tracker 服务
- ✅ 项目防火墙规则:仅项目相关端口 (3001, 5173)
💡 安全特性:卸载脚本只清理项目相关资源,不会影响服务器上的其他应用和配置
手动卸载
如果卸载脚本无法正常工作,可以手动执行以下步骤:
1. 停止并删除项目 Docker 容器
# 使用 docker-compose 停止项目容器
docker-compose -f docker-compose.prod.yml down --remove-orphans
# 删除项目相关容器
docker rm -f study-tracker-app-prod study-tracker-postgres-prod study-tracker-redis-prod study-tracker-docs-prod
2. 删除项目 Docker 资源
# 删除项目相关的镜像(只删除项目构建的镜像)
docker images --format "{{.Repository}}:{{.Tag}}" | grep "study-tracker" | while read image; do
if [[ -n "$image" ]]; then
echo "删除镜像: $image"
docker rmi "$image" 2>/dev/null || true
fi
done
# 删除项目相关的数据卷
docker volume rm postgres_data redis_data app_logs app_uploads 2>/dev/null || true
# 删除项目网络
docker network rm study-tracker-network 2>/dev/null || true
3. 清理项目系统配置
# 清理项目相关的 Nginx 配置
sudo rm -f /etc/nginx/sites-available/study-tracker
sudo rm -f /etc/nginx/sites-enabled/study-tracker
sudo rm -f /etc/nginx/conf.d/study-tracker.conf
# 删除项目相关的 SSL 证书
sudo rm -f /etc/nginx/ssl/study-tracker* 2>/dev/null || true
# 重新加载 Nginx(如果配置有效)
if sudo nginx -t 2>/dev/null; then
sudo systemctl reload nginx
fi
# 清理项目系统服务
sudo systemctl stop study-tracker 2>/dev/null || true
sudo systemctl disable study-tracker 2>/dev/null || true
sudo rm -f /etc/systemd/system/study-tracker.service
sudo systemctl daemon-reload
# 清理项目防火墙规则(只删除项目端口 3001, 5173)
# 使用编号删除规则,避免误删其他规则
ufw status numbered | grep "ALLOW.*3001/tcp" | head -1 | sed 's/\[\([0-9]*\)\].*/\1/' | while read rule_num; do
if [[ -n "$rule_num" ]]; then
echo "y" | sudo ufw delete "$rule_num" 2>/dev/null || true
fi
done
ufw status numbered | grep "ALLOW.*5173/tcp" | head -1 | sed 's/\[\([0-9]*\)\].*/\1/' | while read rule_num; do
if [[ -n "$rule_num" ]]; then
echo "y" | sudo ufw delete "$rule_num" 2>/dev/null || true
fi
done
⚠️ 重要提醒
- 数据备份:卸载前请确保已备份重要数据
- 不可逆操作:卸载后项目数据将被永久删除
- 安全特性:卸载脚本只清理项目相关资源,不会影响服务器上的其他应用和配置
- 重新安装:卸载后如需重新安装,请重新运行
deploy-prod.sh
🧹 Docker 镜像清理
清理 标签镜像
在 Docker 构建过程中可能会产生一些 <none>
标签的镜像,这些是构建过程中的中间层。可以使用以下脚本清理:
# 快速清理 <none> 镜像
./quick-cleanup.sh
# 完整清理所有未使用的 Docker 资源
./cleanup-docker.sh
手动清理命令
# 查看当前镜像状态
docker images
# 清理 <none> 标签的镜像
docker images -f "dangling=true" -q | xargs -r docker rmi -f
# 清理所有未使用的资源
docker system prune -f
👤 默认账户
管理员账户
- 用户名: admin
- 密码: ChangeMe123!
演示账户
- 用户名: demo_user
- 演示用户禁止上传、编辑、删除操作,仅提供部分界面的预览
📁 项目结构
study-tracker/
├── assets/ # 静态资源
│ ├── css/ # CSS 文件
│ ├── js/ # JavaScript 文件
│ ├── ico/ # 图标文件
│ └── lib/ # 第三方库
├── database/ # 数据库相关
│ ├── migrations/ # 数据库迁移
│ └── seeds/ # 种子数据
├── docs/ # 项目文档(VitePress)
│ ├── .vitepress/ # VitePress 配置
│ ├── api/ # API 文档
│ ├── deployment/ # 部署文档
│ └── features/ # 功能文档
├── middleware/ # 中间件
├── public/ # 公共文件
├── routes/ # 路由文件
├── services/ # 业务逻辑服务
├── uploads/ # 上传文件
├── utils/ # 工具函数
├── views/ # 视图模板
├── Dockerfile # 主应用 Docker 配置
├── Dockerfile.docs # 文档系统 Docker 配置
├── docker-compose.yml # 开发环境 Docker Compose
├── docker-compose.prod.yml # 生产环境 Docker Compose
├── deploy.sh # 开发环境部署脚本
├── deploy-prod.sh # 生产环境部署脚本
├── build-docs-quick.sh # 快速文档构建脚本
├── check-docs-status.sh # 文档状态检查脚本
├── server.js # 主服务器文件
├── package.json # 项目配置
└── knexfile.js # 数据库配置
🔧 开发指南
可用的 npm 脚本
# 开发环境
npm run dev # 启动开发服务器
npm run dev:clean # 清理端口后启动
npm run dev:full # 启动完整开发环境
# 数据库操作
npm run db:setup # 设置数据库
npm run db:migrate # 运行迁移
npm run db:seed # 运行种子数据
npm run db:reset # 重置数据库
# 构建
npm run build:css:dev # 构建开发环境 CSS
npm run build:css:prod # 构建生产环境 CSS
# 生产环境
npm run start # 启动生产服务器
npm run start:pm2 # 使用 PM2 启动
# 日志
npm run log:view # 查看错误日志
npm run log:view-all # 查看所有日志
# 文档系统
cd docs
npm run docs:dev # 启动文档开发服务器
npm run docs:build # 构建文档
npm run docs:preview # 预览构建后的文档
Docker 管理命令
# 查看服务状态
docker-compose ps
# 查看服务日志
docker-compose logs -f app
docker-compose logs -f docs
docker-compose logs -f postgres
docker-compose logs -f redis
# 重启服务
docker-compose restart app
docker-compose restart docs
# 停止所有服务
docker-compose down
# 停止并删除数据卷
docker-compose down -v
# 重新构建镜像
docker-compose build --no-cache
# 进入容器
docker-compose exec app bash
docker-compose exec postgres psql -U postgres
代码规范
- 使用 ESLint 进行代码检查
- 遵循项目既定的目录结构
- 所有 API 接口必须添加认证中间件
- 数据库操作使用参数化查询
- 前端使用 Alpine.js 进行状态管理
- 所有敏感信息使用环境变量配置
🚀 部署指南
📋 部署脚本说明
项目提供了多个部署脚本,根据不同的使用场景选择合适的脚本:
🐳 应用部署脚本
脚本名称 | 用途 | 适用环境 | 特点 |
---|---|---|---|
deploy.sh |
开发环境部署 | 开发/测试 | 快速部署,包含开发工具 |
deploy-prod.sh |
生产环境部署 | 生产环境 | 完整配置,安全优化 |
📖 文档部署脚本
脚本名称 | 用途 | 适用环境 | 特点 |
---|---|---|---|
build-docs-quick.sh |
快速文档构建 | 开发/生产 | 快速构建文档镜像 |
check-docs-status.sh |
文档状态检查 | 生产环境 | 检查文档服务状态 |
🚀 快速部署命令
# 开发环境部署
chmod +x deploy.sh
./deploy.sh
# 生产环境部署
chmod +x deploy-prod.sh
./deploy-prod.sh
# 文档快速构建
chmod +x build-docs-quick.sh
./build-docs-quick.sh
# 检查文档状态
chmod +x check-docs-status.sh
./check-docs-status.sh
生产环境优化
1. 性能优化
# 启用 Gzip 压缩
# 在 Nginx Proxy Manager 中启用
# 配置缓存策略
# 静态资源缓存 1 年
# API 响应缓存 5 分钟
# 数据库优化
# 连接池配置
# 索引优化
# 查询优化
2. 安全配置
# 防火墙设置
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
# SSL 证书自动续期
# 使用 Let's Encrypt 自动续期
# 定期备份
# 数据库备份
# 文件备份
# 配置备份
3. 监控和日志
# 日志轮转
# 使用 logrotate 管理日志文件
# 系统监控
# 使用 htop 监控系统资源
# 使用 docker stats 监控容器
# 应用监控
# 使用 PM2 监控 Node.js 进程
# 使用 Redis INFO 监控 Redis
备份和恢复
数据库备份
# 创建备份
docker-compose exec postgres pg_dump -U postgres study_tracker_prod > backup_$(date +%Y%m%d_%H%M%S).sql
# 恢复备份
docker-compose exec -T postgres psql -U postgres study_tracker_prod < backup_file.sql
文件备份
# 备份上传文件
tar -czf uploads_backup_$(date +%Y%m%d_%H%M%S).tar.gz uploads/
# 备份配置文件
tar -czf config_backup_$(date +%Y%m%d_%H%M%S).tar.gz .env docker-compose.prod.yml
📊 性能优化
- 缓存策略: Redis 缓存热点数据
- 数据库优化: 连接池配置、索引优化
- 静态资源: CDN 加速、资源压缩
- 移动端优化: 响应式设计、触摸优化
- 图片优化: 自动压缩、WebP 格式支持
- 代码分割: 按需加载 JavaScript 模块
🔐 JWT 密钥安全指南
⚠️ 重要安全提醒
JWT 密钥是系统安全的核心,必须使用强密钥并妥善保管:
🚨 安全要求
- 密钥长度: 至少 32 个字符,推荐 64 个字符以上
- 复杂度: 包含大小写字母、数字、特殊字符
- 唯一性: 每个环境使用不同的密钥
- 保密性: 绝对不要提交到版本控制系统
- 定期更换: 生产环境建议每 6-12 个月更换一次
🔧 安全生成方法
方法一:使用项目提供的脚本(推荐)
# 生成默认密钥(64 字符,OpenSSL 方法)
./scripts/generate-jwt-secrets.sh
# 生成 128 字符的超强密钥
./scripts/generate-jwt-secrets.sh -l 128
# 生成生产环境密钥
./scripts/generate-jwt-secrets.sh -o .env.production
# 验证现有密钥
./scripts/generate-jwt-secrets.sh -v
# 轮换现有密钥
./scripts/generate-jwt-secrets.sh -r
# 查看帮助
./scripts/generate-jwt-secrets.sh -h
方法二:使用 OpenSSL(手动)
# 生成 64 字符的强密钥
openssl rand -base64 64
# 生成 128 字符的超强密钥
openssl rand -base64 128
# 生成包含特殊字符的密钥
openssl rand -hex 64
方法三:使用 Node.js(手动)
# 使用 Node.js 生成密钥
node -e "console.log(require('crypto').randomBytes(64).toString('base64'))"
# 生成包含特殊字符的密钥
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
方法四:使用系统工具(手动)
# 使用 /dev/urandom(Linux/macOS)
head -c 64 /dev/urandom | base64
# 使用 PowerShell(Windows)
[System.Convert]::ToBase64String([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(64))
📝 密钥管理最佳实践
1. 环境分离
# 开发环境密钥(示例)
JWT_SECRET=dev-jwt-secret-2024-xyz123abc456def789ghi
JWT_REFRESH_SECRET=dev-refresh-secret-2024-xyz123abc456def789ghi
# 测试环境密钥(示例)
JWT_SECRET=test-jwt-secret-2024-xyz123abc456def789ghi
JWT_REFRESH_SECRET=test-refresh-secret-2024-xyz123abc456def789ghi
# 生产环境密钥(示例)
JWT_SECRET=prod-jwt-secret-2024-xyz123abc456def789ghi-very-long-and-secure
JWT_REFRESH_SECRET=prod-refresh-secret-2024-xyz123abc456def789ghi-very-long-and-secure
2. 密钥存储
# 本地开发:存储在 .env 文件中
echo "JWT_SECRET=$(openssl rand -base64 64)" >> .env
echo "JWT_REFRESH_SECRET=$(openssl rand -base64 64)" >> .env
# 生产环境:使用环境变量或密钥管理服务
export JWT_SECRET="your-production-jwt-secret"
export JWT_REFRESH_SECRET="your-production-refresh-secret"
# Docker 环境:使用 Docker secrets 或环境变量
docker run -e JWT_SECRET="your-secret" your-app
3. 密钥轮换
# 生成新密钥
NEW_JWT_SECRET=$(openssl rand -base64 64)
NEW_REFRESH_SECRET=$(openssl rand -base64 64)
# 更新环境变量
sed -i "s/JWT_SECRET=.*/JWT_SECRET=$NEW_JWT_SECRET/" .env
sed -i "s/JWT_REFRESH_SECRET=.*/JWT_REFRESH_SECRET=$NEW_REFRESH_SECRET/" .env
# 重启服务
docker-compose restart app
🔍 密钥验证
# 验证密钥长度
echo $JWT_SECRET | wc -c # 应该大于 32
# 验证密钥复杂度
echo $JWT_SECRET | grep -E "[A-Za-z0-9+/=]{32,}" # 应该匹配
# 检查是否包含默认值
echo $JWT_SECRET | grep -v "CHANGE_THIS" # 不应该包含默认值
🛡️ 安全检查清单
- [ ] 密钥长度至少 32 个字符
- [ ] 包含大小写字母、数字、特殊字符
- [ ] 不同环境使用不同密钥
- [ ] 密钥未提交到版本控制
- [ ] 生产环境密钥定期更换
- [ ] 密钥访问权限限制
- [ ] 密钥备份安全存储
🔒 安全特性
- 身份认证: JWT Token 认证
- 密码安全: bcrypt 加密存储
- XSS 防护: 输入验证和输出转义
- CSRF 防护: 令牌验证
- 速率限制: API 访问频率控制
- 安全头: Helmet 中间件
- SQL 注入防护: 参数化查询
- 文件上传安全: 类型验证、大小限制
📖 文档系统
项目包含完整的文档系统,使用 VitePress 构建:
文档结构
- API 文档: 详细的 API 接口说明
- 部署文档: 各种部署方式的详细指南
- 功能文档: 各功能模块的使用说明
- 开发文档: 开发环境搭建和代码规范
- 故障排除: 常见问题和解决方案
开发环境设置
# 克隆你的 fork
git clone https://github.com/laurawu0122/study-tracker.git
cd study-tracker
# 添加上游仓库
git remote add upstream https://github.com/original-owner/study-tracker.git
# 创建功能分支
git checkout -b feature/your-feature
# 开发完成后提交
git add .
git commit -m "feat: add your feature"
git push origin feature/your-feature
🆘 支持与帮助
常见问题
1. 端口被占用
# 查看端口占用
lsof -i :3001
lsof -i :5173
# 杀死进程
npm run kill-port
# 或者
pkill -f node
2. 数据库连接失败
# 检查 PostgreSQL 服务状态
sudo systemctl status postgresql
# 检查连接配置
cat .env | grep DB_
# 测试连接
psql -h localhost -U postgres -d study_tracker_dev
3. Redis 连接失败
# 检查 Redis 服务状态
sudo systemctl status redis
# 测试连接
redis-cli ping
# 检查配置
cat .env | grep REDIS_
4. Docker 相关问题
# 检查 Docker 服务状态
sudo systemctl status docker
# 查看容器状态
docker-compose ps
# 查看容器日志
docker-compose logs app
# 重新构建镜像
docker-compose build --no-cache
# 清理 Docker 资源
docker system prune -a
# 检查端口占用
netstat -tulpn | grep :3001
netstat -tulpn | grep :5173
# 检查数据卷
docker volume ls
docker volume inspect study-tracker_postgres_data
# 重置 Docker 环境
docker-compose down -v
docker system prune -a
./deploy.sh # 或 ./deploy-prod.sh
5. Nginx Proxy Manager 问题
# 检查 NPM 状态
docker-compose -f /opt/nginx-proxy-manager/docker-compose.yml ps
# 查看 NPM 日志
docker-compose -f /opt/nginx-proxy-manager/docker-compose.yml logs
# 重启 NPM
docker-compose -f /opt/nginx-proxy-manager/docker-compose.yml restart
故障排除工具
# 系统信息检查
npm run system:check
# 数据库连接测试
npm run db:test
# Redis 连接测试
npm run redis:test
# 端口占用检查
npm run port:check
# 安全配置检查
npm run security:check
# PWA 功能检查
npm run pwa:check
钉钉消息测试配置
如果钉钉消息测试提示通知还未配置,请按以下步骤操作:
- 启用钉钉通知:
docker-compose -f docker-compose.prod.yml exec app node -e "
const { db } = require('./database/db');
db('system_config').where('key', 'dingtalk_enabled').update({value: 'true'}).then(() => {
console.log('钉钉启用状态已更新为true');
});
"
- 重启应用容器:
docker-compose -f docker-compose.prod.yml restart
- 验证配置:
- 访问管理后台 → 钉钉配置管理
- 配置钉钉群机器人 Webhook URL
- 点击"测试连接"按钮
- 检查钉钉群中是否收到测试消息
💡 提示: 确保钉钉群机器人已正确配置,并且 Webhook URL 可以正常访问。
PWA 功能故障排除
1. Service Worker 未注册
症状: PWA 测试页面显示 Service Worker 未注册
解决方案:
# 检查 sw.js 文件是否存在
ls -la public/sw.js
# 检查文件权限
chmod 644 public/sw.js
# 清除浏览器缓存
# 在 Chrome DevTools → Application → Storage → Clear site data
2. Manifest 文件无法访问
症状: 测试页面显示 Manifest 文件无法访问
解决方案:
# 检查 manifest.json 文件
ls -la public/manifest.json
# 验证 JSON 格式
node -e "console.log(JSON.parse(require('fs').readFileSync('public/manifest.json', 'utf8')))"
# 检查服务器配置
# 确保静态文件正确提供服务
3. 安装提示不显示
症状: 浏览器地址栏没有显示安装图标
解决方案:
- 确保网站通过 HTTPS 访问
- 检查 manifest.json 中的
display
设置 - 验证
start_url
和scope
配置 - 确保有合适的应用图标
💡 提示: PWA 功能需要 HTTPS 环境,本地开发时可以使用 localhost。
🔄 更新和维护
系统更新
# 拉取最新代码
git pull origin main
# 更新依赖
npm install
# 运行数据库迁移
npm run db:migrate
# 重启服务
docker-compose restart app
定期维护
# 清理 Docker 镜像
docker system prune -a
# 清理日志文件
npm run log:clean
# 数据库优化
npm run db:optimize
# 备份数据
npm run backup:create
二、懒人配置文件
1、生产环境docker-compose.prod.yml
version: '2.3' # 指定docker-compose文件的版本
services:
postgres: # PostgreSQL数据库服务
image: postgres:15-alpine # 使用PostgreSQL15的轻量级Alpine版本镜像
container_name: study-tracker-postgres-prod # 容器名称
restart: unless-stopped # 当容器意外退出时自动重启,除非手动停止
environment: # 数据库相关环境变量
POSTGRES_DB: study_tracker_prod # 初始化创建的数据库名称
POSTGRES_USER: study_tracker # 数据库用户名
POSTGRES_PASSWORD: "${DB_PASSWORD:-StudyTracker2024!}" # 数据库密码,支持外部环境变量覆盖
volumes:
- postgres_data:/var/lib/postgresql/data # 数据持久化卷,防止容器重启数据丢失
ports:
- "5432:5432" # 映射主机端口5432到容器PostgreSQ 默认端口
networks:
- study-tracker-network # 加入study-tracker网络,供其他容器访问
redis: # Redis 缓存服务
image: redis:7-alpine # 使用Redis7的轻量级Alpine版本
container_name: study-tracker-redis-prod # 容器名称
restart: unless-stopped # 自动重启策略
command: redis-server --bind 0.0.0.0 --appendonly yes --requirepass "${REDIS_PASSWORD:-Redis2024!}" --maxmemory 256mb --maxmemory-policy allkeys-lru
# 自定义 Redis 启动命令:
# --bind 0.0.0.0 允许所有地址访问
# --appendonly yes 开启持久化
# --requirepass 设置访问密码
# --maxmemory 256mb 限制最大内存
# --maxmemory-policy allkeys-lru 内存满后采用LRU淘汰策略
volumes:
- redis_data:/data # 数据持久化卷
ports:
- "6379:6379" # 映射Redis默认端口
networks:
- study-tracker-network # 加入同一网络
app: # Node.js 主应用服务
build:
context: . # 使用当前目录作为构建上下文
dockerfile: Dockerfile # 指定Dockerfile文件
args:
- NODE_ENV=production # 构建参数,指定生产环境
labels: # 自定义标签,用于标识镜像信息
- "com.study-tracker.version=2.0.0"
- "com.study-tracker.component=app"
image: study-tracker-app:latest # 构建后生成的镜像名称
container_name: study-tracker-app-prod # 容器名称
restart: unless-stopped # 自动重启策略
environment: # 应用运行所需环境变量
NODE_ENV: production # 运行环境
PORT: 3001 # 应用服务端口
HOST: 0.0.0.0 # 绑定所有网络接口
DB_HOST: postgres # 数据库主机名,与服务名一致
DB_PORT: 5432 # 数据库端口
DB_USER: study_tracker # 数据库用户名
DB_PASSWORD: ${DB_PASSWORD:-StudyTracker2024!} # 数据库密码,如果环境配置里面没有自己设置密码,默认的密码为StudyTracker2024!
DB_NAME: study_tracker_prod # 数据库名
REDIS_HOST: redis # Redis主机名
REDIS_PORT: 6379 # Redis端口
REDIS_PASSWORD: ${REDIS_PASSWORD:-Redis2024!} # Redis密码
JWT_SECRET: ${JWT_SECRET:-default_jwt_secret_key} # JWT签名秘钥
JWT_REFRESH_SECRET: ${JWT_REFRESH_SECRET:-default_jwt_refresh_secret_key} # JWT刷新秘钥
ENABLE_HTTPS: "false" # 是否启用HTTPS
TRUST_PROXY: "true" # 是否信任代理头,用于部署在反向代理后
SESSION_SECURE_COOKIES: "false" # 是否启用安全 Cookie
CORS_ORIGIN: https://yourdomain.com # 允许跨域访问的前端域名
DOCS_CORS_ORIGIN: https://docs.yourdomain.com # 允许跨域访问的文档域名
LOG_LEVEL: info # 日志级别
LOG_SECURITY_EVENTS: "true" # 是否记录安全事件日志
RATE_LIMIT_WINDOW_MS: 900000 # 速率限制时间窗口(毫秒)
RATE_LIMIT_MAX_REQUESTS: 1000 # 每个窗口最大请求数
MAX_LOGIN_ATTEMPTS: 5 # 最大登录失败次数
LOCKOUT_DURATION_MINUTES: 15 # 锁定持续时间(分钟)
DOMAIN: https://yourdomain.com # 主域名
DOCS_DOMAIN: https://docs.yourdomain.com # 文档域名
SMTP_USER: ${SMTP_USER:-} # 邮件服务用户名
SMTP_PASS: ${SMTP_PASS:-} # 邮件服务密码
SMTP_HOST: ${SMTP_HOST:-} # 邮件服务器地址
SMTP_PORT: ${SMTP_PORT:-} # 邮件服务器端口
SMTP_FROM_NAME: ${SMTP_FROM_NAME:-学习项目追踪系统} # 邮件发件人名称
SMTP_FROM_EMAIL: ${SMTP_FROM_EMAIL:-} # 邮件发件人邮箱
DINGTALK_WEBHOOK_URL: ${DINGTALK_WEBHOOK_URL:-} # 钉钉通知 Webhook 地址
DINGTALK_SECRET: ${DINGTALK_SECRET:-} # 钉钉加签秘钥
DINGTALK_KEYWORD: ${DINGTALK_KEYWORD:-学习追踪} # 钉钉关键字
DINGTALK_ENABLED: ${DINGTALK_ENABLED:-false} # 是否启用钉钉通知
volumes:
- app_logs:/app/logs # 挂载日志目录
- app_uploads:/app/uploads # 挂载文件上传目录
ports:
- "3001:3001" # 宿主机端口3001映射到容器端口
depends_on:
- postgres # 启动顺序依赖数据库
- redis # 启动顺序依赖Redis
networks:
- study-tracker-network # 加入同一网络
docs: # 文档站点服务
build:
context: . # 构建上下文
dockerfile: Dockerfile.docs # 指定文档Dockerfile
args:
- NODE_ENV=production # 构建参数:生产环境
labels:
- "com.study-tracker.version=2.0.0"
- "com.study-tracker.component=docs"
image: study-tracker-docs:latest # 构建出的文档镜像
container_name: study-tracker-docs-prod # 容器名称
restart: unless-stopped # 自动重启策略
ports:
- "5173:5173" # 宿主机5173端口映射到文档服务
depends_on:
- app # 文档站点依赖主应用启动
networks:
- study-tracker-network # 加入同一网络
volumes:
postgres_data: # PostgreSQL数据持久化卷
redis_data: # Redis数据持久化卷
app_logs: # 应用日志存储卷
app_uploads: # 应用上传文件存储卷
networks:
study-tracker-network:
driver: bridge # 使用默认桥接网络驱动
2、.env环境配置文件
# ========================================
# Study Tracker 环境变量配置
# ========================================
# 应用配置
NODE_ENV=production
PORT=3001
HOST=0.0.0.0
# HOST 配置说明:
# - localhost: 仅本机可访问
# - 0.0.0.0: 允许局域网访问(生产环境推荐)
# - 具体IP地址: 如 192.168.1.200
# HTTPS配置
ENABLE_HTTPS=false
# ENABLE_HTTPS 配置说明:
# - true: 启用HTTPS(需要证书文件,推荐)
# - false: 使用HTTP(仅限本机开发)
# 注意:局域网访问必须使用HTTPS,建议设置为true
# JWT配置(必需)
# 使用以下命令生成两次安全的JWT密钥:
# openssl rand -base64 64
JWT_SECRET=
JWT_REFRESH_SECRET=
# JWT过期时间配置
JWT_ACCESS_EXPIRES=15m
JWT_REFRESH_EXPIRES=7d
# 默认管理员密码(可选)
# 如果不设置,系统使用默认密码:ChangeMe123!
DEFAULT_ADMIN_PASSWORD=yourpassword
# 邮件配置(可选)
EMAIL_HOST=smtp.example.com
EMAIL_PORT=587
EMAIL_USER=xx@example.com
EMAIL_PASS=通常为邮箱授权码
# 安全配置
TRUST_PROXY=true
# 速率限制配置
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=1000
RATE_LIMIT_ADMIN_MAX_REQUESTS=2000
# 会话安全配置
SESSION_SECURE_COOKIES=true
SESSION_HTTP_ONLY=true
SESSION_SAME_SITE=strict
# 密码策略配置
PASSWORD_MIN_LENGTH=8
PASSWORD_REQUIRE_UPPERCASE=true
PASSWORD_REQUIRE_LOWERCASE=true
PASSWORD_REQUIRE_NUMBERS=true
PASSWORD_REQUIRE_SPECIAL_CHARS=true
# 账户锁定配置
MAX_LOGIN_ATTEMPTS=5
LOCKOUT_DURATION_MINUTES=15
# PostgreSQL数据库配置(必需)
DB_HOST=postgres
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=yourpassword
DB_NAME=study_tracker_prod
# 数据库连接池配置(可选)
DB_POOL_MIN=2
DB_POOL_MAX=10
DB_ACQUIRE_TIMEOUT=30000
DB_CREATE_TIMEOUT=30000
DB_IDLE_TIMEOUT=30000
# 文件上传安全配置
MAX_FILE_SIZE=5242880
ALLOWED_FILE_TYPES=image/jpeg,image/png,image/gif,application/pdf
# CORS配置
# 主应用 CORS 配置(端口 3001)
CORS_ORIGIN=https://yourdomain.com
CORS_CREDENTIALS=true
# 文档系统 CORS 配置(端口 5173)
# 注意:文档系统是静态站点,通常不需要 CORS 配置
# 但如果文档系统需要与主应用通信,请配置以下参数
DOCS_CORS_ORIGIN=https://docs.yourdomain.com
DOCS_CORS_CREDENTIALS=true
# 多域名 CORS 配置(生产环境)
# 如果主应用和文档系统使用不同域名,请配置:
# CORS_ORIGIN=https://yourdomain.com,https://docs.yourdomain.com
# 或者使用通配符(不推荐用于生产环境):
# CORS_ORIGIN=https://*.yourdomain.com
# 域名配置(生产环境)
# 主应用域名,用于生产环境
DOMAIN=yourdomain.com
# 文档站点域名,如果不设置则使用主域名
# 例如:docs.yourdomain.com 或 yourdomain.com/docs
DOCS_DOMAIN=https://docs.yourdomain.com
# SMTP邮件配置(生产环境)
# 邮件服务器配置,用于发送验证码和通知
SMTP_USER=xx@example.com
SMTP_PASS=通常为邮箱授权码
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_FROM_NAME=学习项目追踪系统
SMTP_FROM_EMAIL=xx@example.com
# 日志配置
LOG_LEVEL=error
LOG_SECURITY_EVENTS=true
# 日志级别: error, warn, info, debug
# Redis 配置(建议补充)
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=yourpassword
REDIS_DB=0
# 钉钉群机器人配置(可选)
# 用于积分兑换实时通知推送
# 安全提醒:请妥善保管签名密钥,不要泄露给他人
DINGTALK_WEBHOOK_URL=
DINGTALK_SECRET=
DINGTALK_KEYWORD=
DINGTALK_ENABLED=true
# 演示数据密码配置(可选)
# 如果不设置,系统使用默认密码:ChangeMe123!
DEMO_USER_PASSWORD=ChangeMe123!
DEMO_DATA_PASSWORD=ChangeMe123!
# ========================================
# 生产环境配置示例
# ========================================
# NODE_ENV=production
# PORT=3001
# HOST=0.0.0.0
# TRUST_PROXY=true
# SESSION_SECURE_COOKIES=true
# CORS_ORIGIN=https://yourdomain.com
# DOCS_CORS_ORIGIN=https://docs.yourdomain.com
# DB_NAME=study_tracker_prod
# LOG_LEVEL=warn
三、特别说明
本项目目前处于私有状态,仅供内部测试和使用。计划于2025年10月份正式转为公共仓库。