feat: 完善环境标识配置
This commit is contained in:
@@ -47,7 +47,8 @@
|
||||
│ └── API.md # 前端对接接口文档
|
||||
├── deploy/
|
||||
│ ├── env/
|
||||
│ │ ├── test.env.example # 测试环境变量示例,不包含真实密码
|
||||
│ │ ├── local.env.example # 本地环境变量示例,不包含真实密码
|
||||
│ │ ├── test.env.example # develop/测试环境变量示例,不包含真实密码
|
||||
│ │ └── production.env.example # 生产环境变量示例,不包含真实密码
|
||||
│ └── server/
|
||||
│ ├── create-env.sh # 在服务器生成测试/生产真实环境变量
|
||||
@@ -94,12 +95,12 @@
|
||||
| --- | --- |
|
||||
| `.agents/skills/readme-structure-sync/` | 项目内 skill。约定当目录、重要文件或 `package.json` 脚本变化时,同步更新 README。 |
|
||||
| `.env.development` | 当前 `package.json` 脚本默认读取的本地开发环境变量文件;该文件只保留在本机,不提交到仓库。 |
|
||||
| `.env.local` / `.env.production` | 本机已有的其他环境变量文件;代码已允许 `NODE_ENV=local` 和 `NODE_ENV=production`,切换脚本时可以复用。 |
|
||||
| `.env.local` / `.env.production` | 本机已有的其他环境变量文件;代码已允许 `APP_ENV=local/develop/production` 区分本地、测试和生产,切换脚本时可以复用。 |
|
||||
| `.gitignore` | 忽略本地环境变量、依赖目录、编译产物和系统文件,避免把无关文件推到仓库。 |
|
||||
| `AGENTS.md` | Agent 工具读取的入口文件,当前通过 `@RTK.md` 引入项目规则。 |
|
||||
| `RTK.md` | 本项目的协作规则,例如使用中文说明、保持分层、改目录时同步 README。 |
|
||||
| `docs/API.md` | 面向前端对接的完整接口文档,包含认证、权限、字段约束、示例请求响应和错误码。 |
|
||||
| `deploy/env/` | 测试/生产环境变量示例,只给字段结构,不提交真实密码。 |
|
||||
| `deploy/env/` | 本地、develop/测试、生产环境变量示例,只给字段结构,不提交真实密码。 |
|
||||
| `deploy/server/` | 服务器部署辅助文件。`create-env.sh` 在服务器本地生成测试/生产真实环境变量,Compose 模板分别启动测试和生产 MySQL。 |
|
||||
| `migrations/` | 数据库迁移目录。所有建表、改表、初始化基础数据的 SQL 都放在这里。 |
|
||||
| `src/app.ts` | 创建 Fastify 应用,注册路由,处理健康检查和全局错误。 |
|
||||
@@ -152,6 +153,8 @@ pnpm install
|
||||
|
||||
```env
|
||||
NODE_ENV=development
|
||||
APP_ENV=local
|
||||
APP_ENV_LABEL=本地环境
|
||||
PORT=3500
|
||||
|
||||
DB_HOST=127.0.0.1
|
||||
@@ -165,7 +168,7 @@ JWT_SECRET=请使用至少 32 位的随机字符串
|
||||
JWT_EXPIRES_IN=2h
|
||||
```
|
||||
|
||||
代码允许的 `NODE_ENV` 值是:`local`、`development`、`test`、`production`。如果改用 `.env.local` 或 `.env.production` 启动,也需要包含同样的 `JWT_SECRET` 和 `JWT_EXPIRES_IN`。
|
||||
代码允许的 `APP_ENV` 值是:`local`、`develop`、`production`,其中历史 `test` 会兼容为 develop/测试环境。未显式配置 `APP_ENV_LABEL` 时,健康检查会按环境输出“本地环境”“测试环境”或“生产环境”。如果改用 `.env.local`、`.env.test` 或 `.env.production` 启动,也需要包含同样的 `JWT_SECRET` 和 `JWT_EXPIRES_IN`。
|
||||
|
||||
## 启动步骤
|
||||
|
||||
@@ -315,7 +318,7 @@ curl http://127.0.0.1:3500/health # 生产
|
||||
pnpm build:dev
|
||||
```
|
||||
|
||||
命令执行完成后会得到最新的 `dist/`。如果需要压缩上传,由部署者手动选择要打包的文件;测试构建可执行 `pnpm build:test`,正式生产构建时执行 `pnpm build:pro`。
|
||||
命令执行完成后会得到最新的 `dist/`。如果需要压缩上传,由部署者手动选择要打包的文件;develop/测试构建可执行 `pnpm build:develop` 或兼容命令 `pnpm build:test`,正式生产构建时执行 `pnpm build:pro`。
|
||||
|
||||
## 环境构建约定
|
||||
|
||||
@@ -330,14 +333,17 @@ pnpm build:dev
|
||||
| `pnpm dev` | 使用现有 `.env.development` 启动开发服务,并通过 `tsx watch` 监听代码变化。 | 日常开发接口时使用。 |
|
||||
| `pnpm build` | 使用 `tsc` 编译 TypeScript,输出到 `dist/`。 | 准备运行编译产物或发布前验证时使用。 |
|
||||
| `pnpm build:dev` | 清空旧 `dist/`,再执行 `pnpm build` 生成新的 `dist/`。 | 准备开发/测试服务器部署产物时使用。 |
|
||||
| `pnpm build:test` | 清空旧 `dist/`,再执行 `pnpm build` 生成新的 `dist/`。 | 准备测试环境部署产物时使用。 |
|
||||
| `pnpm build:develop` | 清空旧 `dist/`,再执行 `pnpm build` 生成新的 `dist/`。 | 准备 develop/测试环境部署产物时使用。 |
|
||||
| `pnpm build:test` | `pnpm build:develop` 的兼容命令。 | 旧测试环境脚本继续可用。 |
|
||||
| `pnpm build:pro` | 清空旧 `dist/`,再执行 `pnpm build` 生成新的 `dist/`。 | 准备生产环境部署产物时使用。 |
|
||||
| `pnpm start` | 使用现有 `.env.development` 运行 `dist/server.js`。 | 已经执行过 `pnpm build` 后,用编译产物启动服务。 |
|
||||
| `pnpm start:test` | 使用 `.env.test` 运行 `dist/server.js`。 | 服务器测试环境启动编译产物时使用。 |
|
||||
| `pnpm start:develop` | 使用 `.env.test` 运行 `dist/server.js`,其中 `APP_ENV=develop`。 | 服务器 develop/测试环境启动编译产物时使用。 |
|
||||
| `pnpm start:test` | `pnpm start:develop` 的兼容命令。 | 旧测试环境服务命令继续可用。 |
|
||||
| `pnpm start:prod` | 使用 `.env.production` 运行 `dist/server.js`。 | 服务器生产环境启动编译产物时使用。 |
|
||||
| `pnpm typecheck` | 执行 `tsc --noEmit`,只检查类型,不生成文件。 | 改 TypeScript 代码后快速确认类型是否正确。 |
|
||||
| `pnpm db:migrate` | 使用现有 `.env.development` 运行 `src/db/migrate.ts`,按顺序执行 `migrations/*.sql`。 | 第一次启动项目、拉到新迁移、改数据库结构后使用。 |
|
||||
| `pnpm db:migrate:test` | 使用 `.env.test` 运行 `dist/db/migrate.js`,按顺序执行 `migrations/*.sql`。 | 服务器测试环境建表、升级表结构或初始化基础数据时使用。 |
|
||||
| `pnpm db:migrate:develop` | 使用 `.env.test` 运行 `dist/db/migrate.js`,按顺序执行 `migrations/*.sql`。 | 服务器 develop/测试环境建表、升级表结构或初始化基础数据时使用。 |
|
||||
| `pnpm db:migrate:test` | `pnpm db:migrate:develop` 的兼容命令。 | 旧测试环境迁移命令继续可用。 |
|
||||
| `pnpm db:migrate:prod` | 使用 `.env.production` 运行 `dist/db/migrate.js`,按顺序执行 `migrations/*.sql`。 | 服务器生产环境建表、升级表结构或初始化基础数据时使用。 |
|
||||
| `pnpm db:shell` | 进入 Docker 容器里的 MySQL 命令行。 | 需要手动查看表结构或查询数据时使用。 |
|
||||
| `pnpm mysql:up` | 启动本地 MySQL 容器。 | 开发前先启动数据库。 |
|
||||
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
NODE_ENV=development
|
||||
APP_ENV=local
|
||||
APP_ENV_LABEL=本地环境
|
||||
PORT=3500
|
||||
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3307
|
||||
DB_USER=access_user
|
||||
DB_PASSWORD=replace-with-local-password
|
||||
DB_NAME=access_manage
|
||||
DB_CONNECTION_LIMIT=10
|
||||
|
||||
JWT_SECRET=replace-with-at-least-32-characters-local-secret
|
||||
JWT_EXPIRES_IN=2h
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
NODE_ENV=test
|
||||
APP_ENV=test
|
||||
APP_ENV=develop
|
||||
APP_ENV_LABEL=测试环境
|
||||
PORT=3501
|
||||
|
||||
|
||||
@@ -5,10 +5,12 @@ target_dir="${1:-$(pwd)}"
|
||||
deploy_env="${2:-production}"
|
||||
|
||||
case "${deploy_env}" in
|
||||
test)
|
||||
test|develop)
|
||||
mysql_env="${target_dir}/.env.test.mysql"
|
||||
app_env="${target_dir}/.env.test"
|
||||
node_env="test"
|
||||
app_env_name="develop"
|
||||
app_env_label="测试环境"
|
||||
app_port="${ACCESS_MANAGE_TEST_PORT:-3501}"
|
||||
mysql_port="${ACCESS_MANAGE_TEST_DB_PORT:-3308}"
|
||||
mysql_database="${ACCESS_MANAGE_TEST_DB_NAME:-access_manage_test}"
|
||||
@@ -17,12 +19,14 @@ case "${deploy_env}" in
|
||||
mysql_env="${target_dir}/.env.production.mysql"
|
||||
app_env="${target_dir}/.env.production"
|
||||
node_env="production"
|
||||
app_env_name="production"
|
||||
app_env_label="生产环境"
|
||||
app_port="${ACCESS_MANAGE_PRODUCTION_PORT:-3500}"
|
||||
mysql_port="${ACCESS_MANAGE_PRODUCTION_DB_PORT:-3307}"
|
||||
mysql_database="${ACCESS_MANAGE_PRODUCTION_DB_NAME:-access_manage}"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 [target_dir] [test|production]" >&2
|
||||
echo "Usage: $0 [target_dir] [test|develop|production]" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -74,8 +78,8 @@ jwt_secret="$(openssl rand -hex 48)"
|
||||
|
||||
cat > "${app_env}" <<EOF
|
||||
NODE_ENV=${node_env}
|
||||
APP_ENV=${node_env}
|
||||
APP_ENV_LABEL=$([[ "${deploy_env}" == "test" ]] && echo "测试环境" || echo "生产环境")
|
||||
APP_ENV=${app_env_name}
|
||||
APP_ENV_LABEL=${app_env_label}
|
||||
PORT=${app_port}
|
||||
|
||||
DB_HOST=127.0.0.1
|
||||
|
||||
+6
-3
@@ -7,14 +7,17 @@
|
||||
"dev": "DOTENV_CONFIG_PATH=.env.development tsx watch src/server.ts",
|
||||
"build": "tsc",
|
||||
"build:dev": "rm -rf dist && pnpm build",
|
||||
"build:test": "rm -rf dist && pnpm build",
|
||||
"build:develop": "rm -rf dist && pnpm build",
|
||||
"build:test": "pnpm build:develop",
|
||||
"build:pro": "rm -rf dist && pnpm build",
|
||||
"start": "DOTENV_CONFIG_PATH=.env.development node dist/server.js",
|
||||
"start:test": "DOTENV_CONFIG_PATH=.env.test node dist/server.js",
|
||||
"start:develop": "DOTENV_CONFIG_PATH=.env.test node dist/server.js",
|
||||
"start:test": "pnpm start:develop",
|
||||
"start:prod": "DOTENV_CONFIG_PATH=.env.production node dist/server.js",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"db:migrate": "DOTENV_CONFIG_PATH=.env.development tsx src/db/migrate.ts",
|
||||
"db:migrate:test": "DOTENV_CONFIG_PATH=.env.test node dist/db/migrate.js",
|
||||
"db:migrate:develop": "DOTENV_CONFIG_PATH=.env.test node dist/db/migrate.js",
|
||||
"db:migrate:test": "pnpm db:migrate:develop",
|
||||
"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",
|
||||
"mysql:up": "docker compose up -d mysql",
|
||||
|
||||
+18
-4
@@ -5,9 +5,9 @@ import { z } from "zod";
|
||||
// 这样数据库密码、端口等配置错误会在服务启动阶段暴露,而不是等到请求进来才失败。
|
||||
const envSchema = z.object({
|
||||
NODE_ENV: z
|
||||
.enum(["local", "development", "test", "production"])
|
||||
.enum(["local", "development", "test", "develop", "production"])
|
||||
.default("development"),
|
||||
APP_ENV: z.enum(["local", "development", "test", "production"]).optional(),
|
||||
APP_ENV: z.enum(["local", "development", "test", "develop", "production"]).optional(),
|
||||
APP_ENV_LABEL: z.string().min(1).optional(),
|
||||
PORT: z.coerce.number().int().positive().default(3000),
|
||||
|
||||
@@ -31,9 +31,23 @@ if (!result.success) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const rawAppEnv = result.data.APP_ENV ?? result.data.NODE_ENV;
|
||||
const resolvedAppEnv =
|
||||
rawAppEnv === "production"
|
||||
? "production"
|
||||
: rawAppEnv === "test" || rawAppEnv === "develop"
|
||||
? "develop"
|
||||
: "local";
|
||||
const defaultAppEnvLabel =
|
||||
{
|
||||
local: "本地环境",
|
||||
develop: "测试环境",
|
||||
production: "生产环境"
|
||||
}[resolvedAppEnv] ?? resolvedAppEnv;
|
||||
|
||||
// 其他模块只从 env 读取已校验过的值,不再直接访问 process.env。
|
||||
export const env = {
|
||||
...result.data,
|
||||
APP_ENV: result.data.APP_ENV ?? result.data.NODE_ENV,
|
||||
APP_ENV_LABEL: result.data.APP_ENV_LABEL ?? result.data.NODE_ENV
|
||||
APP_ENV: resolvedAppEnv,
|
||||
APP_ENV_LABEL: result.data.APP_ENV_LABEL ?? defaultAppEnvLabel
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user