---
tags: [全栈开发, 大作业, 执行计划, gRPC, Gin, OSS, Eino, React]
create time: 2026-05-09 14:30
---
# 大作业·执行计划 — 双端 gRPC HR 招聘系统
## 概述
本文档基于《大作业项目要求》《思维导图》《工程结构设计》三份参考资料,梳理出分阶段、可落地的开发执行计划。整体采用 **六阶段推进** 策略:环境准备 → Proto 先行 → 后端双服务 → **前端一日冲刺** → 联调测试 → 视频录制与提交,每个阶段明确任务清单、前置依赖和验收标准,确保按期完成高质量交付。
> [!tip] 如何使用本计划
> 建议按阶段的顺序推进,不要跳跃。Proto 定义是前后端的"契约",必须先于业务代码完成。每个阶段完成后对照验收清单自检,避免返工。
## 一、整体时间规划与打勾进度
将整个开发周期拆分为 6 个阶段,各阶段之间存在明确的先后依赖关系。下方是总进度看板,每完成一个阶段就打勾:
```mermaid
gantt
title 大作业开发总时间线
dateFormat YYYY-MM-DD
axisFormat %m-%d
todayMarker stroke-width:3px,stroke:#fb8c00,opacity:0.6
section 阶段一 · 环境就绪 (M0)
Go / Node / MySQL / OSS :done, p1, 2026-05-10, 1d
.gitignore + .env.example :done, p1b, after p1, 30m
section 阶段二 · Proto 先行 (M1)
7 个接口定义文件 :done, p2, 2026-05-11, 1d
protoc 生成 Go 代码 :done, p2b, after p2, 30m
section 阶段三 · 后端双服务 (M2)
3A · MySQL 建表 : p3a, 2026-05-12, 1d
3B · Logic 核心服务 (12项) :milestone, m3b, 2026-05-14, 0d
3C · Web 网关服务 : p3c, after p3a, 2d
section 阶段四 · 前端一日冲刺 (M3)
Foundation 共享基建 : p4a, 2026-05-15, 3h
候选人用户端 (6页) : p4u, after p4a, 4h
HR 管理端 (7页) : p4h, after p4a, 5h
Build 验证 + Commit :milestone,m4z, 2026-05-15, 0d
section 阶段五 · 联调自测 (M4)
全链路跑通 : p5a, 2026-05-16, 1d
专项测试 + Bug 修复 : p5b, 2026-05-17, 1d
section 阶段六 · 录制提交 (M5)
文档完善 : p6a, 2026-05-18, 2d
视频录制 + KDoc 提交 :milestone,m6end, 2026-05-18, 0d
%% 里程碑锚点
milestone M0_环境就绪 :milestone, mk1, 2026-05-10, 0d
milestone M1_Protobuf冻结 :milestone, mk2, 2026-05-11, 0d
milestone M2_后端可运行 :milestone, mk3, 2026-05-14, 0d
milestone M3_双端完成 :milestone, mk4, 2026-05-15, 0d
milestone M4_联调通过 :milestone, mk5, 2026-05-17, 0d
milestone M5_正式提交 :milestone, mk6, 2026-05-18, 0d
```
| 阶段 | 日期 | 核心交付物 | 里程碑 |
| --------------- | ------------- | ------------------------------ | -------- |
| ~~阶段一:环境与基础建设~~ | ~~05-10~~ | Go / Node / MySQL / OSS 就绪 | ✅ **M0** |
| 阶段二:Proto 接口定义 | ~~05-11~~ | 7 个 `.proto` 文件 + 生成代码 | ⬜ **M1** |
| 阶段三:后端双服务 | 05-12 ~ 05-14 | Logic gRPC + Web Gin 均可独立运行 | ⬜ **M2** |
| 阶段四:前端一日冲刺 | 05-15 | hr-frontend + user-frontend 启动 | ⬜ **M3** |
| 阶段五:前后端联调 | 05-16 ~ 05-17 | 全链路测试通过 | ⬜ **M4** |
| 阶段六:视频录制与提交 | 05-18 | 视频 + 文档全部提交 | ⬜ **M5** |
> [!tip] 使用说明
> - 🟢 **绿色条** = 已完成阶段 · 🟡 **黄色条** = 当前活跃期 · 🔴 **菱形标记** = 里程碑检查点
> - 橙色竖线为今日日期标注,直观对比当前所处阶段
> - 甘特图下方表格同步映射 M0~M5 里程碑编号,与第九节里程碑总表一一对应
> [!question] 如果某个阶段超时了怎么办?
> 优先级原则:核心功能(gRPC 分层调用、OSS 签名上传、Eino 对话)> 次要功能(分页搜索、数据可视化)。宁可缩减 UI 装饰细节,也要保住验收红线。
## 二、阶段一:环境与基础建设
> [!note] 进度追踪
> - [x] T1.1 Go 1.21+ 安装并验证
> - [x] T1.2 Node.js 18+ / npm 安装并验证
> - [x] T1.3 MySQL 8.0+ 安装 + 数据库实例创建
> - [x] T1.4 OSS 平台注册 + 私有 Bucket 创建
> - [x] T1.5 Git 仓库初始化 + 目录结构建立
> - [ ] T1.6 `.gitignore` + `.env.example` 初始化
📋 展开查看详细任务表
### 2.1 详细任务清单
| 编号 | 任务 | 耗时估计 | 说明 |
|------|------|----------|------|
| T1.1 | 安装并验证 Go 1.21+ | 30min | `go version`,配置 GOPATH 和 GOMODCACHE |
| T1.2 | 安装并验证 Node.js 18+ / npm | 30min | 后续用于两个前端项目 |
| T1.3 | 安装并验证 MySQL 8.0+ | 30min | 创建数据库实例,记录连接信息 |
| T1.4 | 注册 OSS 平台,创建私有 Bucket | 30min | 关闭匿名访问,关闭公开读权限 |
| T1.5 | 创建 Git 仓库,建立最终目录结构 | 30min | 参照 `final_homework/` 规范 |
| T1.6 | 初始化 .gitignore 和 .env.example | 30min | 敏感文件排除:.env、go.sum(可选)、node_modules |
### 2.2 前置条件
- 无,这是第一个阶段。
### 2.3 验收标准
- [ ] `go version`、`node -v`、`mysql --version` 均正常输出
- [ ] OSS Bucket 已创建且为私有(匿名访问已关闭)
- [ ] 本地目录结构已按 `工程结构.md` 的顶层树创建出来
- [ ] `.gitignore` 正确排除了敏感配置文件
```bash
# 预期目录骨架
final_homework/
├── hr-frontend/
├── user-frontend/
├── web-gin-service/
├── logic-grpc-service/
└── api/
```
> [!warning] 常见陷阱
> - OSS 密钥务必写入 .env 或独立配置文件,**不要硬编码到业务代码中**。真实业务场景中 key 是绝对禁止提交到仓库的。
> - 新建 Git 仓库后立刻添加 .gitignore,避免误提交 .env 文件。
## 三、阶段二:Proto 接口定义(契约先行)
> [!note] 进度追踪
> - [ ] T2.1 `common.proto` — 通用响应码、分页参数
> - [ ] T2.2 `auth.proto` — Login/RPC、Register/RPC、VerifyToken/RPC
> - [ ] T2.3 `job.proto` — CreateJob/RPC、UpdateJob/RPC、ListJobs/RPC、DeleteJob/RPC
> - [ ] T2.4 `application.proto` — SubmitApplication/RPC、ListApplications/RPC
> - [ ] T2.5 `profile.proto` — GetProfile/RPC、UpdateProfile/RPC
> - [ ] T2.6 `resume.proto` — GenOssSign/RPC、SaveResume/RPC
> - [ ] T2.7 `chat.proto` — SendChat/RPC、GetHistory/RPC
> - [ ] T2.8 protoc 生成 Go 代码
📋 展开查看详细任务表 + 前置条件
### 3.1 详细任务清单
| 编号 | 任务 | 前置依赖 | 耗时估计 |
|------|------|----------|----------|
| T2.1 | 定义 `common.proto`(通用响应码、分页参数) | — | 30min |
| T2.2 | 定义 `auth.proto`(Login/RPC、Register/RPC、VerifyToken/RPC) | T2.1 | 30min |
| T2.3 | 定义 `job.proto`(CreateJob/RPC、UpdateJob/RPC、ListJobs/RPC、DeleteJob/RPC) | T2.1 | 30min |
| T2.4 | 定义 `application.proto`(SubmitApplication/RPC、ListApplications/RPC) | T2.1 | 30min |
| T2.5 | 定义 `profile.proto`(GetProfile/RPC、UpdateProfile/RPC) | T2.1 | 30min |
| T2.6 | 定义 `resume.proto`(GenOssSign/RPC、SaveResume/RPC) | T2.1 | 30min |
| T2.7 | 定义 `chat.proto`(SendChat/RPC、GetHistory/RPC) | T2.1 | 30min |
| T2.8 | protoc 生成 Go 代码 | T2.1 ~ T2.7 | 30min |
### 3.2 前置条件
- 阶段一已完成(T1.1 ~ T1.6)
- protoc 编译器及 go plugin 插件已安装
### 3.3 验收标准
- [ ] `protoc --go_out=... --go-grpc_out=...` 在 `api/proto/v1/` 下编译通过
- [ ] 生成的 Go 代码存在于两个服务的 `proto/gen/v1/` 目录
- [ ] 所有 RPC 方法签名覆盖项目需求文档中的全部接口
> [!tip] Proto 设计最佳实践
> - 每个 Service 对应一个 proto 文件,职责单一
> - Request 和 Response 消息统一命名规范:`XxxRequest`、`XxxResponse`
> - `common.proto` 中的 `CommonResponse{code, msg, data}` 作为所有响应的包装壳
> - 字段使用 tag 编号,从 1 开始递增,预留扩展空间
## 四、阶段三:后端双服务开发
### 3.1 子阶段 3A:MySQL 数据库建表
> [!note] 进度追踪
> - [ ] T3A.1 根据 ER 图设计 SQL DDL
> - [ ] T3A.2 执行建表 + 插入测试种子数据
建表清单(对照 `db.md` 细化):
| 表名 | 用途 | 关键字段 |
|------|------|----------|
| `users` | 用户表 | id, username, password_hash, role, created_at |
| `jobs` | 岗位表 | id, creator_id, title, description, status, created_at |
| `applications` | 投递记录表 | id, job_id, candidate_id, applied_at |
| `profiles` | 候选人档案表 | id, user_id, name, phone, education, school, experience, skills |
| `resumes` | 简历信息表 | id, profile_id, file_key, oss_url, created_at |
| `chat_records` | AI对话历史表 | id, hr_id, question, ai_reply, created_at |
> [!note] 思考题
> 为什么 `creator_id` 放在 jobs 表中而不是单独的 job_ownership 关联表?因为本系统架构轻量化,HR 仅管理本人发布的岗位,单字段外键足以表达这种一对一的归属关系。
### 3.2 子阶段 3B:Logic 核心业务服务
> [!note] 进度追踪
> - [ ] T3B.1 gRPC Server 框架 + config 模块
> - [ ] T3B.2 AuthService(注册/登录/JWT签发)
> - [ ] T3B.3 JobService(岗位 CRUD + 创建者权限校验)
> - [ ] T3B.4 ApplicationService(投递逻辑 + 校验拦截)
> - [ ] T3B.5 ProfileService(候选人档案增改查)
> - [ ] T3B.6 ResumeService + OSS signer(签名 URL 生成 + 文件头校验)
> - [ ] T3B.7 ChatService(意图解析 → SQL查询 → Prompt拼接 → Eino推送 → 持久化)
> - [ ] T3B.8 repository 层数据访问封装(6张表)
> - [ ] T3B.9 converter 层 proto ↔ model 转换
> - [ ] T3B.10 JWT 工具模块(签发 + 验证 + 角色提取)
> - [ ] T3B.11 AI 模块封装(Eino Chat Engine + prompt 模板 + 意图解析器)
> - [ ] T3B.12 Logic 服务独立启动测试
📋 展开查看 Logic 详细任务表
| 编号 | 任务 | 前置依赖 | 耗时估计 |
|------|------|----------|----------|
| T3B.1 | 搭建 gRPC Server 框架 + config 模块 | T3A.2 | 1h |
| T3B.2 | 实现 AuthService(注册/登录/JWT签发) | T3B.1 | 2h |
| T3B.3 | 实现 JobService(岗位 CRUD + 创建者权限校验) | T3B.1 | 2h |
| T3B.4 | 实现 ApplicationService(投递逻辑 + 校验拦截) | T3B.1, T3B.3 | 2h |
| T3B.5 | 实现 ProfileService(候选人档案增改查) | T3B.1 | 1.5h |
| T3B.6 | 实现 ResumeService + OSS signer(签名 URL 生成 + 文件头校验) | T3B.1 | 2h |
| T3B.7 | 实现 ChatService(意图解析 → SQL查询 → Prompt拼接 → Eino推送 → 持久化) | T3B.1, T3A.2 | 2.5h |
| T3B.8 | repository 层数据访问封装(6张表) | T3B.1 | 2h |
| T3B.9 | converter 层 proto ↔ model 转换 | T2.8, T3B.8 | 1h |
| T3B.10 | JWT 工具模块(签发 + 验证 + 角色提取) | T3B.1 | 1h |
| T3B.11 | AI 模块封装(Eino Chat Engine + prompt 模板 + 意图解析器) | T3B.1 | 2h |
| T3B.12 | Logic 服务独立启动测试 | T3B.2 ~ T3B.11 | 1h |
#### Logic 核心流程自查
- [ ] 用户注册时密码 bcrypt 加密存储
- [ ] 登录成功签发 JWT(包含 userId + role)
- [ ] 岗位编辑/下架时校验当前操作用户 == creator_id
- [ ] 候选人投递时拦截:未完善资料或无简历 → 返回错误码
- [ ] OSS 签名 URL 严格后缀白名单 (.pdf/.doc/.docx) + 文件头 Magic Number 校验
- [ ] 简历不经过服务端缓存,客户端直传 OSS
- [ ] AI 对话每条问答自动写入 chat_records 表
> [!danger] 验收红线
> Logic 服务内所有业务逻辑只能通过 gRPC Server 暴露,Web 服务不得通过同工程内部函数直连调用。如果同一个 Go module 里直接 import service 包 = 架构违规。
### 3.3 子阶段 3C:Web 网关服务
> [!note] 进度追踪
> - [ ] T3C.1 Gin 项目框架 + router 注册
> - [ ] T3C.2 CORS 中间件(全局跨域处理)
> - [ ] T3C.3 JWT 鉴权中间件(读取 Token + 角色校验)
> - [ ] T3C.4 参数合法性校验中间件
> - [ ] T3C.5 gRPC Client 连接池 + codec JSON 转换
> - [ ] T3C.6 Auth Handler
> - [ ] T3C.7 Job Handler
> - [ ] T3C.8 Application Handler
> - [ ] T3C.9 Profile Handler
> - [ ] T3C.10 Resume Handler
> - [ ] T3C.11 Chat Handler
> - [ ] T3C.12 Web 服务独立启动测试
📋 展开查看 Web 网关详细任务表
| 编号 | 任务 | 前置依赖 | 耗时估计 |
|------|------|----------|----------|
| T3C.1 | 搭建 Gin 项目框架 + router 注册 | T3B.12 | 1h |
| T3C.2 | CORS 中间件(全局跨域处理) | T3C.1 | 30min |
| T3C.3 | JWT 鉴权中间件(读取 Token + 角色校验) | T3B.10 | 1h |
| T3C.4 | 参数合法性校验中间件 | T3C.1 | 1h |
| T3C.5 | gRPC Client 连接池 + codec JSON 转换 | T3B.12 | 1.5h |
| T3C.6 | Auth Handler(POST /api/auth/login, register) | T3C.5, T3B.2 | 1h |
| T3C.7 | Job Handler(CRUD 路由映射到 gRPC) | T3C.5, T3B.3 | 1.5h |
| T3C.8 | Application Handler | T3C.5, T3B.4 | 1h |
| T3C.9 | Profile Handler | T3C.5, T3B.5 | 1h |
| T3C.10 | Resume Handler(获取签名 URL 返回给前端) | T3C.5, T3B.6 | 1.5h |
| T3C.11 | Chat Handler(AI 对话转发) | T3C.5, T3B.7 | 1.5h |
| T3C.12 | Web 服务独立启动,用 curl/postman 测试 | T3C.6 ~ T3C.11 | 1h |
#### Web 端架构自查
- [ ] Handler 中没有任何核心业务逻辑——只有参数解析 + gRPC 调用转发
- [ ] JWT 中间件在路由注册前挂载,未携带 Token 的请求一律返回 401
- [ ] 所有 gRPC 调用都有 context deadline(防止阻塞)
- [ ] 错误码统一通过 CommonResponse.code 传递
## 五、阶段四:前端一日冲刺
> [!tip] 技术选型确认
> 前端统一使用 **React + Vite + TypeScript + Axios**,UI 组件库推荐 **Ant Design**(开箱即用、减少造轮子时间)。前端只负责页面渲染和接口请求,所有业务逻辑在后端处理。
### 4.1 核心策略:共享基础层 + 下午独立填页
两个前端共用了同一套后端 API 契约(`api/proto/v1/`),因此**不需要各自从零搭架子**。关键压缩思路:
```mermaid
graph LR
subgraph Foundation["Foundation(共享基础层)"]
A1["hr-frontend 脚手架初始化"] --> A2["user-frontend 脚手架初始化"]
A2 --> A3["双方同步搭建: Router/Axios/AuthContext/布局组件"]
A3 --> A4["Ant Design 主题配置"]
end
subgraph Candidate["候选人用户端(独立完成)"]
B1["公开岗位列表"] --> B2["登录注册"] --> B3["档案表单"] --> B4["OSS直传"] --> B5["投递记录"]
end
subgraph HR["HR 管理端(独立完成)"]
C1["登录注册"] --> C2["岗位CRUD"] --> C3["候选人列表"] --> C4["AI对话窗口"]
end
A4 -.-> B1
A4 -.-> C1
```
| 模块 | 策略 | 复用收益 |
|------|------|----------|
| Foundation | 两个项目同时跑:Vite 初始化 + Router + Axios client + AuthContext + 布局组件 | 每个文件只写一次,两份代码各自 `cp -r` 起步,省去重复劳动 |
| 候选人 / HR | 各自独立填充页面——候选人端 6 页 / HR 端 7 页,互不干扰 | 后端 API 已完成,前端只对接已有接口 |
### 4.2 Foundation 搭建
> [!note] 进度追踪
> - [ ] T4.AM.1 hr-frontend 脚手架初始化 (`create-vite`)
> - [ ] T4.AM.1b user-frontend 脚手架初始化 (`create-vite`)
> - [ ] T4.AM.2 安装依赖 (antd, icons, react-router-dom)
> - [ ] T4.AM.3 路由配置 + Layout 组件(hr: Sidebar/Header, user: Navbar/Footer)
> - [ ] T4.AM.4 Axios client 封装(baseURL / interceptor / token 注入)
> - [ ] T4.AM.5 AuthContext(useContext 管理 JWT,isAuthenticated / role 状态)
> - [ ] T4.AM.6 Ant Design 全局主题 & 全局 CSS
📋 展开查看详细任务表
| 编号 | 任务 | 耗时 | 说明 |
|------|------|------|------|
| T4.AM.1 | `npx create-vite hr-frontend --template react-ts` | 5min | 同步创建两个项目 |
| T4.AM.1b | `npx create-vite user-frontend --template react-ts` | 5min | — |
| T4.AM.2 | 安装依赖 (`antd`, `@ant-design/icons`, `react-router-dom`) | 10min | 两端同步操作 |
| T4.AM.3 | 路由配置 + Layout 组件(hr: Sidebar/Header, user: Navbar/Footer) | 45min | 各自按风格定制 |
| T4.AM.4 | Axios client 封装(baseURL / interceptor / token 注入) | 30min | 模板几乎相同,改 baseURL 即可 |
| T4.AM.5 | AuthContext(useContext 管理 JWT,isAuthenticated / role 状态) | 30min | 两端复制 + 角色名差异 |
| T4.AM.6 | Ant Design 全局主题 & 全局 CSS | 20min | hr 用深色主题, user 用浅色主题 |
#### AM 成果验证
- [ ] 两个 `npm run dev` 均能启动,显示空白布局框架
- [ ] 路由切换正常,Axios 请求可发送到 `http://localhost:8080/api`
> [!note] 思考题
> 为什么 AuthContext 只需要改"角色名"就可以复用?因为前后端的鉴权模型是一致的——都靠 JWT 中的 `role` 字段区分 HR/候选人。这个设计体现了"接口契约驱动开发"的思想:proto 定义了统一的用户身份模型,前端只需消费它。
### 4.3 候选人用户端
> [!note] 进度追踪
> - [ ] T4.U.1 HomePage — 公开岗位列表(免登录浏览)
> - [ ] T4.U.2 LoginPage + RegisterPage — 表单 + 提交到 `/api/auth/login`
> - [ ] T4.U.3 JobDetailPage — 岗位详情 + 条件渲染投递按钮
> - [ ] T4.U.4 SetupProfilePage — 结构化档案表单
> - [ ] T4.U.5 ResumeUploadPage — OSS 签名 URL 直传组件
> - [ ] T4.U.6 ApplicationPage + WarningModal — 投递记录 + 拦截弹窗
📋 展开查看详细任务表
| 编号 | 任务 | 前置依赖 | 耗时 | 页面数 |
|------|------|----------|------|--------|
| T4.U.1 | HomePage:调用 `/api/jobs` 展示岗位卡片列表(免登录) | T4.AM | 40min | 1 |
| T4.U.2 | LoginPage + RegisterPage:表单 + 提交到 `/api/auth/login` | T4.AM | 40min | 2 |
| T4.U.3 | JobDetailPage:岗位详情 + 条件渲染投递按钮(已登录 && 有档案 && 有简历) | T4.U.1 | 40min | 1 |
| T4.U.4 | SetupProfilePage:Ant Design Form 表格单(姓名/电话/学历/院校/经历/技能) | T4.AM | 30min | 1 |
| T4.U.5 | ResumeUploadPage:选择文件 → 调 `/api/resume/upload` 拿签名 URL → 客户端 PUT 到 OSS | T4.AM, T3C.10 | 50min | 1 |
| T4.U.6 | ApplicationPage + WarningModal:投递记录 + 拦截弹窗 | T4.AM | 30min | 1+1 |
#### 候选人端关键交互逻辑
```mermaid
flowchart TD
A["游客打开 /user/"] --> B["查看岗位列表"]
B --> C["点击投递按钮"]
C --> D{"是否已登录?"}
D -->|"否"| E["跳转 /user/login"]
D -->|"是"| F{"是否完善档案?"}
F -->|"否"| G["提示跳转到 /user/profile/setup"]
F -->|"是"| H{"是否有合规简历?"}
H -->|"否"| I["提示 /user/resume/upload
PDF/DOC/DOCX 格式校验"]
H -->|"是"| J["发送 POST /api/applications"]
J --> K["投递成功 ✅"]
```
### 4.4 HR 管理端
> [!note] 进度追踪
> - [ ] T4.H.1 LoginPage + RegisterPage(HR 账号体系)
> - [ ] T4.H.2 Dashboard/HomePage — 工作台概览
> - [ ] T4.H.3 JobListPage — 本人岗位列表(分页 + 搜索)
> - [ ] T4.H.4 JobEditPage — 新建/编辑岗位表单
> - [ ] T4.H.5 CandidatePage — 岗位下候选人列表
> - [ ] T4.H.6 ProfileViewPage — 候选人结构化档案只读展示
> - [ ] T4.H.7 ChatPage — AI 智能对话窗口
📋 展开查看详细任务表
| 编号 | 任务 | 前置依赖 | 耗时 | 页面数 |
|------|------|----------|------|--------|
| T4.H.1 | LoginPage + RegisterPage(HR 账号体系) | T4.AM | 30min | 2 |
| T4.H.2 | Dashboard/HomePage:工作台概览(数据卡片) | T4.AM | 30min | 1 |
| T4.H.3 | JobListPage:本人岗位列表(Ant Design Table + 分页 + 搜索) | T4.AM | 50min | 1 |
| T4.H.4 | JobEditPage:新建/编辑岗位表单 | T4.AM | 40min | 1 |
| T4.H.5 | CandidatePage:岗位下候选人列表 + 跳转档案详情页 | T4.AM | 50min | 1 |
| T4.H.6 | ProfileViewPage:候选人结构化档案只读展示 | T4.H.5 | 30min | 1 |
| T4.H.7 | ChatPage:AI 智能对话窗口(消息气泡 + 历史加载) | T4.AM, T3C.11 | 80min | 1 |
#### ChatPage 核心交互时序
```mermaid
sequenceDiagram
participant P as ChatPage
participant S as ChatContext
participant A as Axios
participant W as Web-Gin
Note over P,W: 页面加载时自动拉历史
P->>S: useEffect 触发
S->>A: GET /api/chat/history
A->>W: 带 JWT
W-->>A: 历史消息数组
A-->>S: state.push(...records)
S-->>P: 渲染对话流
Note over P,W: 用户输入新提问
P->>A: POST /api/chat/messages {question}
A->>W: 经 gRPC 转发到 Logic
W-->>A: {reply, records[]}
A-->>S: 追加 AI 回复
S-->>P: 自动滚动到底部
```
### 4.5 收尾
> [!note] 进度追踪
> - [ ] T4.Z.1 两端 `npm run build` 验证无编译错误
> - [ ] T4.Z.2 检查 .env 是否正确指向后端地址
> - [ ] T4.Z.3 git add + commit 本阶段变更
> [!warning] 前端权限边界
> 前端只做视觉展示和跳转控制。**真正的权限校验必须发生在后端**。例如:即使前端显示了投递按钮,后端也应该再次校验候选人是否满足条件;不应依赖前端隐藏按钮来保护安全。验收时评委可能会故意绕过前端直接调接口测试。
> [!tip] 加速技巧速查
> - Ant Design 的 `Form` + `Input` + `Select` 可以直接粘贴文档示例修改
> - 岗位列表复用同一个 `JobCard` 组件(候选人端和 HR 端都可以引用)
> - Axios interceptor 写一次就能用在两个项目中
> - 如果某个页面实在写不完,先用 `console.log` 占位,确保核心功能优先上线
## 六、阶段五:前后端联调与自测
> [!note] 进度追踪
> - [ ] T5.1 全链路跑通:注册 → 登录 → 岗位发布 → 浏览
> - [ ] T5.2 OSS 签名上传端到端测试(候选人端直传)
> - [ ] T5.3 AI 对话完整流程测试(提问 → 数据查询 → 回答 → 历史加载)
> - [ ] T5.4 权限隔离测试(非创建者操作他人岗位应被拒绝)
> - [ ] T5.5 文件格式拦截测试(上传图片/TXT应为非法)
> - [ ] T5.6 游客 vs 登录态功能边界测试
> - [ ] T5.7 Bug 修复与体验优化
### 6.1 详细任务清单
| 编号 | 任务 | 前置依赖 | 耗时估计 |
|------|------|----------|----------|
| T5.1 | 全链路跑通:注册 → 登录 → 岗位发布 → 浏览 | T4.Z.3 | 2h |
| T5.2 | OSS 签名上传端到端测试(候选人端直传) | T5.1 | 2h |
| T5.3 | AI 对话完整流程测试(提问 → 数据查询 → 回答 → 历史加载) | T5.1 | 2h |
| T5.4 | 权限隔离测试(非创建者操作他人岗位应被拒绝) | T5.1 | 1h |
| T5.5 | 文件格式拦截测试(上传图片/TXT应为非法) | T5.2 | 1h |
| T5.6 | 游客 vs 登录态功能边界测试 | T5.1 | 1h |
| T5.7 | Bug 修复与体验优化 | T5.1 ~ T5.6 | 2h |
### 6.2 验收 Checklist
对照以下每一项逐项打勾:
- [ ] gRPC 分层:Web 与 Logic 之间全部通过 gRPC 调用,无同工程内部函数调用
- [ ] OSS 签名 URL:文件不落地本地,客户端直传 OSS
- [ ] Eino 框架:使用了 Eino 封装的 Chat,非裸写 HTTP
- [ ] JWT 鉴权:HR 只能管理自己发布的岗位,候选人未完善资料不可投递
- [ ] AI 对话持久化:每条问答对入 MySQL,刷新页面自动加载历史上下文
- [ ] 双端前端独立运行:hr-frontend 和 user-frontend 各自 `npm run dev` 均可启动
- [ ] 四个源码目录完整、三个文档文件齐全
## 七、阶段六:视频录制与提交
> [!note] 进度追踪
> - [ ] T6.1 撰写 answer.md(拓展设计方案:OpenClaw/Hermes 集成思路)
> - [ ] T6.2 完善 README.md(启动部署指南 + 项目亮点)
> - [ ] T6.3 完善 api.md(前后端接口说明)
> - [ ] T6.4 完善 db.md(数据库设计文档补充)
> - [ ] T6.5 整理代码仓库(检查 .gitignore、清理临时文件)
> - [ ] T6.6 录制演示视频(原生实操、口述两大核心技术点)
> - [ ] T6.7 提交至 KDoc 表单
### 7.1 详细任务清单
| 编号 | 任务 | 耗时估计 |
|------|------|----------|
| T6.1 | 撰写 answer.md(拓展设计方案:OpenClaw/Hermes 集成思路) | 2h |
| T6.2 | 完善 README.md(启动部署指南 + 项目亮点) | 1.5h |
| T6.3 | 完善 api.md(前后端接口说明) | 1.5h |
| T6.4 | 完善 db.md(数据库设计文档补充) | 1h |
| T6.5 | 整理代码仓库(检查 .gitignore、清理临时文件) | 1h |
| T6.6 | 录制演示视频(原生实操、口述两大核心技术点) | 2h |
| T6.7 | 提交至 KDoc 表单 | 30min |
### 7.2 视频录制脚本大纲
| 时间段 | 内容 | 口述要点 |
|--------|------|----------|
| 0:00-0:30 | 开场 + 服务启动演示 | "我现在依次启动 Logic 服务和 Web 网关服务..." |
| 0:30-2:00 | 候选人端操作流程 | "候选人浏览岗位、注册、完善档案、上传简历、投递..." |
| 2:00-3:00 | 口述核心技术点①:gRPC 两层架构 | "Web 网关接收 HTTP 请求后,通过 gRPC 远程调用 Logic 服务...这两个是独立进程..." |
| 3:00-4:00 | 口述核心技术点②:OSS 签名 URL | "简历文件先获取签名URL,然后客户端直传 OSS,服务端零缓存..." |
| 4:00-5:30 | HR 管理端操作流程 | "HR 登录、发布岗位、查看候选人、AI 对话..." |
| 5:30-6:30 | AI 对话演示 | "输入自然语言提问,后端查询 MySQL 真实数据,通过 Eino 推送大模型..." |
| 6:30-7:00 | 总结与结尾 | 简要说明个人开发收获和优化方向 |
> [!important] 视频硬性要求
> - **禁止剪辑拼接**:一次录完,保证画面真实
> - **全程配语音解说**:不能无声黑屏
> - **必录两大技术点口述**:gRPC 分层调用逻辑、OSS 签名 URL 安全上传下载
> - **文件命名**:`姓名_学号_全栈大作业.mp4`
## 八、风险识别与应对
| 风险 | 影响范围 | 概率 | 应对措施 |
|------|----------|------|----------|
| OSS 平台注册审核慢 | 整个项目 | 中 | 提前注册,使用 MinIO 本地替代方案作为兜底 |
| Eino 框架学习成本超预期 | AI 对话模块 | 中 | 官方文档优先,只使用基础 Chat 组件,不做复杂编排 |
| Protobuf 字段频繁变更 | 前后端同步 | 高 | Proto 先行、冻结接口后再写业务代码;做好注释 |
| gRPC 调试困难 | 后端通信 | 中 | 启用 grpcurl 命令行工具进行 RPC 调用调试 |
| 前端样式适配耗时过长 | UI 呈现 | 中 | 使用现成 UI 组件库(Ant Design),不自研 CSS |
| JWT Token 过期处理遗漏 | 用户体验 | 低 | 初期可不实现自动刷新,手动重新登录即可 |
## 九、里程碑检查点
> [!note] 里程碑进度追踪
> 点击以下复选框标记里程碑完成情况:
> - [ ] **M0** — 环境就绪
> - [ ] **M1** — Proto 冻结
> - [ ] **M2** — 后端可独立运行
> - [ ] **M3** — 双端前端完成
> - [ ] **M4** — 全链路联调通过
> - [ ] **M5** — 视频已录制
> - [ ] **M6** — 正式提交
```mermaid
graph LR
M0["环境就绪
阶段一"] --> M1["Proto 冻结
阶段二"]
M1 --> M2["后端可独立运行
阶段三"]
M2 --> M3["双端前端完成
阶段四"]
M3 --> M4["全链路联调通过
阶段五"]
M4 --> M5["视频已录制
待提交"]
M5 --> M6["正式提交
KDoc表单"]
classDef done fill:#c8e6c9;
classDef current fill:#fff9c4;
classDef future fill:#eceff1;
class M0,M1,M2,M3,M4 done;
class M5 current;
class M6 future;
```
## 关联笔记
- [[大作业项目要求]] — 作业完整需求文档
- [[思维导图]] — 双端 gRPC HR 系统的知识体系与核心考点
- [[工程结构]] — 详细的仓库目录结构与代码组织