This repository has been archived on 2026-05-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
all-in-kingsoft/FinalHomework/hzh_doc/工程结构.md
T

558 lines
20 KiB
Markdown
Raw Normal View History

2026-05-09 20:29:11 +08:00
# 大作业·工程结构设计
> 基于《思维导图》与《大作业项目要求》,前端技术栈统一采用 **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核心业务服务
2026-05-10 21:47:14 +08:00
├── proto/ # Protobuf 定义
│ └── v1/
│ ├── auth.proto # 认证相关
│ ├── job.proto # 岗位相关
│ ├── application.proto # 投递相关
│ ├── profile.proto # 候选人档案
│ ├── resume.proto # 简历/OSS上传
│ └── chat.proto # AI对话
├── api.md # 前后端接口说明文档
├── db.md # 数据库设计文档
2026-05-09 20:29:11 +08:00
├── 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
```
---
2026-05-10 21:47:14 +08:00
## 六、Protobuf 定义(`proto/v1/`)
2026-05-09 20:29:11 +08:00
2026-05-10 21:47:14 +08:00
所有 proto 文件统一放在 `proto/v1/`,供 `web-gin-service` 和 `logic-grpc-service` 共同引用。
2026-05-09 20:29:11 +08:00
```
2026-05-10 21:47:14 +08:00
proto/v1/
2026-05-09 20:29:11 +08:00
├── 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管理端<br/>hr-frontend"]
User["候选人用户端<br/>user-frontend"]
end
subgraph GW ["Web网关层(Gin)<br/>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)<br/>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<br/>(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<br/>(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)。
2026-05-10 21:47:14 +08:00
2. **Proto 先行**:先写好 `proto/v1/` 下的所有 `.proto` 文件,再各自 `protoc` 生成代码,避免来回改接口。
2026-05-09 20:29:11 +08:00
3. **前端共享模式**:HR端和用户端都遵循「API层 → Store层 → 页面层」三层分离,可抽取公共的 Axios client 和类型定义作为参考。
4. **环境变量隔离**:两个前端的 `.env`、后端的 `.env` 全部加 `.gitignore`,使用 `.env.example` 作为模板提交。