补充仓库文档并完善备份部署脚本

This commit is contained in:
WuYongJie 2026-03-10 17:01:56 +08:00
parent dee0ca70f6
commit b61bd197df
5 changed files with 327 additions and 23 deletions

37
AGENTS.md Normal file
View File

@ -0,0 +1,37 @@
# Repository Guidelines
## 项目结构
仓库分为 `frontend/` 和 `backend/` 两部分。前端是 Vue 3 + Vite,主要代码在 `frontend/src/`:页面在 `src/views/`,通用组件在 `src/components/`,接口封装在 `src/api/`,状态管理在 `src/stores/`,路由在 `src/router/`。后端是 Express + TypeScript,代码在 `backend/src/`,按 `routes/`、`controllers/`、`middleware/`、`utils/` 分层。数据库模型统一在 `backend/prisma/schema.prisma`。部署相关文件在仓库根目录:`docker-compose.yml`、`Dockerfile`、`deploy.sh`。
## 构建、运行与开发命令
首次进入前后端目录分别执行 `npm install`。
- `cd frontend && npm run dev`:启动前端开发环境。
- `cd frontend && npm run build`:执行类型检查并打包前端。
- `cd backend && npm run dev`:用 `nodemon + ts-node` 启动后端。
- `cd backend && npm run build`:编译后端到 `dist/`。
- `cd backend && npm run prisma:generate`:Prisma 模型变更后重建客户端。
- `cd backend && npm run prisma:migrate`:生成并应用本地数据库迁移。
- `docker compose up --build`:同时启动 MySQL、后端、前端。
## 代码风格与命名
项目以 TypeScript 为主,现有代码统一使用 2 空格缩进。Vue 组件文件使用 PascalCase,如 `EquipmentForm.vue`;接口、store、工具模块使用语义化名称,如 `equipment.ts`、`storageLocation.ts`。新增功能时,尽量保持前端 API 名称、后端路由、控制器按同一业务域对应,方便排查问题。
## 测试与验证
当前仓库没有现成自动化测试脚本,因此每次改动后至少执行 `frontend` 和 `backend` 的 `npm run build`。涉及接口改动时,还应手动验证对应页面流程,并检查 `GET /api/health`。涉及 Prisma 或数据库结构调整时,额外执行 `npm run prisma:generate`,确认相关增删改查正常。若后续补测试,建议使用 `*.spec.ts` 命名。
## 提交与合并请求
当前 Git 历史很少,只有初始提交,没有强约束格式。建议提交信息使用简短中文,写清“改了什么”,例如:`后端:修复借用记录筛选条件`。Pull Request 需要说明变更范围、验证方式、是否影响数据库或部署;前端页面改动建议附截图,接口或表结构改动要明确标注兼容性影响。
## 配置与安全
不要提交真实密码、数据库连接串或生产环境地址。`DATABASE_URL`、会话密钥、认证模式等应通过环境变量管理。修改 `docker-compose.yml`、认证配置或对外端口时,先确认是否会影响本地联调和线上部署。
## Multi-Agent 团队分工
推荐使用 4 个角色,保持团队小而清晰。
- 主控 / 集成代理:负责拆任务、安排子代理、收敛方案、做最终验收;默认可读全仓库,但不要直接承担大批量业务改动。
- 前端业务代理:只负责 `frontend/src/views/`、`frontend/src/components/`、`frontend/src/api/`、`frontend/src/stores/`、`frontend/src/router/`,处理页面、交互、表单、状态和前端接口联调。
- 后端业务代理:只负责 `backend/src/routes/`、`backend/src/controllers/`,处理资产、借还、搜索、统计、人员等业务接口。
- 数据与系统代理:只负责 `backend/prisma/`、`backend/src/middleware/`、`backend/src/utils/`、认证配置、`docker-compose.yml`、`Dockerfile`、`deploy.sh`,处理数据库结构、权限、认证、部署和环境问题。
协作时尽量避免跨边界改动:前端代理不直接改 Prisma,后端业务代理不直接动 Docker,数据与系统代理不直接改页面。

42
BACKUP.md Normal file
View File

@ -0,0 +1,42 @@
# 固定资产系统备份说明
本仓库只备份固定资产系统,不处理摄影设备借还系统。对应服务器资源如下:
- 项目目录:`/opt/equipment-management`
- 数据库容器:`equipment-mysql`
- 数据库名:`equipment_management`
- 后端容器:`equipment-backend`
- 上传目录:`/app/uploads`
- 备份目录:`/opt/backups/equipment-management`
- 默认保留:最近 `3` 份备份
## 执行方式
先把脚本上传到服务器,例如放到 `/opt/equipment-management/scripts/backup-equipment.sh`,然后执行:
```bash
chmod +x /opt/equipment-management/scripts/backup-equipment.sh
/opt/equipment-management/scripts/backup-equipment.sh
```
如果以后要临时调整保留数量,可以这样执行:
```bash
KEEP_BACKUPS=5 /opt/equipment-management/scripts/backup-equipment.sh
```
## 备份内容
每次执行会生成一个时间戳目录,包含:
- `db/equipment_management.sql.gz`:数据库导出
- `uploads/uploads.tar.gz`:上传文件归档
- `config/`:当前部署配置副本
- `backup-info.txt`:备份元信息
- `SHA256SUMS`:校验文件
脚本完成后会自动清理更早的备份目录,只保留最近 `KEEP_BACKUPS` 份,避免占满服务器磁盘。
## 回滚思路
发生部署异常时,先恢复代码和部署配置,再恢复数据库和上传目录。数据库恢复建议在停掉固定资产系统容器后执行,避免写入冲突。摄影设备借还系统使用独立容器、端口、网络和数据卷,不应纳入这套备份或回滚流程。

80
README.md Normal file
View File

@ -0,0 +1,80 @@
# 固定资产管理系统
这是一个前后端分离的固定资产管理系统,覆盖资产台账、借用归还、扫码出入库、挂载关系、维修、报废、统计分析和系统设置等功能。
## 技术栈
- 前端:Vue 3、Vite、TypeScript、Pinia、Vue Router、Tailwind CSS
- 后端:Express、TypeScript、Prisma、MySQL
- 部署:Docker Compose
## 目录结构
- `frontend/`:前端页面、组件、状态管理、接口封装
- `backend/`:后端路由、控制器、中间件、工具函数
- `backend/prisma/schema.prisma`:数据库模型
- `deploy.sh`:固定资产系统安全部署脚本
- `scripts/backup-equipment.sh`:固定资产系统备份脚本
- `AGENTS.md`:仓库协作与多代理分工说明
- `BACKUP.md`:备份与回滚说明
## 本地开发
分别安装依赖:
```bash
cd frontend && npm install
cd backend && npm install
```
常用命令:
```bash
cd frontend && npm run dev
cd frontend && npm run build
cd backend && npm run dev
cd backend && npm run build
cd backend && npm run prisma:generate
cd backend && npm run prisma:migrate
```
## 服务器部署
生产服务器上同时运行两套同类系统:
- 固定资产系统:`/opt/equipment-management`
- 摄影设备借还系统:`/opt/shebeiguanli`
两套系统使用不同的容器、端口、网络和数据卷。部署本项目时,只能操作固定资产系统这一套资源,不能影响 `shebeiguanli-*` 容器。
执行部署:
```bash
cd /opt/equipment-management
./deploy.sh
```
部署脚本默认会先备份,再重建固定资产系统容器,最后检查健康状态和另一套系统状态。
## 备份与回滚
执行备份:
```bash
cd /opt/equipment-management
./scripts/backup-equipment.sh
```
默认只保留最近 `3` 份备份,备份目录在 `/opt/backups/equipment-management`。详细说明见 `BACKUP.md`。
## 当前线上资源
- 前端:`http://1.13.22.133`
- 后端:`http://1.13.22.133:3000/api`
- 健康检查:`http://1.13.22.133:3000/api/health`
## 注意事项
- 不要把真实密码、数据库连接串或生产环境地址提交到仓库。
- 涉及 Prisma 模型调整时,先生成客户端,再验证相关接口。
- 发布前默认执行备份,不建议跳过。

View File

@ -1,41 +1,87 @@
#!/bin/bash
# 摄影设备借还系统部署脚本
set -e
# 固定资产管理系统部署脚本
set -euo pipefail
PROJECT_DIR="/opt/equipment-management"
COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml"
PROJECT_NAME="equipment-management"
BACKUP_SCRIPT="$PROJECT_DIR/scripts/backup-equipment.sh"
SKIP_BACKUP="${SKIP_BACKUP:-0}"
EQUIPMENT_CONTAINERS=("equipment-frontend" "equipment-backend" "equipment-mysql")
LEGACY_CONTAINERS=("shebeiguanli-frontend" "shebeiguanli-backend" "shebeiguanli-mysql")
if docker compose version >/dev/null 2>&1; then
COMPOSE_CMD=(docker compose -p "$PROJECT_NAME" -f "$COMPOSE_FILE")
elif command -v docker-compose >/dev/null 2>&1; then
COMPOSE_CMD=(docker-compose -p "$PROJECT_NAME" -f "$COMPOSE_FILE")
else
echo "未找到 docker compose / docker-compose,无法部署。"
exit 1
fi
echo "=========================================="
echo " 摄影设备借还系统 - 部署脚本"
echo " 固定资产管理系统 - 安全部署脚本"
echo "=========================================="
echo "项目目录: $PROJECT_DIR"
echo "Compose 文件: $COMPOSE_FILE"
echo "Compose 项目名: $PROJECT_NAME"
echo "备份脚本: $BACKUP_SCRIPT"
echo ""
# 进入项目目录
cd /opt/equipment-management
if [ ! -f "$COMPOSE_FILE" ]; then
echo "未找到 $COMPOSE_FILE"
exit 1
fi
# 停止旧容器
echo ">>> 停止旧容器..."
sudo docker-compose down 2>/dev/null || true
cd "$PROJECT_DIR"
# 构建并启动容器
echo ">>> 构建Docker镜像..."
sudo docker-compose build --no-cache
if [ "$SKIP_BACKUP" = "1" ]; then
echo ">>> 已设置 SKIP_BACKUP=1,跳过备份"
else
if [ ! -x "$BACKUP_SCRIPT" ]; then
echo "备份脚本不存在或不可执行: $BACKUP_SCRIPT"
exit 1
fi
echo ">>> 启动服务..."
sudo docker-compose up -d
echo ">>> 先执行固定资产系统备份..."
"$BACKUP_SCRIPT"
fi
echo ">>> 部署前检查旧系统容器状态..."
for container in "${LEGACY_CONTAINERS[@]}"; do
status=$(docker inspect -f '{{.State.Status}}' "$container" 2>/dev/null || echo "missing")
echo " $container => $status"
done
echo ">>> 仅更新固定资产系统容器..."
"${COMPOSE_CMD[@]}" down
"${COMPOSE_CMD[@]}" build
"${COMPOSE_CMD[@]}" up -d
# 等待服务启动
echo ">>> 等待服务启动..."
sleep 10
# 检查服务状态
echo ">>> 检查服务状态..."
sudo docker-compose ps
echo ">>> 固定资产系统容器状态..."
for container in "${EQUIPMENT_CONTAINERS[@]}"; do
status=$(docker inspect -f '{{.State.Status}}' "$container" 2>/dev/null || echo "missing")
echo " $container => $status"
done
# 检查后端健康状态
echo ">>> 检查后端API..."
curl -s http://localhost:3000/api/health || echo "后端服务启动中..."
echo ">>> 再次确认摄影设备借还系统未受影响..."
for container in "${LEGACY_CONTAINERS[@]}"; do
status=$(docker inspect -f '{{.State.Status}}' "$container" 2>/dev/null || echo "missing")
echo " $container => $status"
done
echo ">>> 检查固定资产系统后端健康状态..."
curl -fsS http://localhost:3000/api/health || echo "后端服务启动中..."
echo ""
echo "=========================================="
echo " 部署完成!"
echo " 前端访问: http://1.13.22.133"
echo " 后端API: http://1.13.22.133:3000/api"
echo " 部署完成"
echo " 固定资产前端: http://1.13.22.133"
echo " 固定资产后端: http://1.13.22.133:3000/api"
echo " 摄影设备前端: http://1.13.22.133:8081"
echo " 摄影设备后端: http://1.13.22.133:3001"
echo "=========================================="

View File

@ -0,0 +1,99 @@
#!/bin/bash
# 固定资产系统备份脚本
set -euo pipefail
PROJECT_DIR="${PROJECT_DIR:-/opt/equipment-management}"
PROJECT_NAME="${PROJECT_NAME:-equipment-management}"
BACKUP_ROOT="${BACKUP_ROOT:-/opt/backups/equipment-management}"
KEEP_BACKUPS="${KEEP_BACKUPS:-3}"
DB_CONTAINER="${DB_CONTAINER:-equipment-mysql}"
BACKEND_CONTAINER="${BACKEND_CONTAINER:-equipment-backend}"
DB_NAME="${DB_NAME:-equipment_management}"
DB_USER="${DB_USER:-root}"
DB_PASSWORD="${DB_PASSWORD:-jsjj8888}"
UPLOADS_PATH="${UPLOADS_PATH:-/app/uploads}"
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
BACKUP_DIR="${BACKUP_ROOT}/${TIMESTAMP}"
mkdir -p "${BACKUP_DIR}"
mkdir -p "${BACKUP_DIR}/db" "${BACKUP_DIR}/uploads" "${BACKUP_DIR}/config"
cleanup_on_error() {
echo "备份失败,清理不完整目录: ${BACKUP_DIR}"
rm -rf "${BACKUP_DIR}"
}
prune_old_backups() {
if ! [[ "${KEEP_BACKUPS}" =~ ^[0-9]+$ ]]; then
echo "KEEP_BACKUPS 不是有效数字: ${KEEP_BACKUPS}"
exit 1
fi
mapfile -t existing_backups < <(find "${BACKUP_ROOT}" -mindepth 1 -maxdepth 1 -type d | sort)
local total="${#existing_backups[@]}"
if [ "${total}" -le "${KEEP_BACKUPS}" ]; then
echo ">>> 当前备份数量 ${total},无需清理"
return
fi
local delete_count=$((total - KEEP_BACKUPS))
echo ">>> 仅保留最近 ${KEEP_BACKUPS} 份备份,清理 ${delete_count} 份旧备份"
for backup_dir in "${existing_backups[@]:0:${delete_count}}"; do
echo " 删除: ${backup_dir}"
rm -rf "${backup_dir}"
done
}
trap cleanup_on_error ERR
echo "备份目录: ${BACKUP_DIR}"
echo "保留策略: 最近 ${KEEP_BACKUPS} 份"
if ! docker inspect "${DB_CONTAINER}" >/dev/null 2>&1; then
echo "数据库容器不存在: ${DB_CONTAINER}"
exit 1
fi
if ! docker inspect "${BACKEND_CONTAINER}" >/dev/null 2>&1; then
echo "后端容器不存在: ${BACKEND_CONTAINER}"
exit 1
fi
echo ">>> 备份数据库 ${DB_NAME}"
docker exec "${DB_CONTAINER}" \
sh -lc "exec mysqldump -u${DB_USER} -p'${DB_PASSWORD}' --single-transaction --routines --triggers ${DB_NAME}" \
| gzip > "${BACKUP_DIR}/db/${DB_NAME}.sql.gz"
echo ">>> 备份上传目录 ${UPLOADS_PATH}"
docker exec "${BACKEND_CONTAINER}" \
sh -lc "if [ -d '${UPLOADS_PATH}' ]; then tar -C '${UPLOADS_PATH}' -czf - .; else printf '' | gzip; fi" \
> "${BACKUP_DIR}/uploads/uploads.tar.gz"
echo ">>> 备份部署配置"
cp "${PROJECT_DIR}/docker-compose.yml" "${BACKUP_DIR}/config/docker-compose.yml"
cp "${PROJECT_DIR}/deploy.sh" "${BACKUP_DIR}/config/deploy.sh"
cp "${PROJECT_DIR}/Dockerfile" "${BACKUP_DIR}/config/Dockerfile"
cat > "${BACKUP_DIR}/backup-info.txt" <<EOF
timestamp=${TIMESTAMP}
project_name=${PROJECT_NAME}
project_dir=${PROJECT_DIR}
db_container=${DB_CONTAINER}
backend_container=${BACKEND_CONTAINER}
db_name=${DB_NAME}
uploads_path=${UPLOADS_PATH}
hostname=$(hostname)
EOF
echo ">>> 生成校验信息"
(
cd "${BACKUP_DIR}"
sha256sum db/${DB_NAME}.sql.gz uploads/uploads.tar.gz config/docker-compose.yml config/deploy.sh config/Dockerfile > SHA256SUMS
)
prune_old_backups
trap - ERR
echo "备份完成: ${BACKUP_DIR}"