# 配置说明

## 环境变量总表

后端所有配置通过 `server/.env` 文件管理（通过 dotenv 加载）。下表列出全部变量：

| 变量名 | 用途 | 示例值 | 必填 | 默认值 |
|--------|------|--------|------|--------|
| `NODE_ENV` | 运行环境 | `development` / `production` | 否 | `development` |
| `PORT` | 监听端口 | `3000` | 否 | `3000` |
| `DB_HOST` | MySQL 主机地址 | `127.0.0.1` | 是 | 无 |
| `DB_PORT` | MySQL 端口 | `3306` | 否 | `3306` |
| `DB_USER` | MySQL 用户名 | `root` | 否 | `root` |
| `DB_PASSWORD` | MySQL 密码 | `mypassword` | 是 | 无 |
| `DB_NAME` | 数据库名 | `jw_beauty` | 否 | `jw_beauty` |
| `WECHAT_APPID` | 微信小程序 AppID | `wxc4045074ef298510` | 生产必填 | 无 |
| `WECHAT_SECRET` | 微信小程序 AppSecret | `abcdef1234567890...` | 生产必填 | 无 |
| `JWT_SECRET` | 用户 JWT 签名密钥 | `a-long-random-string` | 生产必填 | `dev-user-secret` |
| `ADMIN_JWT_SECRET` | 管理员 JWT 签名密钥 | `another-long-random-string` | 生产必填 | `dev-admin-secret` |
| `ADMIN_USERNAME` | 初始管理员用户名 | `admin` | 否 | `admin` |
| `ADMIN_PASSWORD` | 初始管理员密码 | `strongpassword` | 生产必填 | `admin` |
| `TENCENT_SECRET_ID` | 腾讯云 API SecretId | `AKIDxxxx` | COS 功能需要 | 无 |
| `TENCENT_SECRET_KEY` | 腾讯云 API SecretKey | `xxxx` | COS 功能需要 | 无 |
| `TENCENT_REGION` | 腾讯云默认地域 | `ap-guangzhou` | 否 | `ap-guangzhou` |
| `COS_BUCKET` | COS 存储桶名称 | `jw-bucket-1426323813` | 否 | `jw-bucket-1426323813` |
| `COS_REGION` | COS 存储桶地域 | `ap-guangzhou` | 否 | 同 `TENCENT_REGION` |
| `COS_CDN_DOMAIN` | COS CDN 加速域名 | `tx.vsai.net.cn` | 否 | `tx.vsai.net.cn` |

### 生产环境安全检查

当 `NODE_ENV=production` 时，服务启动会强制检查以下条件，不满足则拒绝启动：

- `JWT_SECRET` 不能是默认值 `dev-user-secret`
- `ADMIN_JWT_SECRET` 不能是默认值 `dev-admin-secret`
- `ADMIN_USERNAME` 和 `ADMIN_PASSWORD` 不能是默认值 `admin`

## 微信配置

### 获取 WECHAT_APPID 和 WECHAT_SECRET

1. 登录 [微信公众平台](https://mp.weixin.qq.com/) -> 开发管理 -> 开发设置
2. AppID(小程序ID) 即为 `WECHAT_APPID`
3. AppSecret(小程序密钥) 即为 `WECHAT_SECRET`（需要管理员扫码后才能查看，只显示一次）

```ini
WECHAT_APPID=wxc4045074ef298510
WECHAT_SECRET=你的AppSecret
```

### 开发环境

本地开发时不填这两个值也能运行，但微信登录（`wx.login` -> `code2Session`）会失败。此时可以通过 mock 端点绕过。

## 数据库配置

### 本地开发

```ini
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=root
DB_PASSWORD=你的本地MySQL密码
DB_NAME=jw_beauty
```

使用 Docker 快速启动 MySQL：

```bash
docker run -d \
  --name jw-mysql \
  -p 3306:3306 \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  -e MYSQL_DATABASE=jw_beauty \
  mysql:8.0 \
  --character-set-server=utf8mb4 \
  --collation-server=utf8mb4_unicode_ci
```

然后 `.env` 中填：

```ini
DB_HOST=127.0.0.1
DB_PASSWORD=rootpass
```

### 腾讯云 TencentDB

SCF 函数部署时，需要将函数放在与 TencentDB 同一 VPC/子网中：

```ini
DB_HOST=10.0.0.x     # VPC 内网地址
DB_PORT=3306
DB_USER=root
DB_PASSWORD=腾讯云数据库密码
DB_NAME=jw_beauty
```

### 数据库表结构

共 10 张表（定义在 `server/sql/schema.sql`）：

| 表名 | 说明 |
|------|------|
| `users` | 小程序用户，openid 唯一索引 |
| `devices` | 美容仪设备，device_id 为主键 |
| `bindings` | 用户-设备绑定关系 |
| `subscriptions` | 用户订阅记录（月卡/年卡） |
| `treatment_records` | 护理记录，含时长、模式、光密度等 |
| `device_events` | 设备事件日志（错误、告警等） |
| `device_commands` | 下发给设备的远程指令 |
| `operation_logs` | 操作审计日志 |
| `admin_accounts` | 管理员账号 |
| `system_settings` | 系统设置键值对（定价、功能开关等） |
| `firmware_files` | 固件版本记录 |

初始化时会自动插入默认系统设置：月卡 99 元、年卡 899 元、试用 7 天等。

## COS 配置

COS（对象存储）用于存储用户头像和固件文件，通过 CDN 域名对外提供访问。

```ini
TENCENT_SECRET_ID=AKIDxxxx          # 腾讯云控制台 -> 访问管理 -> API密钥管理
TENCENT_SECRET_KEY=xxxx
COS_BUCKET=jw-bucket-1426323813     # 存储桶名称（含 APPID 后缀）
COS_REGION=ap-guangzhou             # 存储桶所在地域
COS_CDN_DOMAIN=tx.vsai.net.cn       # CDN 加速域名（可选，不填有默认值）
```

### 获取密钥

1. 登录 [腾讯云控制台](https://console.cloud.tencent.com/)
2. 访问管理 -> API 密钥管理 -> 新建密钥
3. 复制 SecretId 和 SecretKey

> 建议创建子用户，只授予 COS 相关权限，不要使用主账号密钥。

### 本地开发

不配置 COS 相关变量时，头像上传和固件上传功能会报错，但不影响其他功能开发。

## 安全配置

### JWT_SECRET

用于签发用户端 JWT token，有效期 7 天。生成方法：

```bash
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
```

将输出填入 `.env`：

```ini
JWT_SECRET=生成的64位十六进制字符串
```

### ADMIN_JWT_SECRET

用于签发管理后台 JWT token，必须与 `JWT_SECRET` 不同。用同样的方法生成：

```bash
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
```

```ini
ADMIN_JWT_SECRET=另一个64位十六进制字符串
```

### 管理员初始密码

`npm run db:init` 会使用 `.env` 中的 `ADMIN_USERNAME` 和 `ADMIN_PASSWORD` 创建管理员账号（bcrypt 哈希存储）。

```ini
ADMIN_USERNAME=admin
ADMIN_PASSWORD=一个强密码
```

> 生产环境不能使用默认值 `admin/admin`，服务启动时会报错退出。

### CORS

当前 CORS 设置为 `Access-Control-Allow-Origin: *`（见 `server/src/app.js`），允许所有来源。这是开发阶段的配置，生产环境应收紧为具体域名。

允许的自定义请求头：

```
Content-Type, Authorization, X-Device-Id, X-App-Version, X-Platform
```

## 小程序配置

### env.js

文件路径：`miniprogram/config/env.js`

```js
var ENV = 'test'    // 可选值：local / test / prod

var API_BASES = {
  local: 'http://localhost:3000',
  test: 'https://api.vsai.net.cn',
  prod: 'https://api.vsai.net.cn'
}

var __DEV__ = ENV !== 'prod'
```

#### ENV 取值说明

| 值 | API 地址 | `__DEV__` | 说明 |
|----|---------|-----------|------|
| `local` | `http://localhost:3000` | `true` | 本地开发 |
| `test` | `https://api.vsai.net.cn` | `true` | 连接测试环境 |
| `prod` | `https://api.vsai.net.cn` | `false` | 生产环境 |

#### `__DEV__` 的作用

当 `__DEV__` 为 `true` 时：

- 启用 mock 绑定设备（无需蓝牙握手）
- 启用 mock 购买订阅（无需微信支付）
- 可能显示额外的调试信息

发布正式版时务必将 `ENV` 设为 `prod`。

### project.config.json

文件中的 `appid` 字段需要与实际的小程序 AppID 一致：

```json
{
  "appid": "wxc4045074ef298510",
  "projectname": "hox-beauty"
}
```

如果没有该 AppID 权限，在微信开发者工具中可以选择测试号。

## 管理后台配置

### env.js

文件路径：`admin-console/src/config/env.js`

```js
const ENV = 'test'    // 可选值：local / test / prod

const API_BASES = {
  local: 'http://localhost:3000',
  test: 'https://api.vsai.net.cn',
  prod: 'https://api.vsai.net.cn'
}
```

与小程序的 `env.js` 功能一致，本地开发时改为 `local`。

### Vite base path

`admin-console/vite.config.js` 配置了 base 路径：

```js
export default defineConfig({
  base: process.env.PUBLIC_PATH || '/admin/',
  plugins: [uni()]
})
```

- 默认 base 为 `/admin/`，意味着所有静态资源路径都会加上 `/admin/` 前缀
- 部署到 COS 后通过 `https://你的域名/admin/` 访问
- 本地开发时访问地址为 `http://localhost:5173/admin/`
- 如需改变路径前缀，设置环境变量 `PUBLIC_PATH`：

```bash
PUBLIC_PATH=/console/ npm run build:h5
```

### 构建与部署

```bash
# 开发
npm run dev

# 构建 H5 产物
npm run build:h5

# 构建并部署到 COS
npm run deploy:cos
```

`deploy:cos` 脚本会将 `dist/build/h5/` 目录的文件上传到 COS 存储桶，需要在 `server/.env`（或管理后台自己的 `.env`）中配置好 `TENCENT_SECRET_ID`、`TENCENT_SECRET_KEY`、`COS_BUCKET` 等变量。
