# 萌芽小店 · 生产环境部署指南

> 覆盖生产环境部署要点：后端目录为 **`mengyastore-backend-go`**，配置以 **环境变量** 为主（与本地 `.env` / `.env.production` 一致），无需再依赖 `config.json`。

---

## 目录

1. [环境要求](#1-环境要求)
2. [准备 MySQL](#2-准备-mysql)
3. [部署后端（Docker）](#3-部署后端docker)
4. [构建并部署前端](#4-构建并部署前端)
5. [Nginx 反向代理](#5-nginx-反向代理)
6. [验证部署](#6-验证部署)
7. [常见问题](#7-常见问题)
8. [升级与回滚](#8-升级与回滚)

---

## 1. 环境要求

| 组件 | 说明 |
|------|------|
| Linux 服务器 | Ubuntu 22.04 / Debian 12 等 |
| Docker 24+、Compose v2 | `docker compose version` |
| MySQL 8.x | 可内网独立实例 |
| Nginx 1.20+ | 静态资源 + `/api/` 反代 |
| Node.js 18+ | 仅前端 **构建** 时使用 |

可选：内网 **RabbitMQ**、**Redis**（与 `docker-compose` / 环境变量一致即可）。

---

## 2. 准备 MySQL

表结构由后端 **GORM AutoMigrate** 自动创建，只需 **建库 + 授权**：

```sql
CREATE DATABASE IF NOT EXISTS `mengyastore`
  CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'mengyastore'@'%' IDENTIFIED BY 'your_strong_password';
GRANT ALL PRIVILEGES ON `mengyastore`.* TO 'mengyastore'@'%';
FLUSH PRIVILEGES;
```

也可参考仓库内 `mengyastore-backend-go/init.sql`。

---

## 3. 部署后端（Docker）

### 3.1 代码路径

```bash
git clone https://github.com/shumengya/mengyastore.git   # 或你的仓库
cd mengyastore/mengyastore-backend-go
```

> 若历史文档写成 `mengyastore-backend`，请改为 **`mengyastore-backend-go`**。

### 3.2 配置方式（推荐）

生产 **不要** 把真实口令写进 Git。任选其一：

- **A.** 在宿主机导出环境变量后执行 `docker compose up`（Compose 中 `${VAR:-默认值}` 会读取宿主机环境）。
- **B.** 在服务器的 `mengyastore-backend-go/` 放置 **`.env`**（勿提交），并在 `docker-compose.yml` 中增加 `env_file: .env`（若你自行加上该条目）；当前仓库默认 compose **未挂载** `.env`，请通过 **environment** 或 **export** 注入。

**必填 / 常用变量（与 `internal/config/config.go` 一致）：**

| 变量 | 说明 |
|------|------|
| `APP_ENV` | `production` |
| `DATABASE_DSN` | 生产 MySQL 连接串 |
| `ADMIN_TOKEN` | 管理后台令牌（强随机） |
| `AUTH_API_URL` | SproutGate 认证网关 Base URL |
| `RABBITMQ_ENABLED` | `true` / `false` |
| `RABBITMQ_URL` | 启用 MQ 时完整 `amqp://…`（或用各 `RABBITMQ_*` 拼装，见配置注释） |
| `REDIS_ENABLED` | `true` / `false` |
| `REDIS_ADDR`、`REDIS_PASSWORD`、`REDIS_DB` | 启用 Redis 探测/缓存时 |
| `HTTP_LISTEN_ADDR` | 可选，默认容器内 `:8080` |
| `PUBLIC_API_BASE_URL` | 可选，管理端「系统状态」展示的对外 API 基址（反代 HTTPS 时建议设） |

根据业务关闭不需要的中间件时，将 `RABBITMQ_ENABLED` 或 `REDIS_ENABLED` 设为 `false`，避免无实例仍去连接。

### 3.3 修改 `docker-compose.yml`

部署前请 **核对并本地化**：

- `DATABASE_DSN` 指向你的库。
- `ports`（示例 `28081:8080`）是否与 Nginx `proxy_pass` 一致。
- **删除或替换** 仓库中带默认口令的示例值；通过宿主机环境注入生产密钥。

示例（**仅结构示意，口令用环境变量**）：

```yaml
services:
  backend:
    build: { context: . }
    container_name: mengyastore-backend
    ports:
      - "28081:8080"
    environment:
      APP_ENV: production
      GIN_MODE: release
      TZ: Asia/Shanghai
      DATABASE_DSN: ${DATABASE_DSN}
      ADMIN_TOKEN: ${ADMIN_TOKEN}
      AUTH_API_URL: ${AUTH_API_URL:-}
      REDIS_ENABLED: ${REDIS_ENABLED:-false}
      REDIS_ADDR: ${REDIS_ADDR:-}
      REDIS_PASSWORD: ${REDIS_PASSWORD:-}
      RABBITMQ_ENABLED: ${RABBITMQ_ENABLED:-false}
      RABBITMQ_ENV: prod
      RABBITMQ_URL: ${RABBITMQ_URL:-}
    restart: unless-stopped
```

### 3.4 启动

```bash
cd /opt/mengyastore/mengyastore-backend-go   # 你的实际路径
export DATABASE_DSN='...'
export ADMIN_TOKEN='...'
# … 其他变量按需 export
docker compose up -d --build
docker compose logs -f
```

预期日志含：`[DB] 数据库连接成功，表结构已同步`、`萌芽小店后端启动于 http://localhost:8080`。

### 3.5 健康检查

```bash
curl -s http://127.0.0.1:28081/api/health
curl -s http://127.0.0.1:28081/api/products
```

---

## 4. 构建并部署前端

```bash
cd mengyastore-frontend
npm ci || npm install
```

**同源部署**（Nginx 把 `/api/` 反代到后端）：构建前可不设 `VITE_API_BASE_URL`，打包后请求会走当前站点域名。

**前后端不同域**：创建 `.env.production`：

```env
VITE_API_BASE_URL=https://你的-api-域名
```

```bash
npm run build
```

将 `dist/` 同步到服务器，例如 `/var/www/mengyastore/`：

```bash
rsync -avz --delete dist/ user@server:/var/www/mengyastore/
```

---

## 5. Nginx 反向代理

```nginx
server {
    listen 80;
    server_name your-domain.com;
    root /var/www/mengyastore;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location /api/ {
        proxy_pass http://127.0.0.1:28081;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 30s;
        proxy_read_timeout 60s;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2|webmanifest)$ {
        expires 7d;
        add_header Cache-Control "public, immutable";
    }
}
```

HTTPS 可使用 `certbot --nginx` 签发 Let's Encrypt。

---

## 6. 验证部署

- [ ] 首页与商品列表正常。
- [ ] SproutGate 登录后收藏、聊天、我的订单可用。
- [ ] **Logo 连点 5 次** → 管理员验证 → 带 `?token=` 或使用 `X-Admin-Token` 访问后台。
- [ ] 后台 **系统状态**：MySQL / Redis / RabbitMQ（若启用）显示合理。
- [ ] 商品：**卡密** 与 **固定内容** 两种类型可分别保存；固定内容商品前台库存显示「不限」。
- [ ] 下一单：结算页金额、收款码区、**复制订单号**、确认后内容与邮件/MQ 预期一致（依你的 SMTP/MQ 配置）。
- [ ] PWA 可安装（如需要）。

---

## 7. 常见问题

**CORS / 白屏**  
确认 Nginx `location /api/` 指向后端端口，且容器 `docker compose ps` 为运行中。

**管理 Token 无效**  
核对容器内实际生效的 `ADMIN_TOKEN`（与前端输入一致）。当前项目 **不再依赖** `config.json`。

**RabbitMQ 报 504 / channel closed**  
服务端已实现重连与消费重启；若仍异常，查 Broker 日志、网络与 `RABBITMQ_URL`/vhost/权限。

**数据库连不上**  
在宿主机用 `mysql` 客户端测 `DATABASE_DSN` 同款主机端口账号；Docker 网络须能访问 MySQL。

**站点设置 KV 查询**  
后端对缺失的 `site_settings` 键使用不产生「record not found」噪声的查询方式；首次保存 SMTP 等后会写入库表。

---

## 8. 升级与回滚

```bash
cd mengyastore-backend-go
git pull
docker compose up -d --build
docker compose logs -f --tail=100
```

回滚：保留上一版本的镜像 tag 或 git tag，重新 `docker compose up` 指定旧镜像（视你实际镜像命名而定）。

---

## 附：目录结构示例

```
/opt/mengyastore/
  mengyastore-backend-go/
    docker-compose.yml
    Dockerfile
    .env                 ← 仅存服务器本地，勿提交 Git
    ...

/var/www/mengyastore/    ← 前端 dist
  index.html
  assets/
```

部署完成后访问你的域名即可。
