From 24c1bcd477d65cfeed2a8ed8df5b13a30be6c07d Mon Sep 17 00:00:00 2001 From: wonder Date: Sat, 9 May 2026 20:29:11 +0800 Subject: [PATCH] vault backup: 2026-05-09 20:29:11 --- FinalHomework/hzh_doc/工程结构.md | 558 +++++++++++++++++++++++++++++ FinalHomework/hzh_doc/执行计划.md | 564 ++++++++++++++++++++++++++++++ 2 files changed, 1122 insertions(+) create mode 100644 FinalHomework/hzh_doc/工程结构.md create mode 100644 FinalHomework/hzh_doc/执行计划.md diff --git a/FinalHomework/hzh_doc/工程结构.md b/FinalHomework/hzh_doc/工程结构.md new file mode 100644 index 0000000..19f1005 --- /dev/null +++ b/FinalHomework/hzh_doc/工程结构.md @@ -0,0 +1,558 @@ +# 大作业·工程结构设计 + +> 基于《思维导图》与《大作业项目要求》,前端技术栈统一采用 **React + Vite**,后端为 Go(Gin + gRPC)。 + +## 一、仓库根目录结构(`final_homework/`) + +``` +final_homework/ +├── hr-frontend/ # HR管理端前端(React + Vite) +├── user-frontend/ # 候选人用户端前端(React + Vite) +├── web-gin-service/ # Gin Web网关服务 +├── logic-grpc-service/ # gRPC核心业务服务 +├── api/ # Protobuf 定义 & API文档 +│ ├── proto/ +│ │ └── v1/ +│ │ ├── auth.proto # 认证相关 +│ │ ├── job.proto # 岗位相关 +│ │ ├── application.proto # 投递相关 +│ │ ├── profile.proto # 候选人档案 +│ │ ├── resume.proto # 简历/OSS上传 +│ │ └── chat.proto # AI对话 +│ ├── api.md # 前后端接口说明文档 +│ └── db.md # 数据库设计文档 +├── README.md # 启动部署指南 + 项目亮点 +└── answer.md # 拓展设计方案(OpenClaw/Hermes集成思路) +``` + +--- + +## 二、HR管理端前端(`hr-frontend/`) + +``` +hr-frontend/ +├── index.html +├── package.json +├── vite.config.ts # Vite 配置,配置代理到 web-gin-service +├── tsconfig.json +├── .env # 前端环境变量(API_BASE_URL 等,不进 Git) +├── .gitignore +├── public/ +│ └── favicon.ico +├── src/ +│ ├── main.tsx # 入口文件 +│ ├── App.tsx # 路由入口 + 权限守卫 +│ ├── vite-env.d.ts +│ │ +│ ├── styles/ # 全局样式 +│ │ ├── global.css +│ │ └── variables.css +│ │ +│ ├── router/ # 路由配置 +│ │ └── index.tsx # 独立路由页面:/hr/* +│ │ +│ ├── api/ # Axios 请求封装 +│ │ ├── client.ts # axios 实例 + baseURL / interceptor +│ │ ├── auth.ts # 登录/注册接口 +│ │ ├── job.ts # 岗位 CRUD 接口 +│ │ ├── application.ts # 投递列表接口 +│ │ ├── profile.ts # 候选人档案接口 +│ │ ├── resume.ts # 简历信息接口 +│ │ └── chat.ts # AI对话接口 +│ │ +│ ├── stores/ # 状态管理(useState + Context 即可) +│ │ ├── AuthContext.tsx # 登录态 + JWT Token 上下文 +│ │ └── ChatContext.tsx # AI对话消息历史上下文 +│ │ +│ ├── pages/ # 页面组件 +│ │ ├── LoginPage.tsx # HR登录页 +│ │ ├── RegisterPage.tsx # HR注册页 +│ │ └── dashboard/ # 后台主页面(登录后可见) +│ │ ├── DashboardLayout.tsx # 布局框架(侧边栏 + 顶栏) +│ │ ├── HomePage.tsx # 工作台概览 +│ │ ├── JobListPage.tsx # 岗位列表(分页、搜索) +│ │ ├── JobEditPage.tsx # 新建/编辑岗位表单 +│ │ ├── CandidatePage.tsx # 岗位下候选人列表(含投递状态) +│ │ ├── ProfileViewPage.tsx # 候选人结构化档案详情页 +│ │ └── ChatPage.tsx # AI智能对话窗口(常驻) +│ │ +│ ├── components/ # 公共组件 +│ │ ├── Layout/ +│ │ │ ├── Sidebar.tsx # 左侧导航栏 +│ │ │ └── Header.tsx # 顶部栏(显示当前HR头像/退出) +│ │ ├── Common/ +│ │ │ ├── LoadingSpinner.tsx +│ │ │ ├── EmptyState.tsx +│ │ │ └── PageHeader.tsx +│ │ └── UI/ # 基础 UI 组件(可用 Ant Design / Shadcn) +│ │ ├── Table.tsx +│ │ ├── Form.tsx +│ │ ├── Modal.tsx +│ │ └── Tag.tsx +│ │ +│ ├── types/ # TypeScript 类型定义 +│ │ ├── auth.ts +│ │ ├── job.ts +│ │ ├── application.ts +│ │ ├── profile.ts +│ │ ├── resume.ts +│ │ └── chat.ts +│ │ +│ └── utils/ # 工具函数 +│ ├── request.ts # 通用请求拦截(自动带 Token) +│ └── format.ts # 日期/数字格式化工具 +``` + +### HR端关键路由 + +| 路径 | 页面 | 说明 | 鉴权 | +|------|------|------|------| +| `/hr/login` | 登录页 | HR账号密码登录 | 访客可访问 | +| `/hr/register` | 注册页 | HR账号注册 | 访客可访问 | +| `/hr/dashboard` | 工作台 | 数据概览 | 必须JWT有效 | +| `/hr/dashboard/jobs` | 岗位列表 | 本人发布的岗位 | 必须JWT有效 | +| `/hr/dashboard/jobs/create` | 新建岗位 | 表单页 | 必须JWT有效 | +| `/hr/dashboard/jobs/:id/edit` | 编辑岗位 | 回显+修改 | 必须是创建者 | +| `/hr/dashboard/candidates` | 候选人列表 | 岗位下投递者 | 必须JWT有效 | +| `/hr/dashboard/candidates/:id/profile` | 档案详情 | 结构化资料 | 必须JWT有效 | +| `/hr/dashboard/chat` | AI对话 | 智能问答窗口 | 必须JWT有效 | + +--- + +## 三、候选人用户端前端(`user-frontend/`) + +``` +user-frontend/ +├── index.html +├── package.json +├── vite.config.ts +├── tsconfig.json +├── .env +├── .gitignore +├── public/ +│ └── favicon.ico +├── src/ +│ ├── main.tsx +│ ├── App.tsx # 路由入口 + 游客/已登录态切换 +│ ├── vite-env.d.ts +│ │ +│ ├── styles/ +│ │ ├── global.css +│ │ └── variables.css +│ │ +│ ├── router/ +│ │ └── index.tsx # 独立路由页面:/user/* +│ │ +│ ├── api/ # Axios 请求封装(同hr-frontend模式) +│ │ ├── client.ts +│ │ ├── auth.ts +│ │ ├── job.ts +│ │ ├── profile.ts +│ │ ├── resume.ts +│ │ └── application.ts +│ │ +│ ├── stores/ +│ │ └── AuthContext.tsx # 登录态 + Token 上下文 +│ │ +│ ├── pages/ +│ │ ├── HomePage.tsx # 首页:公开岗位列表(游客可见) +│ │ ├── LoginPage.tsx # 候选人登录页 +│ │ ├── RegisterPage.tsx # 候选人注册页(强校验) +│ │ ├── JobDetailPage.tsx # 岗位详情(含投递按钮) +│ │ ├── SetupProfilePage.tsx # 引导完善档案 +│ │ ├── ResumeUploadPage.tsx # 简历上传页(OSS签名URL直传) +│ │ └── ApplicationPage.tsx # 我的投递记录 +│ │ +│ ├── components/ +│ │ ├── Layout/ +│ │ │ ├── Navbar.tsx # 顶栏导航(游客/已登录不同UI) +│ │ │ └── Footer.tsx +│ │ ├── JobCard.tsx # 岗位卡片组件(复用) +│ │ ├── JobList.tsx # 岗位列表组件 +│ │ ├── UploadProgress.tsx # 简历上传进度条 +│ │ ├── WarningModal.tsx # 拦截弹窗(未完善资料/无简历) +│ │ └── Common/ +│ │ ├── EmptyState.tsx +│ │ └── LoadingSpinner.tsx +│ │ +│ ├── types/ +│ │ ├── auth.ts +│ │ ├── job.ts +│ │ ├── profile.ts +│ │ ├── resume.ts +│ │ └── application.ts +│ │ +│ └── utils/ +│ ├── request.ts +│ └── format.ts +``` + +### 候选人端关键路由 + +| 路径 | 页面 | 说明 | 鉴权 | +|------|------|------|------| +| `/user/` | 首页 | 公开岗位列表 | 免登录 | +| `/user/login` | 登录页 | 候选人登录 | 访客可访问 | +| `/user/register` | 注册页 | 候选人注册(强校验) | 访客可访问 | +| `/user/job/:id` | 岗位详情 | 查看岗位 + 投递 | 投递需登录 | +| `/user/profile/setup` | 完善档案 | 必填字段表单 | 必须登录 | +| `/user/resume/upload` | 简历上传 | OSS签名URL直传 | 必须登录 | +| `/user/applications` | 我的投递 | 投递记录列表 | 必须登录 | + +--- + +## 四、Web 网关服务(`web-gin-service/`) + +``` +web-gin-service/ +├── go.mod +├── go.sum +├── main.go # 服务入口,初始化 Gin Router + gRPC dial +├── config/ +│ ├── config.go # 配置加载(Viper / env) +│ └── .env.example # 环境变量模板 +├── internal/ +│ ├── handler/ # HTTP Handler(仅做参数解析 + gRPC调用转发) +│ │ ├── auth_handler.go # POST /api/auth/login, /api/auth/register +│ │ ├── job_handler.go # POST/GET/PUT/DELETE /api/jobs +│ │ ├── application_handler.go +│ │ ├── profile_handler.go +│ │ ├── resume_handler.go # POST /api/resume/upload → 调gRPC取签名URL +│ │ └── chat_handler.go # POST /api/chat/messages +│ │ +│ ├── middleware/ # 中间件 +│ │ ├── cors.go # 全局跨域处理 +│ │ ├── jwt_auth.go # JWT 统一鉴权(角色校验) +│ │ └── validate.go # 请求参数合法性校验 +│ │ +│ ├── transport/ # gRPC 客户端(连接 logic-grpc-service) +│ │ ├── grpc_client.go # 统一 gRPC client 池 +│ │ └── codec.go # proto message ↔ HTTP JSON 转换 +│ │ +│ └── router/ # 路由注册 +│ └── router.go # gin.Engine 路由绑定 +├── proto/ # 引用的 proto 文件只读拷贝 +│ └── gen/ +│ └── v1/ +└── README.md # Web服务自述 +``` + +### Web端 API 路由清单 + +| 方法 | 路径 | 说明 | 鉴权 | +|------|------|------|------| +| POST | `/api/auth/login` | 登录,返回 JWT | 无 | +| POST | `/api/auth/register` | 注册 | 无 | +| GET | `/api/jobs` | 岗位列表(分页) | 无 | +| GET | `/api/jobs/:id` | 岗位详情 | 无 | +| POST | `/api/jobs` | 发布岗位 | HR | +| PUT | `/api/jobs/:id` | 编辑岗位 | HR(本人) | +| DELETE | `/api/jobs/:id` | 下架岗位 | HR(本人) | +| GET | `/api/jobs/:id/applications` | 岗位下候选人列表 | HR | +| GET | `/api/profile/:userId` | 查看候选人档案 | HR | +| POST | `/api/resume/upload` | 获取OSS签名URL | 候选人 | +| POST | `/api/profile` | 更新个人档案 | 候选人 | +| POST | `/api/applications` | 投递简历 | 候选人 | +| POST | `/api/chat/messages` | AI对话发送 | HR | +| GET | `/api/chat/history` | 加载对话历史 | HR | + +--- + +## 五、Logic 核心业务服务(`logic-grpc-service/`) + +``` +logic-grpc-service/ +├── go.mod +├── go.sum +├── main.go # 服务入口,注册 gRPC Server +├── config/ +│ ├── config.go +│ └── .env.example +├── internal/ +│ ├── server/ # gRPC Server 实现 +│ │ ├── auth_service.go # 用户注册/登录/鉴权 +│ │ ├── job_service.go # 岗位 CRUD(含创建者权限校验) +│ │ ├── application_service.go # 投递逻辑 +│ │ ├── profile_service.go # 候选人档案增改查 +│ │ ├── resume_service.go # OSS签名URL生成 +│ │ └── chat_service.go # AI对话 + 历史持久化 +│ │ +│ ├── model/ # 数据模型(ORM struct) +│ │ ├── user.go +│ │ ├── job.go +│ │ ├── application.go +│ │ ├── profile.go +│ │ └── chat_record.go +│ │ +│ ├── repository/ # 数据访问层(MySQL操作) +│ │ ├── user_repo.go +│ │ ├── job_repo.go +│ │ ├── application_repo.go +│ │ ├── profile_repo.go +│ │ ├── resume_repo.go +│ │ └── chat_record_repo.go +│ │ +│ ├── oss/ # OSS客户端封装 +│ │ ├── client.go # MinIO / 阿里云 OSS SDK 初始化 +│ │ └── signer.go # 签名URL生成 + 文件头白名单校验 +│ │ +│ ├── ai/ # Eino AI 封装 +│ │ ├── engine.go # Eino Chat 引擎初始化 +│ │ ├── prompt.go # 提示词模板 + 业务上下文拼接 +│ │ └── query_parser.go # 自然语言意图解析 → SQL查询条件 +│ │ +│ ├── jwt/ # JWT 工具 +│ │ └── jwt.go # 签发 + 验证 + 角色提取 +│ │ +│ └── converter/ # DTO 转换 +│ └── proto_converter.go # proto message ↔ model struct +├── proto/ +│ └── gen/ +│ └── v1/ +└── README.md +``` + +--- + +## 六、Protobuf 定义(`api/proto/v1/`) + +所有 proto 文件统一放在 `api/proto/v1/`,供 `web-gin-service` 和 `logic-grpc-service` 共同引用。 + +``` +api/proto/v1/ +├── common.proto # 公共定义(Response code/msg, Pagination) +├── auth.proto # AuthService: Login, Register, VerifyToken +├── job.proto # JobService: CreateJob, UpdateJob, ListJobs, DeleteJob +├── application.proto # ApplicationService: SubmitApplication, ListApplications +├── profile.proto # ProfileService: GetProfile, UpdateProfile +├── resume.proto # ResumeService: GenOssSign, GetResumeInfo +└── chat.proto # ChatService: SendChat, GetHistory +``` + +--- + +## 七、数据流总览 + +### 7.1 核心架构调用链 + +```mermaid +flowchart LR + subgraph FE ["前端层(React + Vite)"] + HR["HR管理端
hr-frontend"] + User["候选人用户端
user-frontend"] + end + + subgraph GW ["Web网关层(Gin)
web-gin-service"] + RH["Auth Handler"] + JH["Job Handler"] + AH["Application Handler"] + PH["Profile Handler"] + RRH["Resume Handler"] + CH["Chat Handler"] + JWT["JWT 鉴权中间件"] + CORS["CORS 中间件"] + end + + subgraph RPC ["Logic业务层(gRPC)
logic-grpc-service"] + US["AuthService"] + JS["JobService"] + AS["ApplicationService"] + PS["ProfileService"] + RSS["ResumeService"] + CS["ChatService"] + JWT_L["JWT 验证"] + DB["MySQL Repository"] + OSS_S["OSS Signer"] + AI["Eino Chat Engine"] + end + + subgraph Storage ["存储 & 外部服务"] + M[(MySQL)] + O[私有 OSS Bucket] + LLM[大语言模型] + end + + %% HR 请求链路 + HR -->|"HTTP /api/*"| CORS + CORS --> JWT + JWT --> RH + JWT --> JH + JWT --> CH + + %% 候选人 请求链路 + User -->|"HTTP /api/*"| CORS + + %% gRPC 跨服务调用 + RH -->|"gRPC Login/RPC"| US + JH -->|"gRPC Job CRUD"| JS + CH -->|"gRPC SendChat/History"| CS + RRH -->|"gRPC GenOssSign"| RSS + + %% Handler 转发候选人请求 + JWT --> RRH + JWT --> PH + JWT --> AH + + PH -->|"gRPC Get/UpdateProfile"| PS + AH -->|"gRPC SubmitApplication"| AS + + %% Backend → Storage + US --> M + JS --> M + AS --> M + PS --> M + DB --> M + CS --> DB + RSS --> O + CS --> AI + AI --> LLM + + classDef frontNode fill:#e3f2fd,stroke:#1565c0; + classDef gwNode fill:#fff3e0,stroke:#e65100; + classDef logicNode fill:#e8f5e9,stroke:#2e7d32; + classDef storeNode fill:#fce4ec,stroke:#c62828; + + class HR,User frontNode; + class CORS,RH,JH,AH,PH,RRH,CH gwNode; + class US,JS,AS,PS,RSS,CS,JWT_L,DB,OSS_S,AI logicNode; + class M,O,LLM storeNode; +``` + +### 7.2 简历直传流程(签名 URL 方案) + +```mermaid +sequenceDiagram + participant C as CandidateFrontend + participant W as Web-Gin + participant R as ResumeService (gRPC) + participant S as Storage (Private OSS) + + Note over C,S: 第一阶段:获取上传凭证 + + C->>W: POST /api/resume/upload
(PDF/DOC/DOCX 文件元信息) + W->>W: JWT校验 + 后缀白名单校验 + W->>R: gRPC GenOssSign(key, extension) + R->>R: 校验文件头 Magic Number + R-->>W: {UploadURL, DownloadURL, Expiry} + W-->>C: 返回签名URL信息 + + Note over C,S: 第二阶段:客户端直传 OSS(服务端零缓存) + + C->>S: PUT 直接上传到 OSS Bucket + S-->>C: 200 OK,上传完成 + + Note over C,W: 第三阶段:记录简历链接到数据库 + + C->>W: POST /api/profile/save-resume
(fileKey) + W->>R: gRPC SaveResume(fileKey) + R->>R: 持久化 fileKey 到 MySQL + R-->>W: 操作成功 + W-->>C: 保存成功 +``` + +### 7.3 AI 对话数据流 + +```mermaid +sequenceDiagram + participant H as HR Frontend + participant W as Web-Gin + participant C as ChatService (gRPC) + participant Q as Query Parser + participant M as MySQL + participant P as Prompt Builder + participant E as Eino Chat + participant L as Large Language Model + participant DB as ChatRecordRepo + + Note over H,M: Step 1 — 发起提问 + + H->>W: POST /api/chat/messages {question} + W->>C: gRPC SendChat(hrId, question) + + Note over C,Q: Step 2 — 意图解析 + 数据查询 + + C->>Q: 解析自然语言意图 + Q->>M: 执行业务SQL查询 + M-->>Q: 真实统计数据 + + Note over C,P: Step 3 — 上下文拼接 + 推送模型 + + Q-->>C: 结构化数据 + C->>P: 拼接 Prompt = 模板 + 业务数据 + 原始问题 + P-->>C: 完整Prompt + C->>E: Eino.Chat.Send(context, messages) + E->>L: HTTP 请求至大模型 + L-->>E: 生成回答 + E-->>C: 自然语言回答 + + Note over C,DB: Step 4 — 持久化 + 返回 + + C->>DB: INSERT chat_record(hr_id, question, reply) + DB-->>C: 写入成功 + C-->>W: gRPC Response {reply, records[]} + W-->>H: 渲染AI回复 + 历史消息列表 +``` + +### 7.4 模块依赖关系图 + +```mermaid +graph TB + subgraph HRFE ["hr-frontend (React + Vite)"] + Routes["路由 /hr/*"] + AuthCtx["AuthContext (JWT)"] + ChatCtx["ChatContext (对话状态)"] + API["Axios API 层"] + end + + subgraph UFE ["user-frontend (React + Vite)"] + URoutes["路由 /user/*"] + UAuthCtx["AuthContext (JWT)"] + UAPI["Axios API 层"] + end + + subgraph GWI ["web-gin-service (Go)"] + Router["Router"] + Middleware["Middleware: CORS + JWT + Validate"] + Handlers["Handlers: auth / job / resume / chat ..."] + GrpcClient["gRPC Client → Logic"] + end + + subgraph LO ["logic-grpc-service (Go)"] + GrpcServer["gRPC Server"] + Services["Services: auth / job / application / profile / resume / chat"] + Repos["Repositories → MySQL"] + OSSMod["OSS Client → Private OSS"] + AIMod["Eino Engine → LLM"] + end + + subgraph DATA ["数据 & 存储"] + MySQL[(MySQL)] + OSS["私有 OSS"] + LLM["大语言模型 API"] + end + + HRFE -->|HTTP JSON| GWI + UFE -->|HTTP JSON| GWI + GWI -->|gRPC| LO + LO --> MySQL + LO --> OSS + LO --> LLM + + classDef fe fill:#e3f2fd,stroke:#1565c0; + classDef gw fill:#fff3e0,stroke:#e65100; + classDef logic fill:#e8f5e9,stroke:#2e7d32; + classDef data fill:#fce4ec,stroke:#c62828; + class HRFE,UFE fe; + class GWI gw; + class LO logic; + class DATA data; +``` + +--- + +## 八、开发建议 + +1. **前后端各自独立运行**:每个 `frontend/` 用 `npm run dev` 启动 Vite 开发服务器,通过 `vite.config.ts` 中的 `server.proxy` 将 `/api/*` 代理到 `localhost:8080`(Web-Gin)。 +2. **Proto 先行**:先写好 `api/proto/v1/` 下的所有 `.proto` 文件,再各自 `protoc` 生成代码,避免来回改接口。 +3. **前端共享模式**:HR端和用户端都遵循「API层 → Store层 → 页面层」三层分离,可抽取公共的 Axios client 和类型定义作为参考。 +4. **环境变量隔离**:两个前端的 `.env`、后端的 `.env` 全部加 `.gitignore`,使用 `.env.example` 作为模板提交。 diff --git a/FinalHomework/hzh_doc/执行计划.md b/FinalHomework/hzh_doc/执行计划.md new file mode 100644 index 0000000..9419fd1 --- /dev/null +++ b/FinalHomework/hzh_doc/执行计划.md @@ -0,0 +1,564 @@ +--- +tags: [全栈开发, 大作业, 执行计划, gRPC, Gin, OSS, Eino, React] +create time: 2026-05-09 14:30 +--- + +# 大作业·执行计划 — 双端 gRPC HR 招聘系统 + +## 概述 + +本文档基于《大作业项目要求》《思维导图》《工程结构设计》三份参考资料,梳理出分阶段、可落地的开发执行计划。整体采用 **六阶段推进** 策略:环境准备 → Proto 先行 → 后端双服务 → **前端一日冲刺** → 联调测试 → 视频录制与提交,每个阶段明确任务清单、前置依赖和验收标准,确保按期完成高质量交付。 + +> [!tip] 如何使用本计划 +> 建议按阶段的顺序推进,不要跳跃。Proto 定义是前后端的"契约",必须先于业务代码完成。每个阶段完成后对照验收清单自检,避免返工。 + +## 一、整体时间规划与打勾进度 + +将整个开发周期拆分为 6 个阶段,各阶段之间存在明确的先后依赖关系。下方是总进度看板,每完成一个阶段就打勾: + +```mermaid +gantt + title 大作业开发总时间线(前端一日冲刺版) + dateFormat MM-DD + section 阶段一 + 环境与基础建设 :done, phase1, 05-09, 1d + section 阶段二 + Proto 接口定义 :active, phase2, 05-10, 1d + section 阶段三 + MySQL 数据库建表 : phase3a, 05-11, 1d + Logic 核心业务服务 :after phase3a, 2d + Web 网关服务 :after phase3b, 1d + section 阶段四 + 前端一日冲刺 : phase4, 05-14, 1d + section 阶段五 + 前后端联调 :after phase4, 2d + 自测与 Bug 修复 :after phase5, 1d + section 阶段六 + 视频录制与提交 :after phase5b, 1d +``` + +| 阶段 | 日期 | 核心交付物 | 进度 | +|------|------|-----------|------| +| 阶段一:环境与基础建设 | 05-09 | Go / Node / MySQL / OSS 就绪 | [] | +| 阶段二:Proto 接口定义 | 05-10 | 7 个 `.proto` 文件 + 生成代码 | [] | +| 阶段三:后端双服务 | 05-11 ~ 05-13 | Logic gRPC + Web Gin 均可独立运行 | [] | +| 阶段四:前端一日冲刺 | 05-14 | hr-frontend + user-frontend 启动 | [] | +| 阶段五:前后端联调 | 05-15 ~ 05-16 | 全链路测试通过 | [] | +| 阶段六:视频录制与提交 | 05-17 | 视频 + 文档全部提交 | [] | + +> [!tip] 使用说明 +> - 甘特图可视化阶段依赖关系和整体进度 +> - 上方总表直接点选 `[]` 标记阶段完成情况 +> - 下方各阶段详细子任务默认折叠,需要时展开查看具体步骤 + +> [!question] 如果某个阶段超时了怎么办? +> 优先级原则:核心功能(gRPC 分层调用、OSS 签名上传、Eino 对话)> 次要功能(分页搜索、数据可视化)。宁可缩减 UI 装饰细节,也要保住验收红线。 + +## 二、阶段一:环境与基础建设 + +> [!note] 进度追踪 +> - [ ] T1.1 Go 1.21+ 安装并验证 +> - [ ] T1.2 Node.js 18+ / npm 安装并验证 +> - [ ] T1.3 MySQL 8.0+ 安装 + 数据库实例创建 +> - [ ] T1.4 OSS 平台注册 + 私有 Bucket 创建 +> - [ ] 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 系统的知识体系与核心考点 +- [[工程结构]] — 详细的仓库目录结构与代码组织