# 劳动用工合规助手 — 产品需求文档 (PRD)

> **文档编号**: 1-prd.md  
> **版本**: v1.0  
> **日期**: 2026-07-23  
> **状态**: 草案  
> **依据**: 0-req.md v3.0 需求规格说明书

---

## 1. 产品概述

### 1.1 产品定位

面向中小企业的**极简用工合规 SaaS 工具**，聚焦劳动仲裁三大高发领域（合同签订、工资加班费、解聘），辅以 AI 合规顾问，帮助企业事前预防、事中管控、事后追溯用工风险。

### 1.2 产品愿景

> 「让每个中小企业都有一个用得起的劳动法顾问」

### 1.3 核心价值主张

| 价值 | 说明 |
|------|------|
| 极简易用 | 三看三不用原则，不需要培训，打开就会用 |
| 自动合规 | 风险自动检测 + 人话提示，不用懂法也能合规 |
| AI 顾问 | 通义千问驱动，随时问、自动查、提前预警 |
| 安全可靠 | SaaS 云端存储，数据隔离，多设备访问 |

### 1.4 目标用户

| 用户角色 | 企业规模 | 使用频率 | 核心诉求 |
|---------|---------|---------|---------|
| 老板兼管 HR | 10-30人 | 每周1-2次 | 快速了解风险，解聘时算钱 |
| 行政兼 HR | 30-80人 | 每天5分钟 | 合同到期提醒，每月算加班费 |
| 初级 HR | 80-200人 | 日常使用 | 合同管理，工资计算，解聘流程 |

---

## 2. 用户故事

### 2.1 认证与注册

| 编号 | 用户故事 | 验收标准 |
|------|---------|---------|
| US-AUTH-01 | 作为企业管理者，我想注册账号，这样我就能开始使用系统管理用工合规 | 输入企业名称+手机号+密码 → 创建组织+管理员账号 → 自动登录跳转首页 |
| US-AUTH-02 | 作为用户，我想用手机号和密码登录，这样我能安全访问我的数据 | 输入手机号+密码 → 校验通过 → 返回 JWT Token → 跳转首页 |
| US-AUTH-03 | 作为管理员，我想添加 HR 用户，这样我的同事也能操作系统 | 设置页 → 用户管理 → 输入姓名+手机号+角色 → 创建成功 |
| US-AUTH-04 | 作为用户，我想找回密码，这样我忘记密码时还能登录 | 忘记密码 → 输入手机号 → 验证码重置 → 重新登录 |

### 2.2 首页风险总览

| 编号 | 用户故事 | 验收标准 |
|------|---------|---------|
| US-HOME-01 | 作为用户，我想打开首页就知道有没有风险，这样我不用到处翻找 | 顶部一句话：「今天有 X 件事需要处理」 |
| US-HOME-02 | 作为用户，我想看到具体待办事项，这样我知道该先处理什么 | 待办列表：信号灯+一句话描述+「去处理」按钮 |
| US-HOME-03 | 作为用户，我想看到风险分布，这样我知道哪类问题最多 | 进度条展示合同/工资/解聘三类风险数量 |
| US-HOME-04 | 作为用户，当没有风险时我想看到安心提示，这样我知道一切正常 | 显示绿色「✅ 暂无风险，继续保持！」 |
| US-HOME-05 | 作为用户，我想看到 AI 风险预测，这样我能提前防范 | 首页下方展示 AI 预测的未来30天风险卡片 |

### 2.3 合同管理

| 编号 | 用户故事 | 验收标准 |
|------|---------|---------|
| US-CON-01 | 作为 HR，我想添加员工和合同信息，这样系统帮我管理合规 | 添加按钮 → 分步表单（基本信息→合同信息）→ 保存成功 |
| US-CON-02 | 作为 HR，我想看到所有员工的合同状态，这样我一眼就知道谁有问题 | 列表5列：姓名/部门/入职日期/合同状态(信号灯)/操作 |
| US-CON-03 | 作为 HR，当合同即将到期时我想收到提醒，这样我不会忘记续签 | 到期前30天列表出现「续签」按钮 + 首页待办提醒 |
| US-CON-04 | 作为 HR，我想一键续签合同，这样我不用填一堆表单 | 点击「续签」→ 弹窗确认期限+签订方式 → 确认 → 状态变绿 |
| US-CON-05 | 作为 HR，我想选择纸质或电子合同签订方式，这样符合实际操作 | 添加/续签时可选「纸质合同」或「电子合同」 |
| US-CON-06 | 作为 HR，当员工入职很久没签合同时我想被提醒，这样避免双倍工资赔偿 | 入职超1个月未签 → 🔴 红色状态 + 首页待办 |
| US-CON-07 | 作为 HR，我想搜索员工，这样快速找到某人的合同 | 搜索框输入姓名 → 实时筛选列表 |
| US-CON-08 | 作为 HR，我想批量续签即将到期的合同，这样不用一个个点 | 全选 → 批量续签 → 弹窗确认 → 批量更新 |

### 2.4 钱的计算

| 编号 | 用户故事 | 验收标准 |
|------|---------|---------|
| US-MONEY-01 | 作为 HR，我想计算加班费，这样我知道该付多少 | 输入月工资+加班小时数 → 实时显示各类加班费明细+合计 |
| US-MONEY-02 | 作为 HR，当加班超过法定上限时我想被提醒，这样避免违法 | 月加班超36小时 → 结果区显示黄色警告 |
| US-MONEY-03 | 作为 HR，我想计算未签合同的双倍工资，这样我知道风险金额 | 输入月工资+入职日期+签订状态 → 显示起止日期+赔偿金额 |
| US-MONEY-04 | 作为 HR，我想计算经济补偿金，这样解聘时知道该赔多少 | 输入入职/离职日期+月工资+原因 → 显示工作年限+补偿金+赔偿金(×2) |
| US-MONEY-05 | 作为 HR，我想关联员工自动填入工资，这样不用手动输入 | 选择员工 → 月工资自动填入 |

### 2.5 解聘助手

| 编号 | 用户故事 | 验收标准 |
|------|---------|---------|
| US-TERM-01 | 作为 HR，我想一步步完成解聘流程，这样不会漏掉步骤 | 5步向导：选原因→选员工→合规检查→算钱→确认 |
| US-TERM-02 | 作为 HR，当解聘原因不同时我想看到对应的检查项，这样有针对性 | Step 3 根据Step 1选择动态展示检查项 |
| US-TERM-03 | 作为 HR，当员工属于禁止解聘情形时我想被警告，这样避免违法解聘 | 选员工后自动检查孕期/工伤/医疗期 → 红色警告弹窗 |
| US-TERM-04 | 作为 HR，我想看到解聘历史记录，这样可以追溯 | 解聘助手页面底部展示历史记录列表 |
| US-TERM-05 | 作为 HR，即使有未通过检查项我也想保存记录，这样尊重我的决策 | Step 5 显示红色警告但不阻止保存 |

### 2.6 AI 合规顾问

| 编号 | 用户故事 | 验收标准 |
|------|---------|---------|
| US-AI-01 | 作为用户，我想用大白话问劳动法问题，这样不用自己查法条 | 聊天界面输入问题 → AI 流式回答 + 法律依据 + 关联本企业数据 |
| US-AI-02 | 作为用户，我想看到 AI 预测的未来风险，这样提前防范 | 首页 AI 风险预测卡片，展示未来30天预计风险 |
| US-AI-03 | 作为 HR，我想让 AI 审查合同条款，这样知道有没有违法 | 粘贴/上传合同文本 → 逐条审查 + 红/黄/绿标注 + 合规评分 |
| US-AI-04 | 作为 HR，我想匹配相似仲裁案例，这样评估败诉风险 | 输入争议情况 → 展示相似案例 + 败诉概率 + 赔偿预估 |
| US-AI-05 | 作为用户，AI 回答时我想看到打字机效果，这样体验更好 | SSE 流式输出，逐字显示 |

### 2.7 系统设置

| 编号 | 用户故事 | 验收标准 |
|------|---------|---------|
| US-SET-01 | 作为管理员，我想设置企业地区，这样系统用对的最低工资标准 | 设置→企业信息→选择城市 → 自动填入最低工资/社平工资默认值 |
| US-SET-02 | 作为管理员，我想管理用户和权限，这样控制谁能看谁能改 | 设置→用户管理→添加/移除用户→分配角色 |
| US-SET-03 | 作为管理员，我想查看当前套餐和人数限制，这样知道是否需要升级 | 设置→套餐信息→显示当前套餐+已用人数+上限 |

### 2.8 员工端

| 编号 | 用户故事 | 验收标准 |
|------|---------|---------|
| US-EMP-01 | 作为员工，我想用手机号+密码登录，这样不用等验证码 | 输入手机号+密码→登录成功→跳转工资条 |
| US-EMP-02 | 作为员工，我想用手机号+验证码登录，这样不用记密码 | 输入手机号→获取验证码→输入验证码→登录成功→跳转工资条 |
| US-EMP-03 | 作为员工，我想扫描 HR 发的二维码直接进入员工端，这样不用手动输入网址 | 扫码→打开员工端登录页→选择登录方式→登录 |
| US-EMP-04 | 作为员工，我想查看月度工资条，这样知道工资明细 | 选择月份→显示基本工资+加班费拆分+应发合计 |
| US-EMP-05 | 作为员工，我想确认已阅工资条，这样 HR 知道我看过了 | 点击「确认已阅」→记录时间+IP→HR端显示已确认 |
| US-EMP-06 | 作为员工，我想查看我的合同信息，这样了解合同条款 | 我的合同页→显示合同类型/期限/试用期/工资/扫描件 |
| US-EMP-07 | 作为员工，HR 发二维码让我填报入职信息，这样不用 HR 手动录入 | 扫码→填写姓名/身份证/银行卡等→提交→HR审核入库 |
| US-EMP-08 | 作为员工，HR 发二维码让我确认电子合同，这样完成签署确认 | 扫码→查看合同内容→勾选确认→点击签署→记录时间+IP |
| US-EMP-09 | 作为 HR，我想生成入职填报二维码发给员工，这样通过微信即可发送 | 添加员工时选「生成填报二维码」→显示二维码+链接→保存图片/复制链接 |
| US-EMP-10 | 作为 HR，我想生成合同确认二维码发给员工，这样完成电子合同签署 | 合同详情→生成确认二维码→微信发给员工→员工确认后状态自动更新 |
| US-EMP-11 | 作为 HR，我想查看员工工资条确认状态，这样知道谁还没看 | 合同/工资管理→显示各员工确认状态（已确认/未确认） |

---

## 3. 用户流程

### 3.1 新用户注册流程

```
访问网站 → 注册页
  │
  ├─ 输入企业名称
  ├─ 输入手机号
  ├─ 输入密码
  ├─ 点击注册
  │
  ├─ 创建 Organization + Admin User
  ├─ 自动登录，返回 JWT Token
  │
  └─ 跳转首页（空状态）
       │
       ├─ 显示新手引导弹窗（3步）
       └─ 显示「添加第一个员工」引导卡片
```

### 3.2 日常使用流程

```
登录 → 首页风险总览
  │
  ├─ 有待办？ → 点击「去处理」→ 跳转对应模块 → 处理 → 返回首页
  │
  ├─ 无待办？ → 查看AI风险预测 → 了解未来风险
  │
  └─ 日常操作：
       ├─ 合同管理 → 添加员工/续签/查看详情
       ├─ 钱的计算 → 切换Tab计算加班费/双倍工资/补偿金
       ├─ 解聘助手 → 5步向导完成解聘
       └─ AI顾问 → 问答/合同审查/案例匹配
```

### 3.3 合同到期续签流程

```
首页待办显示「🟡 XX合同还有20天到期」
  │
  └─ 点击「去续签」→ 合同管理页
       │
       └─ 点击「续签」→ 弹窗
            │
            ├─ 确认新期限（默认3年）
            ├─ 选择签订方式（默认沿用上次）
            ├─ 确认新到期日
            │
            └─ 点击「确认续签」
                 │
                 ├─ 更新合同记录
                 ├─ 状态变 🟢 正常
                 ├─ 风险项自动消除
                 └─ 首页待办减少
```

### 3.4 解聘流程

```
解聘助手 → Step 1: 选择解聘原因
  │
  └─ Step 2: 选择员工
       │
       ├─ 自动检查禁止解聘情形
       ├─ 触发？→ 红色警告 → 用户确认继续
       │
       └─ Step 3: 合规检查（根据原因动态展示）
            │
            └─ Step 4: 自动计算补偿金
                 │
                 └─ Step 5: 确认汇总
                      │
                      ├─ 有未通过项？→ 红色警告（不阻止）
                      ├─ 点击保存
                      │
                      └─ 生成解聘记录
                           ├─ 员工状态变更为离职
                           ├─ 记录存档
                           └─ 审计日志记录
```

### 3.5 AI 智能问答流程

```
AI顾问页 → 输入问题（或点击预设问题）
  │
  ├─ 前端构建上下文：
  │    ├─ 当前企业数据摘要（员工数/风险项/合同状态）
  │    └─ RAG 检索相关法律条文
  │
  ├─ 调用 DashScope API（qwen-plus）
  │
  ├─ SSE 流式返回
  │    ├─ 逐字显示回答
  │    └─ 显示完成后附法律依据（可折叠）
  │
  └─ 支持多轮对话（保留上下文）
```

### 3.6 员工入职填报流程

```
HR 管理端 → 添加员工 → 选择「生成填报二维码」
  │
  ├─ 生成一次性 token（24h 有效）
  ├─ 页面显示二维码图片 + 可复制链接
  │
  └─ HR 通过微信发送给员工（二维码图片或链接）
       │
       └─ 员工扫码/点击链接 → 填报页面
            │
            ├─ 填写姓名/手机号/身份证/银行卡等
            ├─ 提交
            │
            └─ 信息进入「待审核」状态
                 │
                 └─ HR 管理端收到通知
                      │
                      ├─ 审核 → 通过 → 正式入库
                      │          ├─ 创建 Employee 记录
                      │          └─ token 失效
                      │
                      └─ 审核 → 驳回 → 员工重新填报
```

### 3.7 电子合同签署确认流程

```
HR 管理端 → 录入电子合同 → 点击「生成确认二维码」
  │
  ├─ 生成一次性 token（7天有效）
  ├─ 页面显示二维码图片 + 可复制链接
  │
  └─ HR 通过微信发送给员工（二维码图片或链接）
       │
       └─ 员工扫码/点击链接 → 合同确认页面
            │
            ├─ 查看合同内容（类型/期限/试用期/工资）
            ├─ 查看合同文件（如有链接）
            ├─ 勾选「我已阅读，确认签署」
            ├─ 点击「确认签署」
            │
            └─ 系统记录：确认时间 + IP + 设备信息
                 │
                 └─ HR 端合同状态自动更新为「已确认签署」
                      ├─ token 失效
                      └─ 审计日志记录
```

---

## 4. 功能规格

### 4.1 认证模块

#### 4.1.1 注册

- **页面**: `/register`
- **输入**: 企业名称、手机号、密码（8位以上）、确认密码
- **校验**: 手机号格式、密码长度、手机号未被注册
- **处理**: 创建 Organization（plan=free, maxEmployees=20）+ User（role=admin）+ bcrypt 加密密码
- **输出**: JWT Token + 跳转首页
- **限流**: 同一 IP 每小时最多 5 次注册

#### 4.1.2 登录

- **页面**: `/login`
- **输入**: 手机号、密码
- **校验**: 手机号存在、密码匹配
- **输出**: Access Token（2h）+ Refresh Token（7d）
- **限流**: 同一 IP 每分钟最多 5 次登录

#### 4.1.3 Token 刷新

- **接口**: `POST /api/v1/auth/refresh`
- **输入**: Refresh Token
- **输出**: 新 Access Token
- **逻辑**: 校验 Refresh Token 有效性 → 签发新 Access Token

### 4.2 首页风险总览

#### 4.2.1 数据聚合接口

- **接口**: `GET /api/v1/dashboard`
- **返回数据**:
```json
{
  "success": true,
  "data": {
    "greeting": "早上好！今天有 3 件事需要处理",
    "stats": {
      "employeeCount": 12,
      "highRiskCount": 2,
      "todoCount": 3,
      "monthlyOvertimePay": 8000
    },
    "todos": [
      {
        "id": "risk_001",
        "level": "high",
        "title": "张三入职35天未签合同",
        "actionUrl": "/contracts?employee=张三"
      }
    ],
    "riskDistribution": {
      "contract": 5,
      "salary": 2,
      "termination": 1
    },
    "aiPrediction": {
      "risks": [...],
      "suggestion": "本周优先处理合同到期和未签问题"
    }
  }
}
```

#### 4.2.2 风险检测引擎

- **触发时机**: 数据变更时实时检测 + 每日凌晨定时全量扫描
- **检测规则**: 见 0-req.md 4.3.3 / 4.4.4 合规检查规则
- **风险生命周期**: `pending` → `resolved`（自动/手动）/ `ignored`（手动）

### 4.3 合同管理模块

#### 4.3.1 API 规格

| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 员工列表 | GET | `/api/v1/employees` | 支持分页、搜索、部门筛选 |
| 添加员工 | POST | `/api/v1/employees` | 含合同信息 |
| 员工详情 | GET | `/api/v1/employees/:id` | 含合同+风险信息 |
| 编辑员工 | PUT | `/api/v1/employees/:id` | 更新员工+合同信息 |
| 删除员工 | DELETE | `/api/v1/employees/:id` | 软删除（status=resigned） |
| 批量续签 | POST | `/api/v1/contracts/batch-renew` | 批量续签合同 |
| 上传附件 | POST | `/api/v1/contracts/:id/attachment` | 上传纸质合同扫描件 |

#### 4.3.2 合同状态自动计算

```
输入：signDate, startDate, endDate, contractType, renewalCount, hireDate
输出：status + statusText + riskLevel

逻辑：
  if signDate == null:
    daysSinceHire = today - hireDate
    if daysSinceHire > 365: → "已视为无固定期限" 🔴
    elif daysSinceHire > 30: → "未签合同(X天)" 🔴
    else: → "未签合同(X天)" 🟡
  elif endDate != null:
    daysToExpire = endDate - today
    if daysToExpire < 0: → "已到期未续签" 🔴
    elif daysToExpire <= 30: → "即将到期(X天)" 🟡
    else: → "正常" 🟢
  else:
    → "无固定期限" 🟢
```

#### 4.3.3 试用期合法性校验

```
规则（劳动合同法第19条）：
  合同期 < 3个月 → 不能约定试用期
  合同期 3个月~1年 → 试用期 ≤ 1个月
  合同期 1年~3年 → 试用期 ≤ 2个月
  合同期 ≥ 3年 → 试用期 ≤ 6个月

校验时机：添加/编辑合同时实时校验
校验失败：红色提示「X年期合同试用期最多Y个月，当前Z个月不合法」
```

### 4.4 钱的计算模块

#### 4.4.1 加班费计算

- **页面**: `/money` Tab 1
- **输入**: 月工资、工作日加班小时、休息日加班小时、节假日加班小时
- **计算**: 纯前端实时计算，无需调后端
- **公式**:
```
hourlyWage = monthlyWage / 21.75 / 8
weekdayPay = hourlyWage * 1.5 * weekdayHours
weekendPay = hourlyWage * 2.0 * weekendHours
holidayPay = hourlyWage * 3.0 * holidayHours
total = weekdayPay + weekendPay + holidayPay
```
- **预警**: 总加班小时 > 36 → 黄色警告

#### 4.4.2 双倍工资计算

- **页面**: `/money` Tab 2
- **输入**: 月工资、入职日期、合同签订日期（可选，默认未签订）
- **计算**: 纯前端实时计算
- **公式**:
```
if 未签订 or 签订日期 - 入职日期 > 30天:
  起算日 = 入职日 + 1个月
  截止日 = 入职日 + 1年（如未签订）或 签订日期
  月数 = min(截止日 - 起算日 的月数, 11)
  双倍工资差额 = 月工资 × 月数
```

#### 4.4.3 经济补偿金计算

- **页面**: `/money` Tab 3
- **输入**: 入职日期、离职日期、月平均工资、离职原因、当地社平工资（选填）
- **计算**: 纯前端实时计算
- **公式**:
```
工作年限 = (离职日期 - 入职日期) 转换为年月
  满1年 → 1个月工资
  满6个月不满1年 → 1个月工资
  不满6个月 → 0.5个月工资
补偿月数 = 向上取整(工作年限月数 / 12) 或 半月

if 社平工资 > 0 and 月工资 > 社平工资 × 3:
  月工资 = 社平工资 × 3
  补偿月数 = min(补偿月数, 12)

经济补偿金 = 月工资 × 补偿月数
违法解除赔偿金 = 经济补偿金 × 2
```

### 4.5 解聘助手模块

#### 4.5.1 解聘向导状态管理

```typescript
interface TerminationWizardState {
  step: 1 | 2 | 3 | 4 | 5;
  reason: 'negotiated' | 'fault' | 'nonfault' | 'layoff' | 'expired' | null;
  employeeId: string | null;
  terminationDate: string | null;
  checklist: {
    item: string;
    passed: boolean;
    remark?: string;
  }[];
  compensation: number;
  riskLevel: 'safe' | 'warning' | 'danger';
}
```

#### 4.5.2 动态检查项规则

| 解聘原因 | 检查项 |
|---------|--------|
| 协商解除 | 是否支付经济补偿金、是否签署协商解除协议 |
| 员工犯错 | 是否有规章制度依据、是否有证据材料、是否通知工会 |
| 员工没犯错但干不了 | 是否提前30天通知或支付代通知金、是否经过培训/调岗 |
| 公司裁员 | 是否提前30天向工会说明、是否听取职工意见、是否报劳动部门 |
| 合同到期不续签 | 是否提前通知、是否支付经济补偿金 |

#### 4.5.3 禁止解聘情形检查

- **触发**: Step 2 选择员工后自动检查
- **检查字段**: `employee.isPregnant` / `employee.isWorkInjured` / `employee.isInMedicalPeriod`
- **交互**: 弹出红色警告框 + 「我已了解风险，继续操作」确认按钮
- **不阻止流程**: 用户确认后可继续

### 4.6 AI 合规顾问模块

#### 4.6.1 智能问答

- **页面**: `/ai-assistant`
- **接口**: `POST /api/v1/ai/chat`（SSE 流式）
- **请求**:
```json
{
  "messages": [
    {"role": "user", "content": "试用期最长可以约定几个月？"}
  ],
  "context": {
    "orgId": "xxx",
    "employeeCount": 12,
    "riskItems": [...]
  }
}
```
- **后端处理**:
  1. 构建系统 Prompt（劳动法专家角色 + 人话风格要求）
  2. RAG 检索相关法律条文（pgvector 语义搜索）
  3. 注入企业数据上下文
  4. 调用 DashScope API（qwen-plus）
  5. SSE 流式返回前端
- **响应**: SSE 事件流
```
data: {"type": "chunk", "content": "根据"}
data: {"type": "chunk", "content": "《劳动合同法》"}
data: {"type": "chunk", "content": "第19条"}
...
data: {"type": "done", "legalBasis": "《劳动合同法》第19条"}
```

#### 4.6.2 风险预测

- **触发**: 每日凌晨定时任务 + 首页加载时读取缓存
- **接口**: `GET /api/v1/ai/prediction`
- **逻辑**:
  1. 查询未来30天将到期的合同
  2. 查询入职将满1年未签合同的员工
  3. 分析上月加班趋势变化
  4. 调用 LLM 生成优先级建议
- **缓存**: 结果存 Redis / 内存缓存，24h 有效

#### 4.6.3 合同审查

- **页面**: `/ai-assistant` 子 Tab
- **接口**: `POST /api/v1/ai/contract-review`
- **输入**: 合同文本（粘贴或文件上传解析）
- **后端处理**:
  1. 调用 qwen-max 分析合同条款
  2. 逐条标注红/黄/绿 + 修改建议
  3. 计算合规评分（0-100）
- **输出**:
```json
{
  "success": true,
  "data": {
    "score": 72,
    "items": [
      {"level": "red", "clause": "试用期6个月", "issue": "超过法定上限", "suggestion": "调整为2个月"},
      {"level": "yellow", "clause": "竞业限制", "issue": "未约定补偿标准", "suggestion": "约定月补偿不低于离职前12个月平均工资的30%"}
    ]
  }
}
```

#### 4.6.4 案例匹配

- **页面**: `/ai-assistant` 子 Tab
- **接口**: `POST /api/v1/ai/case-match`
- **输入**: 争议情况描述
- **后端处理**:
  1. 将描述向量化（DashScope text-embedding-v2）
  2. pgvector 检索相似案例（top 5）
  3. 调用 qwen-max 分析败诉概率和赔偿预估
- **输出**: 相似案例列表 + 败诉概率 + 赔偿预估 + 建议

#### 4.6.5 使用次数限制

- **中间件**: 每次 AI 请求前检查当月已用次数
- **计数**: Redis / 数据库按 `orgId + 月份 + 类型` 统计
- **超限**: 返回 `429 Too Many Requests` + 提示升级套餐

---

## 5. 页面规格

### 5.1 页面清单

**管理端**：

| 页面 | 路由 | 访问控制 | 布局 |
|------|------|---------|------|
| 登录 | `/login` | 公开 | 居中卡片 |
| 注册 | `/register` | 公开 | 居中卡片 |
| 忘记密码 | `/forgot-password` | 公开 | 居中卡片 |
| 风险总览 | `/` | 登录 | 顶部导航 + 主内容 |
| 合同管理 | `/contracts` | 登录 | 顶部导航 + 主内容 |
| 钱的计算 | `/money` | 登录 | 顶部导航 + 主内容 |
| 解聘助手 | `/termination` | 登录 | 顶部导航 + 主内容 |
| AI 合规顾问 | `/ai-assistant` | 登录 | 顶部导航 + 主内容 |
| 系统设置 | `/settings` | 登录(admin) | 顶部导航 + 主内容 |

**员工端**：

| 页面 | 路由 | 访问控制 | 布局 |
|------|------|---------|------|
| 员工登录 | `/portal/login` | 公开 | 居中卡片 |
| 工资条 | `/portal/payslip` | 员工Token | 极简布局 |
| 我的合同 | `/portal/contract` | 员工Token | 极简布局 |
| 入职填报 | `/portal/onboarding` | Token链接 | 极简布局 |
| 合同确认 | `/portal/contract-confirm` | Token链接 | 极简布局 |

### 5.2 响应式断点

| 断点 | 宽度 | 布局变化 |
|------|------|---------|
| 桌面 | ≥1280px | 顶部导航 + 960px 居中内容 |
| 平板 | 768-1279px | 顶部导航 + 全宽内容 |
| 手机 | 375-767px | 底部 Tab Bar + 全宽内容 |

### 5.3 空状态设计

| 场景 | 展示内容 |
|------|---------|
| 首页无员工 | 插图 + 「添加第一个员工」按钮 + 示例截图 |
| 合同列表无数据 | 插图 + 「还没有员工，点这里添加」按钮 |
| 无风险 | 绿色大勾 + 「✅ 暂无风险，继续保持！」 |
| AI 顾问无对话 | 欢迎语 + 预设问题快捷按钮 |
| 解聘无历史记录 | 插图 + 「还没有解聘记录」文字 |
| 员工端无工资条 | 插图 + 「暂无工资记录」文字 |
| 员工端无合同 | 插图 + 「暂无合同信息，请联系 HR」文字 |
| 入职填报链接失效 | 提示「链接已过期，请联系 HR 重新发送」 |
| 合同确认链接失效 | 提示「链接已过期，请联系 HR 重新发送」 |

---

## 6. API 规格

### 6.1 统一规范

- **前缀**: `/api/v1/`
- **认证**: `Authorization: Bearer <access_token>`
- **响应格式**:
```json
{
  "success": true,
  "data": {},
  "error": null
}
```
- **错误格式**:
```json
{
  "success": false,
  "data": null,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "手机号格式不正确"
  }
}
```
- **分页**: `?page=1&pageSize=20` → 返回 `{ items: [], total: 100, page: 1, pageSize: 20 }`

### 6.2 API 清单

| 模块 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 认证 | POST | `/auth/register` | 注册 |
| 认证 | POST | `/auth/login` | 登录 |
| 认证 | POST | `/auth/refresh` | 刷新 Token |
| 认证 | GET | `/auth/me` | 获取当前用户 |
| Dashboard | GET | `/dashboard` | 首页数据聚合 |
| 员工 | GET | `/employees` | 员工列表 |
| 员工 | POST | `/employees` | 添加员工 |
| 员工 | GET | `/employees/:id` | 员工详情 |
| 员工 | PUT | `/employees/:id` | 编辑员工 |
| 员工 | DELETE | `/employees/:id` | 删除员工（软删除） |
| 合同 | POST | `/contracts/batch-renew` | 批量续签 |
| 合同 | POST | `/contracts/:id/attachment` | 上传扫描件 |
| 加班 | GET | `/overtime` | 加班记录列表 |
| 加班 | POST | `/overtime` | 添加加班记录 |
| 解聘 | GET | `/termination` | 解聘记录列表 |
| 解聘 | POST | `/termination` | 创建解聘记录 |
| 风险 | GET | `/risks` | 风险列表 |
| 风险 | PUT | `/risks/:id` | 更新风险状态 |
| AI | POST | `/ai/chat` | 智能问答（SSE） |
| AI | GET | `/ai/prediction` | 风险预测 |
| AI | POST | `/ai/contract-review` | 合同审查 |
| AI | POST | `/ai/case-match` | 案例匹配 |
| 设置 | GET | `/settings/org` | 企业信息 |
| 设置 | PUT | `/settings/org` | 更新企业信息 |
| 设置 | GET | `/settings/users` | 用户列表 |
| 设置 | POST | `/settings/users` | 添加用户 |
| 设置 | PUT | `/settings/users/:id` | 编辑用户 |
| 设置 | DELETE | `/settings/users/:id` | 移除用户 |
| 员工端 | POST | `/portal/auth/login` | 手机号+密码登录 |
| 员工端 | POST | `/portal/auth/send-code` | 发送验证码（v1.0 页面内显示） |
| 员工端 | POST | `/portal/auth/verify` | 验证码登录 |
| 员工端 | POST | `/portal/auth/change-password` | 修改密码 |
| 员工端 | GET | `/portal/payslip` | 工资条列表 |
| 员工端 | GET | `/portal/payslip/:month` | 指定月工资明细 |
| 员工端 | POST | `/portal/payslip/:month/confirm` | 确认已阅工资条 |
| 员工端 | GET | `/portal/contract` | 我的合同信息 |
| 员工端 | GET | `/portal/onboarding/:token` | 获取入职填报信息 |
| 员工端 | POST | `/portal/onboarding/:token` | 提交入职填报 |
| 员工端 | GET | `/portal/contract-confirm/:token` | 获取合同确认信息 |
| 员工端 | POST | `/portal/contract-confirm/:token` | 确认签署合同 |
| 管理端 | POST | `/employees/:id/generate-onboarding-qr` | 生成入职填报二维码 |
| 管理端 | POST | `/contracts/:id/generate-confirm-qr` | 生成合同确认二维码 |
| 管理端 | GET | `/payslip/confirm-status` | 工资条确认状态 |

---

## 7. 数据库设计

### 7.1 Prisma Schema 概要

```prisma
// 核心表
model Organization {
  id           String   @id @default(cuid())
  name         String
  plan         Plan     @default(FREE)
  maxEmployees Int      @default(20)
  city         String?
  createdAt    DateTime @default(now())
  users        User[]
  employees    Employee[]
  contracts    LaborContract[]
  overtimeRecords OvertimeRecord[]
  terminations TerminationRecord[]
  riskItems    RiskItem[]
  auditLogs    AuditLog[]
}

model User {
  id           String   @id @default(cuid())
  orgId        String
  org          Organization @relation(fields: [orgId], references: [id])
  phone        String   @unique
  email        String?
  passwordHash String
  name         String
  role         Role     @default(ADMIN)
  createdAt    DateTime @default(now())
  lastLoginAt  DateTime?
}

// 业务表
model Employee {
  id               String   @id @default(cuid())
  orgId            String
  org              Organization @relation(fields: [orgId], references: [id])
  name             String
  department       String
  hireDate         DateTime
  monthlySalary    String   // AES-256 加密存储
  status           EmployeeStatus @default(ACTIVE)
  gender           String?
  isPregnant       Boolean  @default(false)
  isInMedicalPeriod Boolean @default(false)
  isWorkInjured    Boolean  @default(false)
  phone            String?
  createdBy        String
  createdAt        DateTime @default(now())
  updatedAt        DateTime @updatedAt
  contracts        LaborContract[]
  overtimeRecords  OvertimeRecord[]
  terminations     TerminationRecord[]
}

model LaborContract {
  id                    String   @id @default(cuid())
  orgId                 String
  org                   Organization @relation(fields: [orgId], references: [id])
  employeeId            String
  employee              Employee @relation(fields: [employeeId], references: [id])
  signDate              DateTime?
  startDate             DateTime
  endDate               DateTime?
  contractType          ContractType
  signMethod            SignMethod @default(PAPER)
  contractYears         Int      @default(3)
  probationMonths       Int      @default(0)
  probationSalary       Int      @default(0)
  renewalCount          Int      @default(0)
  attachmentName        String?
  attachmentUrl         String?
  electronicContractNo  String?
  electronicContractUrl String?
  createdBy             String
  createdAt             DateTime @default(now())
  updatedAt             DateTime @updatedAt
}

// 其余表参考 0-req.md 第5章数据模型
```

### 7.2 枚举定义

```prisma
enum Plan { FREE PRO ENTERPRISE }
enum Role { ADMIN HR VIEWER }
enum EmployeeStatus { ACTIVE RESIGNED }
enum ContractType { FIXED UNFIXED UNSIGNED }
enum SignMethod { PAPER ELECTRONIC }
enum RiskType { CONTRACT SALARY TERMINATION }
enum RiskLevel { HIGH MEDIUM LOW }
enum RiskStatus { PENDING RESOLVED IGNORED }
enum TerminationReason { NEGOTIATED FAULT NONFAULT LAYOFF EXPIRED }
enum RiskAssessment { SAFE WARNING DANGER }
enum OnboardingStatus { PENDING APPROVED REJECTED }
enum ContractConfirmStatus { UNCONFIRMED CONFIRMED EXPIRED }

// 员工端扩展表
model Payslip {
  id           String   @id @default(cuid())
  orgId        String
  employeeId   String
  employee     Employee @relation(fields: [employeeId], references: [id])
  month        String   // YYYY-MM
  baseSalary   Decimal  // 基本工资
  overtimePay  Decimal  // 加班费合计
  weekdayOvertimePay  Decimal
  weekendOvertimePay  Decimal
  holidayOvertimePay  Decimal
  totalPay     Decimal  // 应发合计
  confirmedAt  DateTime? // 员工确认时间
  confirmedIp  String?   // 确认 IP
  createdAt    DateTime @default(now())

  @@unique([employeeId, month])
}

model OnboardingLink {
  id           String   @id @default(cuid())
  orgId        String
  employeeId   String?  // 关联员工（审核通过后关联）
  token        String   @unique  // 一次性 token
  status       OnboardingStatus @default(PENDING)
  phone        String   // 员工手机号
  expiresAt    DateTime  // 24h 有效
  submittedAt  DateTime? // 员工提交时间
  submittedData Json?   // 员工填报数据
  reviewedBy   String?  // 审核人 userId
  reviewedAt   DateTime? // 审核时间
  createdAt    DateTime @default(now())
}

model ContractConfirmLink {
  id           String   @id @default(cuid())
  orgId        String
  contractId   String
  token        String   @unique  // 一次性 token
  status       ContractConfirmStatus @default(UNCONFIRMED)
  employeePhone String  // 员工手机号
  expiresAt    DateTime  // 7天有效
  confirmedAt  DateTime? // 员工确认时间
  confirmedIp  String?   // 确认 IP
  confirmedDevice String? // 设备信息
  createdAt    DateTime @default(now())
}
```

---

## 8. 前端架构

### 8.1 项目结构

```
frontend/
├── src/
│   ├── main.tsx                 # 入口
│   ├── App.tsx                  # 路由定义
│   ├── components/              # 通用组件
│   │   ├── layout/
│   │   │   ├── TopNav.tsx       # 顶部导航
│   │   │   ├── MobileTabBar.tsx # 移动端底部导航
│   │   │   └── PageContainer.tsx
│   │   ├── ui/
│   │   │   ├── Button.tsx
│   │   │   ├── Card.tsx
│   │   │   ├── Signal.tsx       # 信号灯组件
│   │   │   ├── Modal.tsx
│   │   │   ├── Input.tsx
│   │   │   ├── Select.tsx
│   │   │   ├── DatePicker.tsx
│   │   │   └── EmptyState.tsx
│   │   └── shared/
│   │       ├── RiskCard.tsx
│   │       ├── TodoList.tsx
│   │       └── ProgressBar.tsx
│   ├── pages/
│   │   ├── auth/
│   │   │   ├── Login.tsx
│   │   │   ├── Register.tsx
│   │   │   └── ForgotPassword.tsx
│   │   ├── Dashboard.tsx
│   │   ├── Contracts.tsx
│   │   ├── Money.tsx
│   │   ├── Termination.tsx
│   │   ├── AIAssistant.tsx
│   │   ├── Settings.tsx
│   │   └── portal/
│   │       ├── PortalLogin.tsx     # 员工端登录
│   │       ├── Payslip.tsx         # 工资条
│   │       ├── MyContract.tsx      # 我的合同
│   │       ├── Onboarding.tsx      # 入职填报
│   │       └── ContractConfirm.tsx # 合同确认
│   ├── hooks/
│   │   ├── useAuth.ts
│   │   ├── useApi.ts
│   │   └── useRiskEngine.ts
│   ├── lib/
│   │   ├── api.ts               # Axios 实例 + 拦截器
│   │   ├── calculator.ts        # 纯前端计算逻辑
│   │   ├── riskEngine.ts        # 风险检测引擎
│   │   └── utils.ts
│   ├── store/
│   │   └── authStore.ts         # Zustand 状态管理
│   └── types/
│       └── index.ts             # TypeScript 类型定义
├── package.json
├── vite.config.ts
├── tailwind.config.ts
└── tsconfig.json
```

### 8.2 状态管理

- **认证状态**: Zustand（user, token, isAuthenticated）
- **服务端数据**: TanStack Query（React Query）缓存 + 自动刷新
- **表单状态**: React Hook Form + Zod 校验
- **AI 对话**: 本地 useState 管理消息列表 + SSE 流式追加

### 8.3 路由守卫

```typescript
// ProtectedRoute：未登录 → 跳转 /login
// AdminRoute：非 admin → 跳转 /
// PublicRoute：已登录 → 跳转 /
```

---

## 9. 后端架构

### 9.1 项目结构

```
backend/
├── src/
│   ├── index.ts                 # 入口
│   ├── app.ts                   # Express 应用
│   ├── routes/
│   │   ├── auth.routes.ts
│   │   ├── employee.routes.ts
│   │   ├── contract.routes.ts
│   │   ├── overtime.routes.ts
│   │   ├── termination.routes.ts
│   │   ├── risk.routes.ts
│   │   ├── ai.routes.ts
│   │   ├── settings.routes.ts
│   │   └── portal.routes.ts        # 员工端路由
│   ├── middleware/
│   │   ├── auth.ts              # JWT 校验
│   │   ├── orgFilter.ts         # 多租户 orgId 注入
│   │   ├── rateLimit.ts         # 限流
│   │   ├── errorHandler.ts      # 统一错误处理
│   │   └── auditLog.ts          # 审计日志
│   ├── services/
│   │   ├── auth.service.ts
│   │   ├── employee.service.ts
│   │   ├── contract.service.ts
│   │   ├── risk.service.ts
│   │   ├── ai.service.ts        # DashScope 调用
│   │   ├── rag.service.ts       # RAG 检索
│   │   ├── portal.service.ts    # 员工端服务
│   │   └── qrcode.service.ts    # 二维码生成
│   ├── lib/
│   │   ├── prisma.ts            # Prisma 客户端
│   │   ├── jwt.ts               # JWT 工具
│   │   ├── crypto.ts            # AES-256 加解密
│   │   └── dashscope.ts         # 通义千问 SDK 封装
│   ├── validators/
│   │   ├── auth.validator.ts    # Zod schema
│   │   ├── employee.validator.ts
│   │   └── ...
│   └── jobs/
│       ├── riskScan.ts          # 定时风险扫描
│       └── aiPrediction.ts      # 定时 AI 预测
├── prisma/
│   ├── schema.prisma
│   └── migrations/
├── package.json
└── .env
```

### 9.2 环境变量

```env
# 数据库
DATABASE_URL=postgresql://...

# JWT
JWT_SECRET=...
JWT_REFRESH_SECRET=...

# DashScope (通义千问)
DASHSCOPE_API_KEY=sk-xxx
DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/api/v1

# 加密
ENCRYPTION_KEY=...  # AES-256 工资字段加密

# 存储
SUPABASE_URL=...
SUPABASE_KEY=...

# 二维码（前端生成，无需后端服务）
# 使用 qrcode.react 库在前端直接生成

# 部署
PORT=3000
CORS_ORIGIN=https://your-app.vercel.app
```

---

## 10. 验收标准

### 10.1 功能验收

| 模块 | 验收项 | 验收标准 |
|------|--------|---------|
| 注册 | 手机号注册 | 输入合法信息 → 创建成功 → 自动登录 |
| 登录 | 密码登录 | 正确密码 → 返回 Token；错误密码 → 提示错误 |
| 首页 | 数据聚合 | 登录后 → 显示员工数/风险数/待办/分布 |
| 合同 | 添加员工 | 4项必填 → 保存成功 → 列表显示 |
| 合同 | 信号灯状态 | 未签合同→🔴；即将到期→🟡；正常→🟢 |
| 合同 | 一键续签 | 点击续签→确认→状态变绿→风险消除 |
| 合同 | 纸质/电子 | 选择纸质→显示上传按钮；选择电子→显示编号/链接输入 |
| 钱的计算 | 加班费实时计算 | 输入数字→右侧结果实时更新 |
| 钱的计算 | 加班超时预警 | 总小时>36→黄色警告 |
| 解聘 | 5步向导 | 每步显示进度条→下一步→最终保存 |
| 解聘 | 禁止情形检查 | 选孕期员工→红色警告弹窗 |
| AI | 智能问答 | 输入问题→流式回答→附法律依据 |
| AI | 合同审查 | 粘贴合同→逐条标注→合规评分 |
| AI | 案例匹配 | 输入情况→相似案例→败诉概率 |
| 设置 | 用户管理 | admin可添加用户→分配角色 |
| 员工端 | 密码登录 | 输入手机号+密码→登录成功 |
| 员工端 | 验证码登录 | 输入手机号→收到验证码→登录成功 |
| 员工端 | 扫码进入 | HR 发二维码→员工扫码→打开员工端 |
| 员工端 | 工资条查看 | 选择月份→显示工资明细→确认已阅 |
| 员工端 | 合同查看 | 显示合同信息+扫描件+签署记录 |
| 员工端 | 入职填报 | 扫码→填写信息→提交→HR审核入库 |
| 员工端 | 合同确认 | 扫码→查看合同→勾选确认→记录时间IP |
| 管理端 | 生成填报二维码 | 添加员工→选生成二维码→显示二维码+链接→微信发送 |
| 管理端 | 生成确认二维码 | 合同详情→生成确认二维码→微信发送→员工确认后状态更新 |

### 10.2 非功能验收

| 类别 | 验收标准 |
|------|---------|
| 性能 | 首屏加载 < 2s，API 响应 < 500ms，AI 首 token < 3s |
| 安全 | 密码 bcrypt 加密，工资 AES-256 加密，JWT 认证，orgId 隔离 |
| 响应式 | 桌面/平板/手机三端可用，导航自适应 |
| 兼容 | Chrome/Edge/Safari 最新版正常 |
| 数据隔离 | A 企业用户无法访问 B 企业数据 |
| 员工端隔离 | 员工只能查看自己的数据，不能查看他人 |
| 链接安全 | 入职/确认链接含一次性 token，过期失效 |

---

## 11. 发布计划

### 11.1 v1.0 发布范围

| 阶段 | 内容 | 预估工期 |
|------|------|---------|
| P0 | 项目搭建 + 路由骨架 + Prisma Schema | 2天 |
| P1 | 认证体系（注册/登录/JWT/路由守卫） | 2天 |
| P2 | 首页风险总览 + 风险检测引擎 | 2天 |
| P3 | 合同管理（列表/添加/续签/纸质电子） | 3天 |
| P4 | 钱的计算（3 Tab 计算器） | 2天 |
| P5 | 解聘助手（5步向导 + 禁止检查） | 2天 |
| P6 | AI 合规顾问（问答/预测/审查/案例 + RAG） | 4天 |
| P7 | 员工端（验证码登录 + 工资条 + 合同 + 入职填报 + 合同确认） | 3天 |
| P8 | 系统设置 + 新手引导 + 空状态 | 1天 |
| P9 | 移动端适配 + 联调 | 2天 |
| P10 | 部署上线 + 验证 | 1天 |
| **合计** | | **~24天** |

### 11.2 后续版本

| 版本 | 内容 | 预估 |
|------|------|------|
| v2.0 | 社保公积金模块 | +2周 |
| v3.0 | 人力成本分析 + 员工自助门户增强（考勤/请假） | +3周 |

---

## 12. 风险与对策

| 风险 | 影响 | 对策 |
|------|------|------|
| 通义千问 API 不稳定 | AI 功能不可用 | 降级为规则引擎回答 + 重试机制 |
| 法律规则地区差异大 | 计算结果不准 | 提供城市选择 + 默认值 + 用户可修改 |
| RAG 知识库构建耗时 | P6 延期 | 先用 Prompt 内嵌法条，后续再建向量库 |
| 中小企业付费意愿低 | 商业化困难 | free 套餐足够基础使用，AI 功能促付费 |
| 数据安全合规要求 | 法律风险 | 数据加密 + 身份证号加密存储 + 隐私协议 |
| 员工端使用率低 | 功能闲置 | HR 主动生成二维码通过微信发给员工，降低使用门槛 |
