chore: 增加服务器部署打包脚本
This commit is contained in:
@@ -4,3 +4,4 @@ dist
|
|||||||
.env.*
|
.env.*
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.log
|
*.log
|
||||||
|
*.tar.gz
|
||||||
|
|||||||
@@ -42,6 +42,10 @@
|
|||||||
├── RTK.md # 项目协作规则和开发约定
|
├── RTK.md # 项目协作规则和开发约定
|
||||||
├── docs/
|
├── docs/
|
||||||
│ └── API.md # 前端对接接口文档
|
│ └── API.md # 前端对接接口文档
|
||||||
|
├── deploy/
|
||||||
|
│ └── server/
|
||||||
|
│ ├── create-env.sh # 在服务器生成真实 .env 和 .env.production
|
||||||
|
│ └── docker-compose.mysql.yml # 服务器 MySQL Compose 模板
|
||||||
├── migrations/ # 数据库迁移 SQL
|
├── migrations/ # 数据库迁移 SQL
|
||||||
│ ├── 001_initial_schema.sql # 创建基础表结构
|
│ ├── 001_initial_schema.sql # 创建基础表结构
|
||||||
│ ├── 002_seed_demo_data.sql # 初始化演示门店和角色
|
│ ├── 002_seed_demo_data.sql # 初始化演示门店和角色
|
||||||
@@ -82,10 +86,11 @@
|
|||||||
| `AGENTS.md` | Agent 工具读取的入口文件,当前通过 `@RTK.md` 引入项目规则。 |
|
| `AGENTS.md` | Agent 工具读取的入口文件,当前通过 `@RTK.md` 引入项目规则。 |
|
||||||
| `RTK.md` | 本项目的协作规则,例如使用中文说明、保持分层、改目录时同步 README。 |
|
| `RTK.md` | 本项目的协作规则,例如使用中文说明、保持分层、改目录时同步 README。 |
|
||||||
| `docs/API.md` | 面向前端对接的完整接口文档,包含认证、权限、字段约束、示例请求响应和错误码。 |
|
| `docs/API.md` | 面向前端对接的完整接口文档,包含认证、权限、字段约束、示例请求响应和错误码。 |
|
||||||
|
| `deploy/server/` | 服务器部署辅助文件。`create-env.sh` 在服务器本地生成真实环境变量,`docker-compose.mysql.yml` 用于启动服务器 MySQL。 |
|
||||||
| `migrations/` | 数据库迁移目录。所有建表、改表、初始化基础数据的 SQL 都放在这里。 |
|
| `migrations/` | 数据库迁移目录。所有建表、改表、初始化基础数据的 SQL 都放在这里。 |
|
||||||
| `src/app.ts` | 创建 Fastify 应用,注册路由,处理健康检查和全局错误。 |
|
| `src/app.ts` | 创建 Fastify 应用,注册路由,处理健康检查和全局错误。 |
|
||||||
| `src/server.ts` | 真正启动 HTTP 服务,监听端口,并处理优雅停机。 |
|
| `src/server.ts` | 真正启动 HTTP 服务,监听端口,并处理优雅停机。 |
|
||||||
| `src/config/env.ts` | 使用 zod 校验 `.env.development` 中的环境变量,避免配置错误拖到请求阶段才暴露。 |
|
| `src/config/env.ts` | 使用 zod 校验当前运行环境变量,避免配置错误拖到请求阶段才暴露。 |
|
||||||
| `src/db/migrate.ts` | 执行 `migrations/*.sql`,并用 `schema_migrations` 记录已执行迁移。 |
|
| `src/db/migrate.ts` | 执行 `migrations/*.sql`,并用 `schema_migrations` 记录已执行迁移。 |
|
||||||
| `src/db/pool.ts` | 创建 MySQL 连接池,提供数据库健康检查和关闭连接的方法。 |
|
| `src/db/pool.ts` | 创建 MySQL 连接池,提供数据库健康检查和关闭连接的方法。 |
|
||||||
| `src/modules/auth/` | 登录鉴权模块,负责后台登录、员工端登录、密码校验、JWT 签发、当前用户查询和权限 guard。 |
|
| `src/modules/auth/` | 登录鉴权模块,负责后台登录、员工端登录、密码校验、JWT 签发、当前用户查询和权限 guard。 |
|
||||||
@@ -200,6 +205,74 @@ curl http://localhost:3500/health
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 服务器部署准备
|
||||||
|
|
||||||
|
服务器部署时不要直接使用本地 `.env.development`,也不要把本机 `.env.*` 打进部署包。真实密码只应该在服务器本地生成和保存。
|
||||||
|
|
||||||
|
1. 生成服务器真实环境变量:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /srv/www/access-manage
|
||||||
|
bash deploy/server/create-env.sh /srv/www/access-manage
|
||||||
|
```
|
||||||
|
|
||||||
|
这个脚本会生成两个不提交到仓库的文件:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/srv/www/access-manage/.env
|
||||||
|
/srv/www/access-manage/.env.production
|
||||||
|
```
|
||||||
|
|
||||||
|
其中 `.env` 给 MySQL 容器使用,`.env.production` 给 Node 后端使用。如果 `.env` 已经存在,脚本会读取现有 `MYSQL_PASSWORD`,只补 `.env.production`;如果 `.env.production` 已经存在,脚本会拒绝覆盖。
|
||||||
|
|
||||||
|
2. 启动服务器 MySQL:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose -f deploy/server/docker-compose.mysql.yml up -d mysql
|
||||||
|
```
|
||||||
|
|
||||||
|
服务器模板会把 MySQL 数据持久化到:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/srv/data/access-manage/mysql
|
||||||
|
```
|
||||||
|
|
||||||
|
当前模板默认后端通过服务器本机端口连接 MySQL:
|
||||||
|
|
||||||
|
```env
|
||||||
|
DB_HOST=127.0.0.1
|
||||||
|
DB_PORT=3307
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 构建、迁移、启动:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
pnpm build
|
||||||
|
pnpm db:migrate:prod
|
||||||
|
pnpm start:prod
|
||||||
|
```
|
||||||
|
|
||||||
|
生产迁移脚本运行的是编译后的 `dist/db/migrate.js`,所以服务器上要先执行 `pnpm build`,再执行 `pnpm db:migrate:prod`。
|
||||||
|
|
||||||
|
4. 健康检查:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://127.0.0.1:3500/health
|
||||||
|
```
|
||||||
|
|
||||||
|
只有返回里出现 `database: "up"`,才代表后端服务和 MySQL 都连通。
|
||||||
|
|
||||||
|
如果用压缩包部署,至少需要包含 `src/`、`migrations/`、`deploy/`、`package.json`、`pnpm-lock.yaml`、`tsconfig.json`。不要把本机 `.env.*`、`node_modules/` 和 `.git/` 打进部署包。
|
||||||
|
|
||||||
|
可以在本机执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm build:dev
|
||||||
|
```
|
||||||
|
|
||||||
|
生成的 `access-manage-dev.tar.gz` 会排除本地环境变量、`node_modules/`、`dist/` 和本地开发用 `docker-compose.yml`,避免覆盖服务器已经准备好的 MySQL 配置。正式生产发布时可以执行 `pnpm build:pro`,生成 `access-manage-pro.tar.gz`。
|
||||||
|
|
||||||
## package.json 脚本说明
|
## package.json 脚本说明
|
||||||
|
|
||||||
这些脚本定义在 [package.json](./package.json) 的 `scripts` 字段里。
|
这些脚本定义在 [package.json](./package.json) 的 `scripts` 字段里。
|
||||||
@@ -208,9 +281,13 @@ curl http://localhost:3500/health
|
|||||||
| ------------------- | --------------------------------------------------------------------------- | -------------------------------------------------- |
|
| ------------------- | --------------------------------------------------------------------------- | -------------------------------------------------- |
|
||||||
| `pnpm dev` | 使用现有 `.env.development` 启动开发服务,并通过 `tsx watch` 监听代码变化。 | 日常开发接口时使用。 |
|
| `pnpm dev` | 使用现有 `.env.development` 启动开发服务,并通过 `tsx watch` 监听代码变化。 | 日常开发接口时使用。 |
|
||||||
| `pnpm build` | 使用 `tsc` 编译 TypeScript,输出到 `dist/`。 | 准备运行编译产物或发布前验证时使用。 |
|
| `pnpm build` | 使用 `tsc` 编译 TypeScript,输出到 `dist/`。 | 准备运行编译产物或发布前验证时使用。 |
|
||||||
|
| `pnpm build:dev` | 先执行 `pnpm build`,再生成 `access-manage-dev.tar.gz`。 | 准备上传开发/测试服务器的源码部署包时使用。 |
|
||||||
|
| `pnpm build:pro` | 先执行 `pnpm build`,再生成 `access-manage-pro.tar.gz`。 | 准备正式生产发布包时使用。 |
|
||||||
| `pnpm start` | 使用现有 `.env.development` 运行 `dist/server.js`。 | 已经执行过 `pnpm build` 后,用编译产物启动服务。 |
|
| `pnpm start` | 使用现有 `.env.development` 运行 `dist/server.js`。 | 已经执行过 `pnpm build` 后,用编译产物启动服务。 |
|
||||||
|
| `pnpm start:prod` | 使用 `.env.production` 运行 `dist/server.js`。 | 服务器生产环境启动编译产物时使用。 |
|
||||||
| `pnpm typecheck` | 执行 `tsc --noEmit`,只检查类型,不生成文件。 | 改 TypeScript 代码后快速确认类型是否正确。 |
|
| `pnpm typecheck` | 执行 `tsc --noEmit`,只检查类型,不生成文件。 | 改 TypeScript 代码后快速确认类型是否正确。 |
|
||||||
| `pnpm db:migrate` | 使用现有 `.env.development` 运行 `src/db/migrate.ts`,按顺序执行 `migrations/*.sql`。 | 第一次启动项目、拉到新迁移、改数据库结构后使用。 |
|
| `pnpm db:migrate` | 使用现有 `.env.development` 运行 `src/db/migrate.ts`,按顺序执行 `migrations/*.sql`。 | 第一次启动项目、拉到新迁移、改数据库结构后使用。 |
|
||||||
|
| `pnpm db:migrate:prod` | 使用 `.env.production` 运行 `dist/db/migrate.js`,按顺序执行 `migrations/*.sql`。 | 服务器生产环境建表、升级表结构或初始化基础数据时使用。 |
|
||||||
| `pnpm db:shell` | 进入 Docker 容器里的 MySQL 命令行。 | 需要手动查看表结构或查询数据时使用。 |
|
| `pnpm db:shell` | 进入 Docker 容器里的 MySQL 命令行。 | 需要手动查看表结构或查询数据时使用。 |
|
||||||
| `pnpm mysql:up` | 启动本地 MySQL 容器。 | 开发前先启动数据库。 |
|
| `pnpm mysql:up` | 启动本地 MySQL 容器。 | 开发前先启动数据库。 |
|
||||||
| `pnpm mysql:down` | 停止并移除本地 MySQL 容器。 | 不再需要本地数据库容器时使用。 |
|
| `pnpm mysql:down` | 停止并移除本地 MySQL 容器。 | 不再需要本地数据库容器时使用。 |
|
||||||
@@ -571,7 +648,7 @@ curl -X DELETE http://localhost:3500/api/employees/1 \
|
|||||||
- [006_create_role_permissions.sql](./migrations/006_create_role_permissions.sql):创建角色权限关系表,并初始化 `admin` 和 `store_manager` 的默认权限。
|
- [006_create_role_permissions.sql](./migrations/006_create_role_permissions.sql):创建角色权限关系表,并初始化 `admin` 和 `store_manager` 的默认权限。
|
||||||
- [007_add_soft_delete_to_roles_and_relations.sql](./migrations/007_add_soft_delete_to_roles_and_relations.sql):给角色、员工角色关系和角色权限关系补充逻辑删除字段,移除关系表旧的 `ON DELETE CASCADE` 级联删除语义。
|
- [007_add_soft_delete_to_roles_and_relations.sql](./migrations/007_add_soft_delete_to_roles_and_relations.sql):给角色、员工角色关系和角色权限关系补充逻辑删除字段,移除关系表旧的 `ON DELETE CASCADE` 级联删除语义。
|
||||||
|
|
||||||
执行 `pnpm db:migrate` 时,脚本会:
|
执行 `pnpm db:migrate` 或 `pnpm db:migrate:prod` 时,脚本会:
|
||||||
|
|
||||||
1. 创建 `schema_migrations` 迁移记录表。
|
1. 创建 `schema_migrations` 迁移记录表。
|
||||||
2. 读取 `migrations` 目录里的 `.sql` 文件。
|
2. 读取 `migrations` 目录里的 `.sql` 文件。
|
||||||
|
|||||||
Executable
+68
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
target_dir="${1:-$(pwd)}"
|
||||||
|
mysql_env="${target_dir}/.env"
|
||||||
|
app_env="${target_dir}/.env.production"
|
||||||
|
|
||||||
|
if [[ -e "${app_env}" ]]; then
|
||||||
|
echo "Refuse to overwrite existing .env.production in ${target_dir}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v openssl >/dev/null 2>&1; then
|
||||||
|
echo "openssl is required to generate production secrets" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "${target_dir}"
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
if [[ -e "${mysql_env}" ]]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source "${mysql_env}"
|
||||||
|
|
||||||
|
mysql_database="${MYSQL_DATABASE:-access_manage}"
|
||||||
|
mysql_user="${MYSQL_USER:-access_user}"
|
||||||
|
mysql_password="${MYSQL_PASSWORD:-}"
|
||||||
|
|
||||||
|
if [[ -z "${mysql_password}" ]]; then
|
||||||
|
echo "MYSQL_PASSWORD is missing in ${mysql_env}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Found existing ${mysql_env}; only creating ${app_env}"
|
||||||
|
else
|
||||||
|
mysql_root_password="root_$(openssl rand -hex 24)"
|
||||||
|
mysql_database="access_manage"
|
||||||
|
mysql_user="access_user"
|
||||||
|
mysql_password="app_$(openssl rand -hex 24)"
|
||||||
|
|
||||||
|
cat > "${mysql_env}" <<EOF
|
||||||
|
MYSQL_ROOT_PASSWORD=${mysql_root_password}
|
||||||
|
MYSQL_DATABASE=${mysql_database}
|
||||||
|
MYSQL_USER=${mysql_user}
|
||||||
|
MYSQL_PASSWORD=${mysql_password}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Created ${mysql_env}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
jwt_secret="$(openssl rand -hex 48)"
|
||||||
|
|
||||||
|
cat > "${app_env}" <<EOF
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=3500
|
||||||
|
|
||||||
|
DB_HOST=127.0.0.1
|
||||||
|
DB_PORT=3307
|
||||||
|
DB_USER=${mysql_user}
|
||||||
|
DB_PASSWORD=${mysql_password}
|
||||||
|
DB_NAME=${mysql_database}
|
||||||
|
DB_CONNECTION_LIMIT=10
|
||||||
|
|
||||||
|
JWT_SECRET=${jwt_secret}
|
||||||
|
JWT_EXPIRES_IN=2h
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Created ${app_env}"
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mysql:8.4
|
||||||
|
container_name: access-manage-mysql
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||||
|
MYSQL_DATABASE: ${MYSQL_DATABASE}
|
||||||
|
MYSQL_USER: ${MYSQL_USER}
|
||||||
|
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||||
|
TZ: Asia/Shanghai
|
||||||
|
ports:
|
||||||
|
- "3307:3306"
|
||||||
|
volumes:
|
||||||
|
- /srv/data/access-manage/mysql:/var/lib/mysql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -p$${MYSQL_ROOT_PASSWORD} --silent"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 20
|
||||||
@@ -6,9 +6,13 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "DOTENV_CONFIG_PATH=.env.development tsx watch src/server.ts",
|
"dev": "DOTENV_CONFIG_PATH=.env.development tsx watch src/server.ts",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
|
"build:dev": "pnpm build && tar -czf access-manage-dev.tar.gz package.json pnpm-lock.yaml tsconfig.json src migrations deploy docs README.md AGENTS.md RTK.md",
|
||||||
|
"build:pro": "pnpm build && tar -czf access-manage-pro.tar.gz package.json pnpm-lock.yaml tsconfig.json src migrations deploy docs README.md AGENTS.md RTK.md",
|
||||||
"start": "DOTENV_CONFIG_PATH=.env.development node dist/server.js",
|
"start": "DOTENV_CONFIG_PATH=.env.development node dist/server.js",
|
||||||
|
"start:prod": "DOTENV_CONFIG_PATH=.env.production node dist/server.js",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"db:migrate": "DOTENV_CONFIG_PATH=.env.development tsx src/db/migrate.ts",
|
"db:migrate": "DOTENV_CONFIG_PATH=.env.development tsx src/db/migrate.ts",
|
||||||
|
"db:migrate:prod": "DOTENV_CONFIG_PATH=.env.production node dist/db/migrate.js",
|
||||||
"db:shell": "docker compose exec mysql mysql -uaccess_user -paccess_pass access_manage",
|
"db:shell": "docker compose exec mysql mysql -uaccess_user -paccess_pass access_manage",
|
||||||
"mysql:up": "docker compose up -d mysql",
|
"mysql:up": "docker compose up -d mysql",
|
||||||
"mysql:down": "docker compose down"
|
"mysql:down": "docker compose down"
|
||||||
|
|||||||
Reference in New Issue
Block a user