码巢引擎2026年开发文档
00-开发规范
后端规范
README
后端开发手册
前端规范
README
TypeScript最佳实践
前端布局规范
前端页面模板
前端颜色与组件规范
核心规范
组件配置手册
问题排查指南
页面模板
最佳实践
README
bp-20260223-m7ps
图片上传优化总结
BUG自动记录系统使用指南
README
TYPE_SAFETY_GUIDE
常见BUG知识库
常见BUG知识库
开发前检查清单
开发安全规范
开发规范-完整版-含FutureBirdAadminAi部署
数据模型字典
文档分类规范
文档标准化规范
文档模板-基础版
文档模板-技术版
类型安全快速参考卡
类型安全规范体系
规范更新指南
过期文档清理机制
错误处理规范
错误预防指南
常见BUG知识库
常见BUG知识库
01-快速开始
Gitee快速开始
README
协作快速开始
快速开始
质量保证快速开始
02-部署指南
Docker更新指南
Docker部署
FutureBirdAadminAi部署指南
FutureBirdAadminAi部署问题分析
README
发布指南
宝塔Docker部署教程
宝塔PM2部署教程
宝塔图形化部署教程
快速发布指南
数据库和依赖变更处理指南
构建和发布
构建标准
构建检查清单
生产部署快速开始
生产部署方案
生产部署标准
生产部署检查清单
程序备份性能
自动修复和发布指南
自动化发布命令使用指南
部署快速开始
部署指南
项目更新部署指南
03-开发指南
Git凭据配置
Git推送规则
Git自动配置
README
全局样式
协作设置
定时任务
开发指南
开发流程
开发环境标准
技术改进
贡献指南
项目目录树
项目目录结构
04-API文档
API接口文档
README
hr-api
企业API
05-数据库
DATABASE_SCHEMA
README
分区指南
数据库字典
数据持久化
数据模型统一
数据迁移
06-架构设计
RBAC-PERMISSIONS
README
SaaS客户引导流程设计
companyId统一规范
employee-permission-system-design
enterprise-data-linkage
仓库实现总结
仓库模式
企业管理端员工权限系统分析
前端架构
前端重构总结
员工权限系统评估报告
员工管理菜单重构方案
权限系统混乱问题分析
架构优化计划
架构使用指南
架构结构
架构结构
状态管理
用户身份管理体系
系统架构
面试管理模块重构规划
项目技术栈
07-测试质量
README
测试修复标准
测试报告
质量保证系统
08-版本管理
CHANGELOG
README
VERSION_RULES
09-配置指南
README
SMTP配置指南
主题切换指南
渠道配置指南
环境变量指南
环境隔离
12-项目记忆
README
知识库导入指南
记忆系统指南
13-迁移指南
README
备份迁移指南
管理员迁移指南
迁移快速开始
17-其他
README
压缩摘要
18-开放平台
01-架构设计
02-API接口设计
03-安全机制
04-前端设计
05-数据库设计
开放平台API指南
开放平台API说明
19-智能进化
AI执行规则
AI进化机制
README
自动化实现总览
黄金规则
40-操作教程
README
微信公众号域名配置指南
微信本地开发调试指南
44-技能文件
alipay-payment-integration
references
checklist
SKILL
audio
python
README
typescript
README
SKILL
database
python
README
typescript
README
SKILL
design-style-thinking
SKILL
doctor
references
sql-patterns
SKILL
document-generation
python
README
SKILL
email
SKILL
embedding
python
README
typescript
README
SKILL
expo-advanced
references
audio-record-play
file-upload
masonry-layout
save-to-gallery
top-tab-navigation
SKILL
feishu-base
SKILL
feishu-message
SKILL
fetch-url
python
README
typescript
README
SKILL
frontend-design
LICENSE
SKILL
FutureBird-coding-web-performance-best-practice
SKILL
general-dev-preview
references
web-preview
SKILL
image-generation
python
README
typescript
README
SKILL
knowledge
references
python
README
typescript
README
cli
SKILL
llm
python
README
typescript
README
SKILL
miniapp-upload-asr
SKILL
pptx-generation
python
README
SKILL
project-memory-loader
scripts
project_memory_loader
SKILL
repair
scripts
merge-commit-map
SKILL
shadcn-web-base-theme
assets
colors
amber
artistic-green
bento-blue
blue
cyan
emerald
fuchsia
gray
green
indigo
lime
low-pink
neutral
orange
purple
red
retro-brown
rose
sky
supbase-green
teal
tech-purple
vintage-grey
violet
yellow
fonts
business
classic
playful
radius
2xl
2xs
lg
md
none
sm
xl
xs
shadow
artistic
bento
cool
retro
superbase
tech
tool
vintage
default
references
colors
fonts
quick
radius
shadows
scripts
theme
SKILL
package
skill-creator-coze
scripts
init_skill
quick_validate
SKILL
storage
python
README
typescript
README
SKILL
supabase
assets
supabase-client
supabase-client
references
_future
asset-supabase-browser
asset-supabase-config-inject
asset-supabase-config-route
python-auth
python-realtime
python-storage
typescript-auth
typescript-realtime
typescript-storage
typescript-supabase-browser
typescript-supabase-config-inject
typescript-supabase-config-route
python
README
database
edge-functions
orm-model-guide
supabase_client
typescript
README
database
drizzle-schema-guide
edge-functions
supabase-client
cli
rls
SKILL
supabase-auth
references
typescript
supabase-browser
supabase-config-inject
supabase-config-route
auth-config
verify-session
SKILL
ui-design-ref
reference
3D黏土风
克莱因蓝高定风
暗黑科技风
杂志风
极光柔和
柔和卡片
玻璃拟态
纯白极简风
自然有机
SKILL
ui-ux-pro-max
scripts
core
design_system
search
SKILL
vercel-composition-patterns
rules
architecture-avoid-boolean-props
architecture-compound-components
patterns-children-over-render-props
patterns-explicit-variants
react19-no-forwardref
state-context-interface
state-decouple-implementation
state-lift-state
AGENTS
SKILL
vercel-react-best-practices
rules
advanced-event-handler-refs
advanced-init-once
advanced-use-latest
async-api-routes
async-defer-await
async-dependencies
async-parallel
async-suspense-boundaries
bundle-barrel-imports
bundle-conditional
bundle-defer-third-party
bundle-dynamic-imports
bundle-preload
client-event-listeners
client-localstorage-schema
client-passive-event-listeners
client-swr-dedup
js-batch-dom-css
js-cache-function-results
js-cache-property-access
js-cache-storage
js-combine-iterations
js-early-exit
js-hoist-regexp
js-index-maps
js-length-check-first
js-min-max-loop
js-set-map-lookups
js-tosorted-immutable
rendering-activity
rendering-animate-svg-wrapper
rendering-conditional-render
rendering-content-visibility
rendering-hoist-jsx
rendering-hydration-no-flicker
rendering-hydration-suppress-warning
rendering-svg-precision
rendering-usetransition-loading
rerender-defer-reads
rerender-dependencies
rerender-derived-state-no-effect
rerender-derived-state
rerender-functional-setstate
rerender-lazy-state-init
rerender-memo-with-default-value
rerender-memo
rerender-move-effect-to-event
rerender-simple-expression-in-memo
rerender-transitions
rerender-use-ref-transient-values
server-auth-actions
server-cache-lru
server-cache-react
server-dedup-props
server-parallel-fetching
server-serialization
AGENTS
SKILL
video-edit
python
README
typescript
README
SKILL
video-generation
python
README
typescript
README
SKILL
volcano-ark
SKILL
web-design-guidelines
SKILL
web-search
python
README
typescript
README
SKILL
webrtc-best-practice
SKILL
websocket-guide
references
nextjs
nodejs
SKILL
wechat-bot
SKILL
wechat-official-account
SKILL
README
README
未来鸟:企业数字化转型奔腾的力量!
-
+
首页
项目更新部署指南
# 项目更新部署指南 > 本指南详细说明如何安全地更新项目,特别是涉及数据库更新时的处理流程。 ## 📋 目录 1. [更新类型说明](#1-更新类型说明) 2. [更新前准备](#2-更新前准备) 3. [常规代码更新](#3-常规代码更新) 4. [数据库更新流程](#4-数据库更新流程) 5. [回滚方案](#5-回滚方案) 6. [更新后验证](#6-更新后验证) 7. [常见问题](#7-常见问题) --- ## 1. 更新类型说明 ### 1.1 更新类型分类 | 类型 | 说明 | 风险等级 | 处理方式 | |------|------|----------|----------| | **纯前端更新** | 只修改 UI、样式、前端逻辑 | ⭐ 低 | 直接部署,无需停机 | | **纯后端代码更新** | 修改 API 逻辑,不涉及数据库 | ⭐⭐ 中 | 短暂停机(秒级) | | **数据库结构更新** | 新增表、新增字段、修改字段类型 | ⭐⭐⭐ 高 | 需要迁移脚本,可能需要停机 | | **数据库数据迁移** | 数据结构调整、数据清洗 | ⭐⭐⭐⭐ 极高 | 需要备份、停机维护 | | **重大版本升级** | 大量结构变化、不兼容更新 | ⭐⭐⭐⭐⭐ 最高 | 需要完整备份、维护窗口 | ### 1.2 如何判断更新类型 ```bash # 拉取最新代码后,检查变更文件 git diff --name-only HEAD~1 HEAD # 示例输出: # src/app/login/page.tsx → 前端文件 # src/app/api/users/route.ts → 后端 API # src/db/schema.ts → 数据库结构 ⚠️ 需要特别关注 # drizzle/0001_add_user_table.sql → 数据库迁移文件 ⚠️ 需要特别关注 ``` **关键信号**:以下文件变更意味着需要数据库更新 ``` src/db/schema.ts # 数据库结构定义 src/storage/database/**/*.ts # 数据库相关代码 drizzle/ # 迁移脚本目录 migrations/ # 迁移脚本目录 ``` --- ## 2. 更新前准备 ### 2.1 更新前检查清单 ```bash # 创建更新前检查脚本 cat > /www/wwwroot/hrm-app/scripts/pre-update-check.sh << 'EOF' #!/bin/bash echo "========== 更新前检查 ==========" echo "" # 1. 检查当前版本 echo "1. 当前 Git 版本:" cd /www/wwwroot/hrm-app git log -1 --oneline echo "" # 2. 检查应用状态 echo "2. PM2 应用状态:" pm2 list | grep hrm-app echo "" # 3. 检查磁盘空间 echo "3. 磁盘空间:" df -h /www/wwwroot/hrm-app echo "" # 4. 检查数据库连接 echo "4. 数据库连接:" pg_isready -h 127.0.0.1 -p 5432 echo "" # 5. 检查内存 echo "5. 内存使用:" free -h echo "" echo "========== 检查完成 ==========" EOF chmod +x /www/wwwroot/hrm-app/scripts/pre-update-check.sh # 执行检查 /www/wwwroot/hrm-app/scripts/pre-update-check.sh ``` ### 2.2 完整备份(重要!) #### 2.2.1 创建备份脚本 ```bash # 创建备份脚本 cat > /www/wwwroot/hrm-app/scripts/backup.sh << 'EOF' #!/bin/bash # 配置 BACKUP_DIR="/www/backup/hrm-app" DATE=$(date +%Y%m%d_%H%M%S) PROJECT_DIR="/www/wwwroot/hrm-app" # 数据库配置(从 .env 读取) source $PROJECT_DIR/.env 2>/dev/null || true # 创建备份目录 mkdir -p $BACKUP_DIR/$DATE echo "========== 开始备份 ==========" echo "备份时间: $DATE" echo "备份目录: $BACKUP_DIR/$DATE" echo "" # 1. 备份数据库 echo "1. 备份数据库..." DB_HOST=$(echo $DATABASE_URL | sed -n 's/.*@\([^:]*\):.*/\1/p') DB_PORT=$(echo $DATABASE_URL | sed -n 's/.*:\([0-9]*\)\/.*/\1/p') DB_NAME=$(echo $DATABASE_URL | sed -n 's/.*\/\([^?]*\).*/\1/p') DB_USER=$(echo $DATABASE_URL | sed -n 's/.*\/\/\([^:]*\):.*/\1/p') pg_dump -h $DB_HOST -p $DB_PORT -U $DB_USER $DB_NAME > $BACKUP_DIR/$DATE/database.sql 2>/dev/null if [ $? -eq 0 ]; then # 压缩数据库备份 gzip $BACKUP_DIR/$DATE/database.sql echo " 数据库备份完成: database.sql.gz" else echo " 数据库备份失败!" exit 1 fi # 2. 备份代码 echo "2. 备份代码..." tar -czf $BACKUP_DIR/$DATE/code.tar.gz \ --exclude='node_modules' \ --exclude='.next' \ --exclude='.git' \ -C $PROJECT_DIR . echo " 代码备份完成: code.tar.gz" # 3. 备份环境变量 echo "3. 备份环境变量..." cp $PROJECT_DIR/.env $BACKUP_DIR/$DATE/.env echo " 环境变量备份完成: .env" # 4. 备份上传文件(如果有) echo "4. 备份上传文件..." if [ -d "$PROJECT_DIR/public/uploads" ]; then tar -czf $BACKUP_DIR/$DATE/uploads.tar.gz -C $PROJECT_DIR/public uploads echo " 上传文件备份完成: uploads.tar.gz" else echo " 无上传文件目录,跳过" fi # 5. 记录版本信息 echo "5. 记录版本信息..." cd $PROJECT_DIR git log -1 > $BACKUP_DIR/$DATE/git-info.txt git diff > $BACKUP_DIR/$DATE/git-diff.txt echo " 版本信息记录完成" # 6. 计算备份大小 echo "" echo "========== 备份完成 ==========" BACKUP_SIZE=$(du -sh $BACKUP_DIR/$DATE | cut -f1) echo "备份大小: $BACKUP_SIZE" echo "备份路径: $BACKUP_DIR/$DATE" # 7. 清理旧备份(保留最近 7 天) echo "" echo "清理 7 天前的旧备份..." find $BACKUP_DIR -type d -name "20*" -mtime +7 -exec rm -rf {} \; 2>/dev/null echo "清理完成" EOF chmod +x /www/wwwroot/hrm-app/scripts/backup.sh # 创建备份目录 mkdir -p /www/backup/hrm-app ``` #### 2.2.2 执行备份 ```bash # 执行备份 /www/wwwroot/hrm-app/scripts/backup.sh # 输出示例: # ========== 开始备份 ========== # 备份时间: 20260517_143000 # 备份目录: /www/backup/hrm-app/20260517_143000 # # 1. 备份数据库... # 数据库备份完成: database.sql.gz # 2. 备份代码... # 代码备份完成: code.tar.gz # 3. 备份环境变量... # 环境变量备份完成: .env # ... # ========== 备份完成 ========== ``` ### 2.3 通知用户(可选) 如果更新需要停机,建议提前通知用户: ```bash # 创建维护页面 cat > /www/wwwroot/hrm-app/public/maintenance.html << 'EOF' <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>系统维护中</title> <style> body { font-family: system-ui; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; background: #f5f5f5; } .container { text-align: center; padding: 40px; background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } h1 { color: #07C160; margin-bottom: 10px; } p { color: #666; } </style> </head> <body> <div class="container"> <h1>🔧 系统维护中</h1> <p>系统正在进行升级维护,请稍后再试</p> <p>预计恢复时间:10-15 分钟</p> </div> </body> </html> EOF # Nginx 配置维护模式(更新时启用) # 在 Nginx 配置中添加: # location / { # try_files /maintenance.html =503; # } ``` --- ## 3. 常规代码更新 ### 3.1 纯前端/后端更新(无数据库变更) ```bash #!/bin/bash # 文件: scripts/update-simple.sh PROJECT_DIR="/www/wwwroot/hrm-app" cd $PROJECT_DIR echo "========== 开始更新 ==========" # 1. 拉取最新代码 echo "1. 拉取最新代码..." git fetch origin git pull origin main # 或指定分支:git pull origin master # 2. 安装新依赖 echo "2. 安装依赖..." pnpm install # 3. 构建项目 echo "3. 构建项目..." pnpm build # 4. 重启应用 echo "4. 重启应用..." pm2 restart hrm-app # 5. 等待启动 echo "5. 等待应用启动..." sleep 5 # 6. 检查状态 echo "6. 检查应用状态..." pm2 list | grep hrm-app echo "========== 更新完成 ==========" ``` ### 3.2 一键更新命令 ```bash # 快速更新(适合低风险更新) cd /www/wwwroot/hrm-app && git pull && pnpm install && pnpm build && pm2 restart hrm-app ``` --- ## 4. 数据库更新流程 ### 4.1 数据库更新分类 | 更新类型 | 说明 | 示例 | 处理方式 | |----------|------|------|----------| | **新增表** | 添加新数据表 | `CREATE TABLE users (...)` | 风险低,直接执行 | | **新增字段** | 添加新列 | `ALTER TABLE users ADD COLUMN phone VARCHAR(20)` | 风险低,直接执行 | | **新增索引** | 添加索引 | `CREATE INDEX idx_phone ON users(phone)` | 可能锁表,建议低峰执行 | | **修改字段类型** | 改变列类型 | `ALTER TABLE users ALTER COLUMN age TYPE BIGINT` | ⚠️ 可能丢失数据 | | **删除字段** | 删除列 | `ALTER TABLE users DROP COLUMN old_field` | ⚠️ 数据丢失 | | **删除表** | 删除表 | `DROP TABLE old_table` | ⚠️ 数据丢失 | | **数据迁移** | 修改已有数据 | `UPDATE users SET status = 'active' WHERE ...` | ⚠️ 需要事务处理 | ### 4.2 使用 Drizzle ORM 迁移(推荐) 本项目使用 Drizzle ORM,数据库迁移有两种方式: #### 方式 A:推送迁移(自动同步 schema) ```bash cd /www/wwwroot/hrm-app # 生成迁移文件 pnpm drizzle-kit generate # 执行迁移 pnpm drizzle-kit push # 或者直接推送(跳过生成) pnpm drizzle-kit push ``` **⚠️ 注意**:`drizzle-kit push` 会直接修改数据库结构,建议先在测试环境验证! #### 方式 B:手动迁移(更安全) ```bash # 1. 生成迁移文件 pnpm drizzle-kit generate # 2. 查看生成的 SQL cat drizzle/*.sql # 3. 在执行前备份数据库! /www/wwwroot/hrm-app/scripts/backup.sh # 4. 执行迁移 pnpm drizzle-kit migrate # 或者手动执行 SQL(更可控) psql -h 127.0.0.1 -U hrm_user -d hrm_db -f drizzle/0001_xxx.sql ``` ### 4.3 完整数据库更新流程 ```bash #!/bin/bash # 文件: scripts/update-with-db.sh PROJECT_DIR="/www/wwwroot/hrm-app" BACKUP_DIR="/www/backup/hrm-app" DATE=$(date +%Y%m%d_%H%M%S) cd $PROJECT_DIR echo "========== 数据库更新流程 ==========" echo "" # Step 1: 备份(必须!) echo "Step 1: 备份数据库..." /www/wwwroot/hrm-app/scripts/backup.sh if [ $? -ne 0 ]; then echo "❌ 备份失败,停止更新!" exit 1 fi echo "✅ 备份完成" echo "" # Step 2: 拉取代码 echo "Step 2: 拉取最新代码..." git fetch origin BEFORE_COMMIT=$(git rev-parse HEAD) git pull origin main AFTER_COMMIT=$(git rev-parse HEAD) if [ "$BEFORE_COMMIT" = "$AFTER_COMMIT" ]; then echo "没有新代码,跳过更新" exit 0 fi echo "✅ 代码更新完成: $BEFORE_COMMIT → $AFTER_COMMIT" echo "" # Step 3: 检查是否有数据库变更 echo "Step 3: 检查数据库变更..." DB_CHANGED=0 # 检查 schema 文件是否变更 if git diff $BEFORE_COMMIT $AFTER_COMMIT --name-only | grep -q "schema.ts"; then echo "⚠️ 检测到 schema.ts 变更" DB_CHANGED=1 fi # 检查迁移目录是否有新文件 NEW_MIGRATIONS=$(git diff $BEFORE_COMMIT $AFTER_COMMIT --name-only | grep "drizzle/.*\.sql" | wc -l) if [ $NEW_MIGRATIONS -gt 0 ]; then echo "⚠️ 检测到 $NEW_MIGRATIONS 个新迁移文件" DB_CHANGED=1 fi echo "" # Step 4: 执行数据库迁移 if [ $DB_CHANGED -eq 1 ]; then echo "Step 4: 执行数据库迁移..." # 停止应用(避免数据冲突) echo " 停止应用..." pm2 stop hrm-app # 安装依赖(可能有新的数据库工具) echo " 安装依赖..." pnpm install # 生成迁移文件 echo " 生成迁移文件..." pnpm drizzle-kit generate # 执行迁移 echo " 执行迁移..." pnpm drizzle-kit push if [ $? -ne 0 ]; then echo "❌ 迁移失败!" echo "正在恢复备份..." # 恢复数据库 LATEST_BACKUP=$(ls -t $BACKUP_DIR | head -1) gunzip -c $BACKUP_DIR/$LATEST_BACKUP/database.sql.gz | psql -h 127.0.0.1 -U hrm_user -d hrm_db echo "恢复完成,请检查问题" exit 1 fi echo "✅ 数据库迁移完成" else echo "Step 4: 无数据库变更,跳过迁移" pnpm install fi echo "" # Step 5: 构建 echo "Step 5: 构建项目..." pnpm build if [ $? -ne 0 ]; then echo "❌ 构建失败!" pm2 start hrm-app exit 1 fi echo "✅ 构建完成" echo "" # Step 6: 启动应用 echo "Step 6: 启动应用..." pm2 start hrm-app sleep 5 # Step 7: 验证 echo "Step 7: 验证应用..." pm2 list | grep hrm-app # 健康检查 HEALTH=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5000) if [ "$HEALTH" = "200" ] || [ "$HEALTH" = "307" ]; then echo "✅ 应用运行正常 (HTTP $HEALTH)" else echo "⚠️ 应用可能有问题 (HTTP $HEALTH)" fi echo "" echo "========== 更新完成 ==========" echo "版本: $AFTER_COMMIT" echo "备份: $BACKUP_DIR/$DATE" ``` ### 4.4 手动数据库操作 有时需要手动执行 SQL,以下是安全操作流程: ```bash # 1. 进入数据库 psql -h 127.0.0.1 -U hrm_user -d hrm_db # 2. 开启事务 BEGIN; # 3. 执行变更 ALTER TABLE users ADD COLUMN phone VARCHAR(20); # 4. 检查结果 SELECT * FROM users LIMIT 5; # 5. 如果正确,提交 COMMIT; # 6. 如果有问题,回滚 # ROLLBACK; ``` ### 4.5 大表变更处理 如果表数据量很大(百万级),需要特别注意: ```sql -- ❌ 错误:直接添加字段会锁表 ALTER TABLE large_table ADD COLUMN new_field VARCHAR(100); -- ✅ 正确:分步处理 -- 1. 添加字段(允许 NULL,不锁表) ALTER TABLE large_table ADD COLUMN new_field VARCHAR(100); -- 2. 分批更新数据 -- 每次更新 10000 条,避免长事务 DO $$ DECLARE batch_size INT := 10000; total_rows INT; batches INT; BEGIN SELECT COUNT(*) INTO total_rows FROM large_table WHERE new_field IS NULL; batches := CEIL(total_rows::FLOAT / batch_size); FOR i IN 1..batches LOOP UPDATE large_table SET new_field = 'default_value' WHERE id IN ( SELECT id FROM large_table WHERE new_field IS NULL LIMIT batch_size ); COMMIT; RAISE NOTICE 'Batch %/% completed', i, batches; END LOOP; END $$; -- 3. 添加约束(如果有需要) ALTER TABLE large_table ALTER COLUMN new_field SET NOT NULL; ``` --- ## 5. 回滚方案 ### 5.1 快速回滚代码 ```bash #!/bin/bash # 文件: scripts/rollback-code.sh PROJECT_DIR="/www/wwwroot/hrm-app" cd $PROJECT_DIR echo "========== 代码回滚 ==========" # 显示最近的提交 echo "最近的提交:" git log --oneline -10 echo "" # 输入要回滚到的版本 read -p "请输入要回滚到的版本号(前7位即可): " VERSION if [ -z "$VERSION" ]; then echo "未输入版本号,取消回滚" exit 1 fi echo "即将回滚到: $VERSION" read -p "确认回滚?(y/n): " CONFIRM if [ "$CONFIRM" != "y" ]; then echo "取消回滚" exit 0 fi # 回滚代码 git reset --hard $VERSION # 重新安装依赖 pnpm install # 重新构建 pnpm build # 重启应用 pm2 restart hrm-app echo "✅ 回滚完成" ``` ### 5.2 回滚数据库 ```bash #!/bin/bash # 文件: scripts/rollback-db.sh BACKUP_DIR="/www/backup/hrm-app" PROJECT_DIR="/www/wwwroot/hrm-app" echo "========== 数据库回滚 ==========" # 显示可用的备份 echo "可用的备份:" ls -lt $BACKUP_DIR | head -10 echo "" # 输入要恢复的备份 read -p "请输入备份目录名(如 20260517_143000): " BACKUP_NAME if [ -z "$BACKUP_NAME" ]; then echo "未输入备份名,取消回滚" exit 1 fi BACKUP_PATH="$BACKUP_DIR/$BACKUP_NAME" if [ ! -d "$BACKUP_PATH" ]; then echo "❌ 备份不存在: $BACKUP_PATH" exit 1 fi echo "即将恢复: $BACKUP_PATH" read -p "确认恢复?这会覆盖当前数据库!(y/n): " CONFIRM if [ "$CONFIRM" != "y" ]; then echo "取消回滚" exit 0 fi # 停止应用 echo "停止应用..." pm2 stop hrm-app # 恢复数据库 echo "恢复数据库..." source $PROJECT_DIR/.env 2>/dev/null || true DB_HOST=$(echo $DATABASE_URL | sed -n 's/.*@\([^:]*\):.*/\1/p') DB_PORT=$(echo $DATABASE_URL | sed -n 's/.*:\([0-9]*\)\/.*/\1/p') DB_NAME=$(echo $DATABASE_URL | sed -n 's/.*\/\([^?]*\).*/\1/p') DB_USER=$(echo $DATABASE_URL | sed -n 's/.*\/\/\([^:]*\):.*/\1/p') gunzip -c $BACKUP_PATH/database.sql.gz | psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME if [ $? -eq 0 ]; then echo "✅ 数据库恢复完成" else echo "❌ 数据库恢复失败" exit 1 fi # 启动应用 echo "启动应用..." pm2 start hrm-app echo "✅ 回滚完成" ``` ### 5.3 完整回滚(代码 + 数据库) ```bash #!/bin/bash # 文件: scripts/rollback-full.sh BACKUP_DIR="/www/backup/hrm-app" PROJECT_DIR="/www/wwwroot/hrm-app" echo "========== 完整回滚 ==========" # 显示可用的备份 echo "可用的备份:" ls -lt $BACKUP_DIR | head -10 echo "" read -p "请输入备份目录名: " BACKUP_NAME BACKUP_PATH="$BACKUP_DIR/$BACKUP_NAME" if [ ! -d "$BACKUP_PATH" ]; then echo "❌ 备份不存在" exit 1 fi read -p "确认完整回滚?(y/n): " CONFIRM if [ "$CONFIRM" != "y" ]; then exit 0 fi cd $PROJECT_DIR # 1. 停止应用 echo "1. 停止应用..." pm2 stop hrm-app # 2. 恢复代码 echo "2. 恢复代码..." rm -rf $PROJECT_DIR/* tar -xzf $BACKUP_PATH/code.tar.gz -C $PROJECT_DIR # 3. 恢复环境变量 echo "3. 恢复环境变量..." cp $BACKUP_PATH/.env $PROJECT_DIR/.env # 4. 恢复数据库 echo "4. 恢复数据库..." source $PROJECT_DIR/.env 2>/dev/null || true DB_HOST=$(echo $DATABASE_URL | sed -n 's/.*@\([^:]*\):.*/\1/p') DB_PORT=$(echo $DATABASE_URL | sed -n 's/.*:\([0-9]*\)\/.*/\1/p') DB_NAME=$(echo $DATABASE_URL | sed -n 's/.*\/\([^?]*\).*/\1/p') DB_USER=$(echo $DATABASE_URL | sed -n 's/.*\/\/\([^:]*\):.*/\1/p') gunzip -c $BACKUP_PATH/database.sql.gz | psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME # 5. 安装依赖 echo "5. 安装依赖..." pnpm install # 6. 构建 echo "6. 构建..." pnpm build # 7. 启动 echo "7. 启动应用..." pm2 start hrm-app echo "✅ 完整回滚完成" ``` --- ## 6. 更新后验证 ### 6.1 自动验证脚本 ```bash #!/bin/bash # 文件: scripts/verify-update.sh echo "========== 更新验证 ==========" # 1. 检查应用状态 echo "1. 应用状态:" pm2 list | grep hrm-app echo "" # 2. 检查端口 echo "2. 端口监听:" netstat -tlnp | grep 5000 echo "" # 3. 健康检查 echo "3. 健康检查:" HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5000) if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "307" ]; then echo "✅ HTTP 状态正常 ($HTTP_CODE)" else echo "❌ HTTP 状态异常 ($HTTP_CODE)" fi echo "" # 4. 数据库连接 echo "4. 数据库连接:" pg_isready -h 127.0.0.1 -p 5432 echo "" # 5. 检查错误日志 echo "5. 最近错误日志:" tail -20 /www/wwwroot/hrm-app/logs/error.log 2>/dev/null || echo "无错误日志" echo "" # 6. 检查数据库表 echo "6. 核心数据表:" psql -h 127.0.0.1 -U hrm_user -d hrm_db -c " SELECT schemaname, tablename, n_live_tup as row_count FROM pg_stat_user_tables WHERE schemaname = 'public' ORDER BY n_live_tup DESC LIMIT 10; " echo "" echo "========== 验证完成 ==========" ``` ### 6.2 功能验证清单 更新后请手动验证以下功能: - [ ] 用户登录功能正常 - [ ] 主要业务功能正常 - [ ] 数据显示正确 - [ ] 文件上传功能正常 - [ ] 导出功能正常 - [ ] API 接口响应正常 - [ ] 页面加载速度正常 --- ## 7. 常见问题 ### Q1: 迁移时报错 "relation already exists" **原因**:表或字段已存在 **解决**: ```sql -- 检查表是否存在 SELECT * FROM pg_tables WHERE tablename = 'your_table'; -- 检查字段是否存在 SELECT column_name FROM information_schema.columns WHERE table_name = 'your_table' AND column_name = 'your_column'; -- 如果已存在,跳过该迁移或修改迁移脚本 ``` ### Q2: 迁移时报错 "column cannot be cast automatically" **原因**:字段类型转换不兼容 **解决**: ```sql -- 添加 USING 子句指定转换方式 ALTER TABLE users ALTER COLUMN age TYPE BIGINT USING age::BIGINT; ``` ### Q3: 数据库更新很慢 **原因**:大表操作锁表 **解决**: ```sql -- 查看当前运行的查询 SELECT * FROM pg_stat_activity WHERE state = 'active'; -- 查看锁等待 SELECT * FROM pg_locks WHERE NOT granted; -- 取消长时间运行的查询(谨慎) SELECT pg_cancel_backend(pid); -- 终止连接(更强制) SELECT pg_terminate_backend(pid); ``` ### Q4: 回滚后数据不一致 **原因**:回滚后应用代码和数据库结构不匹配 **解决**: 1. 确保使用完整的备份回滚 2. 回滚后重新安装依赖和构建 3. 清除浏览器缓存重新测试 ### Q5: 如何查看迁移历史 ```bash # Drizzle 迁移记录 ls -la drizzle/ # 或查询数据库 psql -h 127.0.0.1 -U hrm_user -d hrm_db -c " SELECT * FROM drizzle.__drizzle_migrations ORDER BY created_at DESC; " ``` ### Q6: 更新时用户正在使用怎么办? **建议**: 1. 选择低峰时段更新(如凌晨 2-4 点) 2. 提前通知用户维护时间 3. 使用维护页面提示用户 4. 快速更新(整个流程控制在 10 分钟内) ```nginx # 维护模式 Nginx 配置 server { # ... 其他配置 ... # 维护模式开关(创建 /www/wwwroot/hrm-app/.maintenance 文件启用) if (-f /www/wwwroot/hrm-app/.maintenance) { return 503; } error_page 503 @maintenance; location @maintenance { root /www/wwwroot/hrm-app/public; try_files /maintenance.html =503; } } ``` --- ## 📝 更新流程总结 ### 低风险更新(无数据库变更) ```bash # 1. 备份(可选) # 2. git pull # 3. pnpm install # 4. pnpm build # 5. pm2 restart hrm-app ``` ### 高风险更新(有数据库变更) ```bash # 1. 完整备份(必须!) # 2. 通知用户维护 # 3. pm2 stop hrm-app # 4. git pull # 5. pnpm install # 6. 执行数据库迁移 # 7. pnpm build # 8. pm2 start hrm-app # 9. 验证功能 # 10. 如有问题,执行回滚 ``` ### 紧急修复 ```bash # 快速回滚到上一个版本 cd /www/wwwroot/hrm-app git reset --hard HEAD~1 pnpm install && pnpm build && pm2 restart hrm-app ``` --- ## 🛡️ 安全建议 1. **永远先备份**:任何更新前都要备份 2. **测试环境验证**:先在测试环境测试更新流程 3. **分步执行**:不要一次性执行大量变更 4. **保留回滚能力**:确保随时可以回滚 5. **监控告警**:设置监控,更新后关注错误日志 6. **文档记录**:记录每次更新的内容和结果 --- ## 📅 建议的维护窗口 | 时段 | 适用场景 | 说明 | |------|----------|------| | 凌晨 2:00-4:00 | 大版本更新 | 用户最少,适合停机维护 | | 凌晨 4:00-6:00 | 常规更新 | 影响最小 | | 周末凌晨 | 数据迁移 | 有充足时间处理问题 | | 工作日晚 | 紧急修复 | 影响较大,仅限紧急情况 |
未来鸟
2026年7月27日 10:20
转发
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
分享
链接
类型
密码
更新密码
有效期
Markdown文件
Word文件
PDF文档(打印)
AI