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 Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 大作业·工程结构设计
> 基于《思维导图》与《大作业项目要求》,前端技术栈统一采用 **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核心业务服务
├── proto/ # Protobuf 定义
│ └── 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 定义(`proto/v1/`)
所有 proto 文件统一放在 `proto/v1/`,供 `web-gin-service` 和 `logic-grpc-service` 共同引用。
```
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管理端<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)。
2. **Proto 先行**:先写好 `proto/v1/` 下的所有 `.proto` 文件,再各自 `protoc` 生成代码,避免来回改接口。
3. **前端共享模式**:HR端和用户端都遵循「API层 → Store层 → 页面层」三层分离,可抽取公共的 Axios client 和类型定义作为参考。
4. **环境变量隔离**:两个前端的 `.env`、后端的 `.env` 全部加 `.gitignore`,使用 `.env.example` 作为模板提交。