补充仓库文档并完善备份部署脚本
This commit is contained in:
parent
dee0ca70f6
commit
b61bd197df
37
AGENTS.md
Normal file
37
AGENTS.md
Normal 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
42
BACKUP.md
Normal 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
80
README.md
Normal 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 模型调整时,先生成客户端,再验证相关接口。
|
||||
- 发布前默认执行备份,不建议跳过。
|
||||
92
deploy.sh
92
deploy.sh
@ -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 "=========================================="
|
||||
|
||||
99
scripts/backup-equipment.sh
Normal file
99
scripts/backup-equipment.sh
Normal 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}"
|
||||
Loading…
x
Reference in New Issue
Block a user