--- 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 仓库初始化 + 目录结构建立 > - [x] 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 验收标准 - [x] `go version`、`node -v`、`mysql --version` 均正常输出 - [x] OSS Bucket 已创建且为私有(匿名访问已关闭) - [x] 本地目录结构已按 `工程结构.md` 的顶层树创建出来 - [x] `.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=...` 在 `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 系统的知识体系与核心考点 - [[工程结构]] — 详细的仓库目录结构与代码组织