Docker一键部署Study-Tracker学习追踪系统

💡
本项目为自主研发的学习追踪系统,主要面向学生的日常学习管理场景。通过数据化手段提升学习效率与习惯养成。系统采用 Node.js + Express 架构,后端基于 PostgreSQL 构建核心数据模型,支持实时的学习数据统计分析及可视化呈现。前端使用 Tailwind CSS、Alpine.js 与 Chart.js 提供响应式界面,并集成 PWA 特性,实现跨平台快速访问。功能模块涵盖学习项目管理、会话记录、成就体系、积分兑换及实时通知等,可为家长和学生提供全面的学习行为追踪与激励反馈机制。
点击查看功能说明

🌟 项目特色

  • 🎯 智能学习追踪 - 记录学习时间、进度和目标完成情况
  • 📊 数据可视化 - 丰富的图表和统计分析功能
  • 🏆 成就系统 - 激励用户持续学习的积分和成就机制
  • 📱 移动端优化 - 完美适配移动平板设备
  • 📱 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. 创建钉钉群机器人

  1. 在钉钉群中点击"群设置" → "智能群助手" → "添加机器人"
  2. 选择"自定义"机器人
  3. 设置机器人名称(如:StudyTracker)
  4. 获取 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 功能:

方法二:Docker 一键部署(推荐)

适用于: 生产环境、快速部署、容器化运行

🐳 Docker 开发环境部署

重要说明:

  • 🐳 Docker 部署需要 .env 文件 - 用于存储敏感配置(密码、密钥)
  • 📝 部署脚本会自动创建 .env 文件模板,用户只需编辑配置
  • 🔧 环境变量 通过 .env 文件传递给 Docker Compose
  • 🔒 安全配置 - 数据库密码、Redis 密码、JWT 密钥等敏感信息

部署流程:

  1. 首次运行 - 脚本会自动从 env.example 创建 .env 文件
  2. 配置密码 - 编辑 .env 文件,设置数据库和 Redis 密码
  3. 重新运行 - 再次执行 ./deploy-prod.sh 完成部署
1. 克隆项目
git clone <your-repository-url>
cd study-tracker
2. 一键部署
# 给部署脚本执行权限
chmod +x deploy.sh

# 执行一键部署
./deploy.sh

部署脚本会自动:

  • ✅ 检查系统环境
  • ✅ 安装 Docker(如果未安装)
  • ✅ 创建必要的目录和文件
  • ✅ 生成环境配置文件
  • ✅ 启动所有服务
  • ✅ 验证服务状态
3. 访问系统
4. 测试 PWA 功能

访问以下页面测试 PWA 功能:

🐳 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 配置主应用代理
  1. 访问 NPM 管理界面:http://your-server-ip:81
  2. 默认登录信息:
    • Email: admin@example.com
    • Password: changeme
  3. 添加代理主机:
    • Domain Names: yourdomain.com
    • Scheme: http
    • Forward Hostname/IP: localhost
    • Forward Port: 3001
    • 启用 SSL: 选择 Let's Encrypt
    • 启用 Force SSL: 是
    • 启用 HTTP/2 Support: 是
5.3 配置文档系统代理
  1. 添加第二个代理主机:
    • Domain Names: docs.yourdomain.com
    • Scheme: http
    • Forward Hostname/IP: localhost
    • Forward Port: 5173
    • 启用 SSL: 选择 Let's Encrypt
    • 启用 Force SSL: 是
    • 启用 HTTP/2 Support: 是
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 部署注意事项

重要提醒
  1. 端口配置

    • 主应用端口:3001
    • 文档系统端口:5173
    • 数据库端口:5432(仅本地访问)
    • Redis 端口:6379(仅本地访问)
  2. 数据持久化

    • PostgreSQL 数据存储在 ./data/postgres 目录
    • Redis 数据存储在 ./data/redis 目录
    • 上传文件存储在 ./uploads 目录
    • 日志文件存储在 ./logs 目录
  3. CORS 配置

    • 主应用 CORS:CORS_ORIGIN=https://yourdomain.com
    • 文档系统 CORS:DOCS_CORS_ORIGIN=https://docs.yourdomain.com
    • 多域名配置:CORS_ORIGIN=https://yourdomain.com,https://docs.yourdomain.com
  4. 安全配置

    • 生产环境启用 HTTPS
    • 使用强密码和 JWT 密钥
    • 启用安全 Cookie
    • 配置防火墙规则
  5. 性能优化

    • 启用 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 密钥是系统安全的核心,必须使用强密钥并妥善保管:

🚨 安全要求

  1. 密钥长度: 至少 32 个字符,推荐 64 个字符以上
  2. 复杂度: 包含大小写字母、数字、特殊字符
  3. 唯一性: 每个环境使用不同的密钥
  4. 保密性: 绝对不要提交到版本控制系统
  5. 定期更换: 生产环境建议每 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

钉钉消息测试配置

如果钉钉消息测试提示通知还未配置,请按以下步骤操作:

  1. 启用钉钉通知
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');
});
"
  1. 重启应用容器
docker-compose -f docker-compose.prod.yml restart
  1. 验证配置
  • 访问管理后台 → 钉钉配置管理
  • 配置钉钉群机器人 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_urlscope 配置
  • 确保有合适的应用图标

💡 提示: 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月份正式转为公共仓库。