# order_site

快手自动发货与履约管理系统。

前后端分离架构：接收外部订单、按规则匹配发货平台、生成统一领取链接，并提供后台做平台配置、任务追踪和人工复核。

## 技术栈

| 层 | 技术 |
| --- | --- |
| 前端 | React 19、Vite 8、Ant Design 6、React Router 7、TanStack Query、TypeScript |
| 后端 | Node.js、Express 5、TypeScript、PostgreSQL、node-pg-migrate |
| 网关 | Caddy |
| 运行 | Docker Compose（开发 / 生产分离） |

## 目录结构

```text
apps/
  backend/                  后端 API、任务编排、平台对接、数据库迁移
    src/
      db/migrations/        SQL 迁移（001 基线 + 后续渐进增量）
    data/                   本地运行数据与平台配置（敏感，默认不提交）
  frontend/                 React 管理后台 + 用户领取页
deploy/
  caddy/                    Caddy 反向代理
  docker/                   前后端 Dockerfile
  mac-dev.sh / ubuntu-deploy.sh
docs/                       平台接口、履约链路、部署说明
docker-compose.dev.yml      本地 Docker 开发环境
docker-compose.yml          生产 / 服务器 Compose
```

## 业务边界（简图）

```text
91 卡券进单
  → 本系统建单 / 匹配商品 / 创建履约任务
  → 返回统一 claimUrl
用户打开领取页
  → 可选：快手行业电子凭证自动核销
  → kuaishou-cloud / kuaishou-feifei / 人工 完成发货
后台
  → 订单任务、平台配置、审计、人工复核
接单平台（打手众包）
  → 工单发布到抢单大厅，打手抢单代练
  → 提交验收 / 问题单处置 / 任务时限超时自动判定
```

更完整的链路说明见：`docs/履约配置/多发货平台与电子凭证整体链路.md`。

## 本地开发

推荐直接用 Docker，本机不必单独装 Node / PostgreSQL。

```bash
cp .env.mac-docker.example .env
docker compose -f docker-compose.dev.yml up -d --build
```

常用入口：

| 入口 | 地址 |
| --- | --- |
| 前端 / 后台 / 领取页 | `http://localhost` |
| 后端健康检查 | `http://localhost/health` |
| 后端就绪检查 | `http://localhost/health/ready` |
| 后端 API 前缀 | `http://localhost/api/v1/...` |

常用命令：

```bash
docker compose -f docker-compose.dev.yml ps
docker compose -f docker-compose.dev.yml logs -f backend
docker compose -f docker-compose.dev.yml logs -f frontend
docker compose -f docker-compose.dev.yml down
```

Mac 也可使用：

```bash
bash deploy/mac-dev.sh
```

## 开发验证

以容器内执行为准：

```bash
docker compose -f docker-compose.dev.yml exec -T backend npm test
docker compose -f docker-compose.dev.yml exec -T backend npm run format:check
docker compose -f docker-compose.dev.yml exec -T backend npm run typecheck
docker compose -f docker-compose.dev.yml exec -T backend npm run build
docker compose -f docker-compose.dev.yml exec -T frontend npm test
docker compose -f docker-compose.dev.yml exec -T frontend npm run format:check
docker compose -f docker-compose.dev.yml exec -T frontend npm run typecheck
docker compose -f docker-compose.dev.yml exec -T frontend npm run build
```

### 本地推送检查

本项目不使用 Gitea Actions。需要在本机推送前自动执行前后端检查时，启用本地 Git hook：

```bash
bash scripts/install-git-hooks.sh
```

启用后，每次 `git push` 会依次执行 `apps/backend` 和 `apps/frontend` 的 `npm run check`。
仅临时跳过检查时使用：

```bash
SKIP_CHECKS=1 git push
```

## 数据库迁移

采用 **基线 + 渐进增量** 策略，由 `node-pg-migrate` 管理，记录表为 `schema_migrations`。

| 文件 | 含义 |
| --- | --- |
| `001_init.sql` | 空库基线，建立完整业务结构 |
| `002_xxx.sql` ~ `009_xxx.sql` | 后续结构变更的增量 SQL（含接单平台 004~009） |

约定：

1. **不要修改**已经应用到共享/生产环境的历史迁移文件。
2. 结构变更一律新增迁移文件，不要回写 `001_init.sql`。
3. 空库按序号依次执行 `001 → 002 → …`；已有库只执行尚未记录的增量。
4. 后端启动时自动 `up`；也可手动执行。

常用命令（容器内）：

```bash
# 查看本地文件与数据库对齐状态
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate:status

# 手动执行未应用迁移
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate

# 创建下一份增量迁移（示例）
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate:create -- add_task_priority
```

宿主机直连开发库（注意主机名）：

```bash
cd apps/backend
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/order_site npm run db:migrate:status
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/order_site npm run db:migrate
```

本地需要清空数据重建库时（会丢开发数据）：

```bash
docker compose -f docker-compose.dev.yml down
docker volume rm order_site_postgres_dev_data
docker compose -f docker-compose.dev.yml up -d --build
```

更多说明见 `docs/部署启动与数据库重建.md`。

## 环境变量

本地：

```bash
cp .env.mac-docker.example .env
```

生产：

```bash
cp .env.server.example .env
```

常用变量：

| 变量 | 说明 |
| --- | --- |
| `APP_DOMAIN` / `CADDY_SITE_ADDR` | 后台与领取页域名、Caddy 主站监听地址 |
| `WORKER_SITE_ADDR` | 打手端独立域名，如 `https://worker.khhao.com` |
| `CLAIM_BASE_URL` | 领取页完整前缀，如 `https://域名/#/claim` |
| `CLAIM_TOKEN_TTL_HOURS` | 领取链接有效期（小时）；`0` 表示长期有效，正整数表示限时 |
| `DATABASE_URL` | PostgreSQL 连接串（容器内主机名用 `postgres`） |
| `ADMIN_SESSION_SECRET` | 后台登录态签名密钥 |
| `ADMIN_DEFAULT_USERS_JSON` | 默认后台用户 |
| `KAQUAN91_USER_ID` / `KAQUAN91_SECRET` | 91 卡券开放接口凭据 |

## 运行数据

| 环境 | 路径 / Volume |
| --- | --- |
| 本地后端配置与日志 | `apps/backend/data` |
| 本地 PostgreSQL | Docker volume `postgres_dev_data` |
| 生产后端数据 | `apps/backend/data`（与本地路径一致） |
| 生产 PostgreSQL | Docker volume `postgres_data` |
| 生产 Caddy | Docker volume `caddy_data` |

注意：`apps/backend/data/*.json` 可能含账号、Cookie、token 等敏感信息，默认不进仓库；只保留 `*.example.json` 模板。

## 生产部署

```bash
cp .env.server.example .env
# 编辑真实配置后：
mkdir -p apps/backend/data
sudo chown -R 1001:1001 apps/backend/data
docker compose up -d --build
```

Ubuntu 一键脚本：

```bash
bash deploy/ubuntu-deploy.sh
```

首次若无 `.env`，脚本会从示例生成模板并退出；填好后再执行一次即可。脚本会检查 Docker、占位配置、数据目录权限，构建启动并等待健康检查。

常用参数：

| 参数 | 说明 |
| --- | --- |
| `--skip-backup` | 跳过部署前的自动数据库备份（默认每次部署都会先 `pg_dump` 再上传 OSS，数据量较大时耗时明显）。仅代码改动、无 schema 变更时可加；涉及数据库迁移或 `--reset-db` 前建议保留备份 |
| `--reset-db` | 删除 PostgreSQL 数据卷后按 migrations 全量重建（执行前会自动抓取最后一份备份） |
| `--yes` | 跳过 `--reset-db` 的交互确认（等价于 `RESET_DB_CONFIRM=1`） |

`--skip-backup` 也可用环境变量 `SKIP_BACKUP=true bash deploy/ubuntu-deploy.sh` 代替。备份与恢复的完整说明见 `docs/数据库备份与恢复.md`。

生产入口示例：

- 前端与领取页：`https://你的域名/`
- 健康检查：`https://你的域名/health`
- API：`https://你的域名/api/v1/...`

生产 Compose 会：启动 PostgreSQL → 后端自动迁移 → 初始化默认管理员 → 同步履约目录 → Caddy 暴露前端与 API。

## 主要模块

| 路径 | 职责 |
| --- | --- |
| `apps/backend/src/routes` | 开放接口 / 领取 / 后台 API |
| `apps/backend/src/routes/worker` | 打手端 API（抢单大厅、我的订单、验收） |
| `apps/backend/src/services/order` | 订单入库、商品匹配、任务同步 |
| `apps/backend/src/services/fulfillment` | 履约路由与执行器（cloud / feifei / 人工） |
| `apps/backend/src/services/worker-platform` | 接单平台业务（工单、等级、押金结算、超时扫描） |
| `apps/backend/src/services/platforms` | 外部平台对接 |
| `apps/backend/src/services/admin` | 后台鉴权、读写、配置 |
| `apps/backend/src/services/scheduler` | 定时任务（云账号健康检查、工单超时扫描） |
| `apps/backend/src/repositories` | 数据访问 |
| `apps/backend/src/db/migrations` | 数据库迁移 |
| `apps/frontend/src/pages/admin` | 管理后台页面 |
| `apps/frontend/src/pages/worker` | 打手端页面（大厅、我的订单、个人中心） |
| `apps/frontend/src/pages/claim` | 用户领取页 |

## 接单平台（打手众包）

用于将部分订单转为打手代练任务，与主履约流程解耦：

| 能力 | 说明 |
| --- | --- |
| 抢单大厅 | 打手按分类/关键词筛选，实时刷新、冻结押金抢单；拼单工单按份参与 |
| 我的订单 | 代练中 / 待验收 / 问题单流转，提交验收支持图片粘贴与拖拽 |
| 任务时限 | 工单可配置时限，超时由定时扫描 + 接口惰性判定双重处置（退回大厅 / 取消退押金 / 取消扣押金），并统计每个打手的超时订单数 |
| 等级权限 | VIP 等级体系：免押额度、最大同时接单量、大厅可见延迟 |
| 资金 | 押金冻结 / 退还 / 扣除流水，充值申请与提现审核 |
| 物品规则 | 按商品/SKU 匹配自动生成工单，可继承默认时限与拼单配置 |
| 管理后台 | 接单工单 CRUD、打手账号管理、问题单处置、定时任务管理，功能标签页记忆上次选择 |

说明：

- 打手通过**手机号验证码注册**并设置密码，注册后直接可用；登录使用手机号 + 密码。
- 短信默认 Mock 模式（验证码打印到服务日志），生产配置 `WORKER_SMS_PROVIDER=aliyun` + 阿里云凭据后走真实短信。
- 来源订单同步由物品规则驱动（`syncWorkerOrdersForSourceOrder`）。
- 工单状态机独立于主履约任务：`pending_material → unassigned → open → in_progress → pending_acceptance → accepted / cancelled`，另有 `problem`。
- 超时扫描定时任务默认 60 秒执行一次（配置见后台"平台配置 → 定时任务"）。

## 提交前检查

```bash
docker compose -f docker-compose.dev.yml exec -T backend npm run check
docker compose -f docker-compose.dev.yml exec -T frontend npm run check
```

代码格式由仓库根目录的 Prettier 配置统一管理。修改代码后可在对应应用目录执行
`npm run format`，提交前使用 `npm run format:check` 只检查、不修改文件。

确认：

- 未提交真实账号、Cookie、token、手机号或生产配置
- `.env` 未入库
- **结构变更的 migration 与业务代码同 PR 提交**
- 领取链接相关改动已在 Docker 环境验证
