# TheBet365 项目启动指南

本文档汇总本地开发、首次部署与日常启动所需的全部步骤与配置说明。

---

## 一、环境要求

| 工具 | 版本要求 | 说明 |
|------|----------|------|
| **Node.js** | ≥ 20 | 见根目录 `package.json` → `engines` |
| **pnpm** | 8+（推荐最新） | Monorepo 包管理，需先 `corepack enable` 或全局安装 |
| **Docker** | 最新稳定版（可选） | 推荐：一键起 PostgreSQL；也可用本机安装的 Postgres |
| **PostgreSQL** | 14+（推荐 16） | **必需**（API / Prisma） |
| **Git** | 任意 | 拉取代码 |

> 当前 API **仅依赖 PostgreSQL**；`docker-compose` 里的 Redis 为预留，未安装 Redis 一般不影响本地开发。

可选：

- **Docker Compose** v2（`docker compose`，非旧版 `docker-compose`）
- Windows 用户建议使用 PowerShell 或 Windows Terminal

---

## 二、仓库结构速览

```
thebet365/
├── apps/
│   ├── api/          NestJS 后端（Prisma + PostgreSQL）
│   ├── admin/        管理后台（平台管理员 + 代理，:5174）
│   └── player/       玩家 H5 前台（:5173）
├── packages/
│   └── shared/       共享类型与静态资源（public）
├── uploads/          上传文件目录（Banner 等，API 静态托管）
├── docker-compose.yml
├── .env.example      环境变量模板
└── package.json      根脚本（dev / db:*）
```

---

## 三、首次启动（完整流程）

按顺序执行，**只需做一次**（或换机器 / 清空数据库后重做）。

### 1. 克隆并进入项目

```bash
git clone https://gitea.dengshikj.com/ysc/thebet365.git
cd thebet365
```

私有库 SSH 与服务器认证见 **第八节 8.3**。

### 2. 启动数据库（二选一）

#### 方案 A：Docker（已安装 Docker Desktop 时）

```bash
docker compose up -d
docker compose ps
```

| 服务 | 容器名 | 端口 | 默认账号 |
|------|--------|------|----------|
| PostgreSQL 16 | `thebet365-postgres` | `5432` | 用户/密码/库：`thebet365` |
| Redis 7 | `thebet365-redis` | `6379` | 无密码（可选） |

`apps/api/.env` 使用：

```env
DATABASE_URL=postgresql://thebet365:thebet365@localhost:5432/thebet365
```

停止：`docker compose down` · 清空数据卷（慎用）：`docker compose down -v`

**Windows 未识别 `docker` 命令时**：安装 [Docker Desktop for Windows](https://www.docker.com/products/docker-desktop/)，安装后重启 PowerShell，并确保设置里已勾选 **Use WSL 2**（推荐）。也可用 winget：

```powershell
winget install Docker.DockerDesktop
```

#### 方案 B：本机 PostgreSQL（无 Docker）

1. 安装 PostgreSQL 16（任选其一）：
   - https://www.postgresql.org/download/windows/
   - 或 `winget install PostgreSQL.PostgreSQL.16`
2. 安装时记住 **超级用户密码**（默认用户常为 `postgres`）。
3. 用 **pgAdmin** 或 `psql` 创建与项目一致的数据库（也可改用你自己的账号，同步改 `DATABASE_URL`）：

```sql
CREATE USER thebet365 WITH PASSWORD 'thebet365';
CREATE DATABASE thebet365 OWNER thebet365;
GRANT ALL PRIVILEGES ON DATABASE thebet365 TO thebet365;
```

4. 编辑 `apps/api/.env`：

```env
DATABASE_URL=postgresql://thebet365:thebet365@localhost:5432/thebet365
```

若只用默认 `postgres` 用户：

```env
DATABASE_URL=postgresql://postgres:你的密码@localhost:5432/thebet365
```

（需已 `CREATE DATABASE thebet365;`）

5. 确认本机 **5432** 端口 Postgres 服务已启动（Windows「服务」里 `postgresql-x64-16` 为「正在运行」）。

### 3. 安装依赖

在**仓库根目录**执行：

```bash
pnpm install
```

### 4. 配置环境变量

将根目录模板复制到 API 目录（Nest 从 `apps/api` 工作目录读取 `.env`）：

```bash
cp .env.example apps/api/.env
```

`apps/api/.env` 主要项说明：

| 变量 | 示例值 | 说明 |
|------|--------|------|
| `DATABASE_URL` | `postgresql://thebet365:thebet365@localhost:5432/thebet365` | 须与 docker-compose 一致 |
| `REDIS_URL` | `redis://localhost:6379` | 预留，与 compose 中 Redis 对应 |
| `JWT_SECRET` | 长随机字符串 | **生产环境务必修改** |
| `JWT_PLAYER_EXPIRES` | `24h` | 玩家 Token 有效期 |
| `JWT_ADMIN_EXPIRES` | `2h` | 管理员 Token |
| `JWT_AGENT_EXPIRES` | `8h` | 代理 Token |
| `PORT` | `3000` | API 监听端口 |
| `NODE_ENV` | `development` | 开发环境 |
| `UPLOAD_DIR` | 留空 | 默认使用 `apps/api/uploads`；可填绝对路径 |

### 5. 数据库迁移与种子数据

仍在**仓库根目录**：

```bash
pnpm db:generate   # 生成 Prisma Client（改 schema 后需要）
pnpm db:migrate    # 执行迁移（开发环境，可交互命名）
pnpm db:seed       # 演示账号、赛事、世界杯 48 强夺冠盘等
```

生产环境部署迁移使用：

```bash
pnpm --filter @thebet365/api db:migrate:deploy
```

可视化查看数据（可选）：

```bash
pnpm db:studio
```

### 6. 启动开发服务

**方式 A：一键启动全部**（API + admin + player + shared 编译监听）

```bash
pnpm dev
```

**方式 B：分终端启动**（推荐调试时）

```bash
# 终端 1 — 必须先起 API
pnpm dev:api

# 终端 2 — 管理后台
pnpm dev:admin

# 终端 3 — 玩家前台
pnpm dev:player
```

> `dev:manage` 与 `dev:admin` 相同，均为管理后台。

---

## 四、访问地址

| 应用 | 地址 | 说明 |
|------|------|------|
| **API** | http://localhost:3000/api | 全局前缀 `api` |
| **Swagger** | http://localhost:3000/api/docs | 接口文档 |
| **玩家前台** | http://localhost:5173 | Vite 代理 `/api` → `:3000` |
| **管理后台** | http://localhost:5174 | Vite 代理 `/api` → `:3000` |
| **静态上传** | http://localhost:3000/uploads/... | 玩家端也可经 `:5173/uploads` 代理 |

前端开发时**无需单独配置 CORS**，Vite 已将 `/api`（玩家端含 `/uploads`）反向代理到 API。

---

## 五、演示账号与默认数据

`pnpm db:seed` 写入账号、赛事、48 强夺冠、Banner 等。**完整清单**见 **[默认数据说明.md](./默认数据说明.md)**。

| 角色 | 用户名 | 密码 | 登录入口 |
|------|--------|------|----------|
| 平台管理员 | `admin` | `Admin@123` | 管理后台 http://localhost:5174 |
| 一级代理 | `agent1` | `Agent@123` | 同上（菜单为代理端） |
| 二级代理 | `agent2` | `Agent@123` | 同上 |
| 玩家 | `player1` | `Player@123` | 玩家前台 http://localhost:5173 |

管理端：`POST /api/manage/auth/login` · 玩家端：`POST /api/player/auth/login`

---

## 六、根目录常用命令

| 命令 | 作用 |
|------|------|
| `pnpm dev` | 并行启动各 app 的 `dev` 脚本 |
| `pnpm dev:api` | 仅 API（watch） |
| `pnpm dev:admin` | 仅管理后台 |
| `pnpm dev:player` | 仅玩家前台 |
| `pnpm build` | 构建所有 workspace 包 |
| `pnpm test` | 运行各包测试 |
| `pnpm db:generate` | Prisma Client 生成 |
| `pnpm db:migrate` | 开发迁移 |
| `pnpm db:seed` | 种子数据（含 WC2026 48 强夺冠） |
| `pnpm db:studio` | Prisma Studio |
| `pnpm pack:deploy` | 生成 zip 部署包（无 Git 时备用，见 `pack.mjs`） |

---

## 七、业务数据与上传目录

详见 **[默认数据说明.md](./默认数据说明.md)**（赛事、盘口、48 强夺冠、player1 余额与注单、Banner 等）。

- 上传目录默认：`apps/api/uploads/`（可由 `UPLOAD_DIR` 覆盖）

---

## 八、服务器生产部署（Docker + Git）

生产环境推荐：**服务器用 Git 拉代码 + Docker Compose 全栈部署**，不必每次本地打 zip 上传。

完整架构与端口说明见 **[Docker部署指南.md](./Docker部署指南.md)**。

### 8.1 服务器要求

| 项目 | 要求 |
|------|------|
| 系统 | Linux（阿里云 ECS + 宝塔面板常见） |
| Docker | 24+，Compose v2（`docker compose`） |
| 内存 | 建议 ≥ 2 GB（首次构建较耗内存） |
| 代码目录 | 例如 `/www/wwwroot/thebet365` |

### 8.2 首次部署（Git 克隆）

在服务器 **宝塔 → 终端** 或 SSH 中执行：

```bash
cd /www/wwwroot

# 1. 若已有 zip 解压的旧目录，先备份配置并改名
cp thebet365/.env.docker /root/thebet365.env.docker.bak 2>/dev/null || true
mv thebet365 thebet365.bak 2>/dev/null || true

# 2. 从 Gitea 克隆（地址按你的仓库为准）
git clone https://gitea.dengshikj.com/ysc/thebet365.git thebet365

cd thebet365

# 3. 恢复或创建生产环境配置
cp /root/thebet365.env.docker.bak .env.docker 2>/dev/null || cp .env.docker.example .env.docker
```

编辑 `.env.docker`，**生产务必修改**：

| 变量 | 说明 |
|------|------|
| `POSTGRES_PASSWORD` | 数据库密码 |
| `JWT_SECRET` | 足够长的随机字符串 |
| `SEED_DATABASE` | 生产建议保持 `false`，首次部署脚本会按需一次性 seed |

构建并启动（首次约 10～20 分钟，**勿提前关终端**）：

```bash
cd /www/wwwroot/thebet365
chmod +x scripts/*.sh
./scripts/deploy-first.sh
```

查看状态（须带 `--env-file .env.docker`）：

```bash
docker compose -f docker-compose.prod.yml --env-file .env.docker ps
```

成功时应看到 5 个容器均为 `Up`：

- `thebet365-postgres`、`thebet365-redis`、`thebet365-api`、`thebet365-player`、`thebet365-admin`

访问（将 `你的IP` 换成服务器公网 IP，并在安全组/防火墙放行端口）：

| 应用 | 地址 |
|------|------|
| 玩家前台 | `http://你的IP:8082` |
| 管理后台 | `http://你的IP:8081` |

生产 compose 不公网映射 API 端口，玩家端/管理端容器会通过内部 Docker 网络访问 API。

### 8.3 Gitea 私有仓库认证

私有库克隆/拉取前需配置认证。**推荐 SSH**（配一次，以后 `git pull` 无需密码）。

#### 方式 A：SSH 密钥（推荐）

在**服务器**执行：

```bash
# 1. 生成密钥（无 passphrase，便于自动拉代码）
ssh-keygen -t ed25519 -C "aliyun-thebet365" -f ~/.ssh/id_ed25519 -N ""

# 2. 查看公钥（整行复制）
cat ~/.ssh/id_ed25519.pub

# 3. 测试连接（首次输入 yes）
ssh -T git@gitea.dengshikj.com
```

在 **Gitea 网页**：头像 → **设置** → **SSH / GPG 密钥** → **添加密钥**，粘贴公钥。

使用 SSH 地址克隆：

```bash
git clone git@gitea.dengshikj.com:ysc/thebet365.git thebet365
```

已用 HTTPS 克隆时可改远程地址：

```bash
cd /www/wwwroot/thebet365
git remote set-url origin git@gitea.dengshikj.com:ysc/thebet365.git
```

#### 方式 B：HTTPS + Access Token

1. Gitea → **设置** → **应用 / Access Tokens** → 生成令牌（勾选 `read:repository`）
2. 克隆时 **Password 填 Token**，不是登录密码：

```bash
git clone https://gitea.dengshikj.com/ysc/thebet365.git thebet365
```

记住凭据（避免每次 `git pull` 输入）：

```bash
git config --global credential.helper store
cd /www/wwwroot/thebet365
git pull   # 再输一次用户名 + Token
```

| 对比 | SSH | HTTPS + Token |
|------|-----|----------------|
| 推荐场景 | 服务器长期部署 | 临时测试 |
| 体验 | 配好后免密 | 需 credential.helper |

### 8.4 日常更新（不用打 zip）

**本地开发机：**

```bash
git add .
git commit -m "你的修改说明"
git push
```

**服务器（宝塔终端）：**

```bash
cd /www/wwwroot/thebet365
./scripts/deploy-update.sh --pull
```

- 更新脚本会先备份数据库与 uploads，再构建新镜像、执行 Prisma 迁移、替换容器并等待健康检查
- 使用离线镜像包时推荐 `./scripts/deploy-update.sh --images thebet365-images-<tag>.tar --tag <tag>`，发布状态会记录到 `.deploy/current-release.env`
- **不要**把 `.env.docker` 提交到 Git；服务器上单独保留
- `release/*.zip` 为旧打包方式，Git 同步后不必再生成上传

若 `git pull` 冲突且可接受覆盖为远程版本：

```bash
git fetch origin
git reset --hard origin/main
# 再确认 .env.docker 仍在
```

### 8.5 部署状态检查

```bash
cd /www/wwwroot/thebet365

# 容器是否在跑
docker compose -f docker-compose.prod.yml --env-file .env.docker ps

# 容器启动失败时看日志
docker compose -f docker-compose.prod.yml --env-file .env.docker logs --tail=30 player
docker compose -f docker-compose.prod.yml --env-file .env.docker logs --tail=30 api

# 本机探测（在服务器上）
curl -I http://127.0.0.1:8082
```

**`ps` 为空**：说明从未成功部署，或构建被中断 — 重新执行 8.2 中的 `./scripts/deploy-first.sh`。

**终端被关掉**：构建可能仍在后台跑，也可能已失败；用上面命令查 `ps` 和容器日志。

### 8.6 从 zip 迁移到 Git（一次性）

若目录原是 zip 解压、没有 `.git`：

```bash
cd /www/wwwroot
cp thebet365/.env.docker /root/thebet365.env.docker.bak
mv thebet365 thebet365.bak
git clone git@gitea.dengshikj.com:ysc/thebet365.git thebet365   # 或 HTTPS
cd thebet365 && cp /root/thebet365.env.docker.bak .env.docker
```

### 8.7 宿主机 + Nginx（可选）

不用 Docker 全栈时：

```bash
pnpm install
pnpm build
pnpm --filter @thebet365/api start
# 前端产物在 apps/*/dist，由 Nginx 托管并反代 /api
```

生产务必：`JWT_SECRET`、数据库密码、`db:migrate:deploy`、`NODE_ENV=production`。

---

## 九、常见问题

### 1. PowerShell 提示「无法将 docker 识别为 cmdlet」

- 未安装 Docker，或未加入 PATH → 用上文 **方案 B 本机 PostgreSQL**，或安装 Docker Desktop 后重启终端。

### 2. `P3015` / `Could not find the migration file at migration.sql`

- 原因：`apps/api/prisma/migrations/` 下某个迁移目录缺少 `migration.sql`（例如空的 `20260602120000_user_preference_contact`）。
- 处理：拉取最新代码后重试 `pnpm db:migrate`；若本地曾误删该文件，需从仓库恢复或删除空目录后重新 `prisma migrate dev`。
- 说明：若 `pnpm db:seed` 已成功，说明表结构多半已可用，可先 `pnpm dev:api` 开发；仍建议修好 migrate 以便团队协作。

**若修复文件后提示 Drift detected（库里有字段但迁移历史未记录）**，在 `apps/api` 下将已存在的迁移标记为已应用（不删数据）：

```bash
cd apps/api
pnpm exec prisma migrate resolve --applied 20260602120000_user_preference_contact
pnpm exec prisma migrate resolve --applied 20260603102323_zhibo_match_fields
pnpm db:migrate
```

仍无法收敛且可接受清空库时：`pnpm exec prisma migrate reset`（会删库），再 `pnpm db:seed`。

### 3. `pnpm db:migrate` 连接数据库失败

- Docker 方案：确认 `docker compose up -d` 且 Postgres 健康  
- 本机方案：确认 PostgreSQL 服务已启动、库 `thebet365` 已创建  
- 检查 `apps/api/.env` 中 `DATABASE_URL` 主机/端口/账号/密码

### 4. 管理后台文案显示为 key（如 `user.field.xxx`）

- 勿在 `apps/admin/src` 下保留误生成的 `*.js`（会抢先于 `.ts` 被 Vite 加载）  
- 清理缓存后重启：`apps/admin/node_modules/.vite`  
- 硬刷新浏览器（Ctrl+Shift+R）

### 5. 前端接口 502 / 代理错误

- 必须先启动 `pnpm dev:api`，再开 admin/player

### 6. `agent-form` 等模块导出报错

- 同上，删除 `apps/admin/src` 内过期 `.js`，重启 dev server

### 7. 夺冠盘不足 48 队

```bash
pnpm db:seed
```

或在管理后台 **优胜冠军 → 导入世界杯 48 强**。

### 8. Windows 下 Prisma / ts-node 权限问题

- 以管理员运行终端，或关闭占用 `5432` 端口的其他 Postgres 实例

### 9. 服务器 `docker compose ps` 为空

- 未加 `--env-file .env.docker` 时可能看不到本项目容器，请用：  
  `docker compose -f docker-compose.prod.yml --env-file .env.docker ps`
- 若仍为空：构建未完成或失败，重新执行 `./scripts/deploy-first.sh`，见 **第八节 8.5**
- 构建失败原因以部署脚本当前终端输出为准；容器启动失败再看 `docker compose logs`

### 10. 服务器 player 构建报 `ENOENT ... public/球员`

- 原因：旧版中文目录 `packages/shared/public/球员/` 在 Linux 编码异常；或 zip 覆盖解压后残留旧目录
- 处理：确保 `git pull` 到最新（含 `packages/shared/public/players/`），并清理：

```bash
find packages/shared/public -mindepth 1 -maxdepth 1 -type d \
  ! -name flags ! -name players -exec rm -rf {} +
docker compose -f docker-compose.prod.yml --env-file .env.docker build --no-cache player admin
./scripts/deploy-update.sh --no-build
```

### 11. 宝塔 Redis 里看到 `lottery-database-*` 等 key

- 那是**宿主机上其他项目**（彩票系统）的数据，与 thebet365 Docker 内 `thebet365-redis` **不是同一个实例**
- 查看本项目 Redis：`docker exec -it thebet365-redis redis-cli KEYS '*'`

### 12. player 启动失败 `8080: bind: address already in use`

- 宝塔/同机其他项目常占用 8080；本项目默认玩家端口已改为 **8082**
- 服务器 `.env.docker` 设置 `PLAYER_PORT=8082`，并放行安全组/防火墙该端口
- 重启：`docker compose -f docker-compose.prod.yml --env-file .env.docker up -d player`

### 13. API 反复重启，`seed.ts` / `run-seed` 找不到

- 原因：生产镜像只有编译后的 `dist`，`prisma db seed` 用 `ts-node` 需要 `src/` 源码
- 已改为 entrypoint 执行 `node dist/infrastructure/database/seed-cli.js`；拉代码后重建 api 镜像
- **临时绕过**（先让 API 起来）：`.env.docker` 设 `SEED_DATABASE=false` 后 `up -d api`

### 14. player/admin 重启，`host not found in upstream "api"`

- 原因：nginx 启动时 API 容器尚未就绪，静态 `proxy_pass http://api:3000` 解析失败
- 已改为 Docker DNS + 变量延迟解析；重建 player/admin 镜像
- **临时处理**（API 已 Up 时）：`docker compose ... restart player`

---

```text
1. docker compose up -d
2. pnpm dev:api          # 等 API 打印 running
3. pnpm dev:admin      # 或 pnpm dev:player
4. 浏览器打开对应端口
```

改 Prisma schema 后：

```text
pnpm db:generate && pnpm db:migrate
```

---

## 十一、相关文档

- [README.md](../README.md) — 项目概览与技术栈  
- [Docker部署指南.md](./Docker部署指南.md) — Docker 全栈生产部署  
- [默认数据说明.md](./默认数据说明.md) — seed 后的账号、赛事、夺冠盘、运营内容  
- [apps/admin/README.md](../apps/admin/README.md) — 管理后台结构  
- [足球投注平台产品需求与MVP实施计划_PRD_v1.2.md](../足球投注平台产品需求与MVP实施计划_PRD_v1.2.md) — 产品需求（若存在）

---

*文档随仓库脚本与端口变更时请同步更新。*
