# resume **Repository Path**: luo-youlu6/resume ## Basic Information - **Project Name**: resume - **Description**: 一个本地优先、所见即所得的在线简历制作工具。左侧结构化编辑、右侧 PDF 实时预览,支持多套模板一键切换,并集成 AI 解析、智能评分与优化建议,帮助用户快速产出一份排版专业的简历。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-08 - **Last Updated**: 2026-09-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 简历制作 Web 程序 一个**本地优先、所见即所得**的在线简历制作工具。左侧结构化编辑、右侧 PDF 实时预览,支持多套模板一键切换,并集成 AI 解析、智能评分与优化建议,帮助用户快速产出一份排版专业的简历。 - 🌐 在线体验:编辑 → 预览 → 下载 PDF/Word 全程在浏览器完成 - 🤖 AI 赋能:粘贴/上传旧简历自动结构化,LLM 按目标岗位评分并给出改进建议 - 📦 本地优先:数据默认保存在浏览器 localStorage,登录后自动多设备云同步 - 🔐 多用户:注册登录、分享链接、管理后台 --- ## 目录 - [功能特性](#功能特性) - [技术架构](#技术架构) - [技术栈](#技术栈) - [快速开始](#快速开始) - [使用指南](#使用指南) - [配置说明](#配置说明) - [LLM 配置](#llm-配置) - [API 概览](#api-概览) - [数据模型](#数据模型) - [测试](#测试) - [部署](#部署) - [安全说明](#安全说明) - [目录结构](#目录结构) - [常见问题](#常见问题) --- ## 功能特性 ### 编辑器 - **结构化分区**:基本信息、证件照、自我评价、工作经历、实习经历、项目经历、教育经历、专业技能、证书/奖项、语言能力,以及用户自建内容模块 - **自定义字段**:每个内容分区(分区级)与每条记录(记录级,如某家公司/某个项目/某段教育)均可扩展自定义 `label: value` 字段 - **分区管理**:显隐切换、拖动排序、自建模块(标题 + 多条目的新增/删除/排序) ### 富文本 - 加粗、斜体、文字着色、相对字号(小/标准/中/大) - 无序列表(圆点)与有序列表(数字),可与普通段落混排 - 粘贴自动净化、网址自动识别为可点击超链接、空白折叠 ### PDF - `@react-pdf/renderer` 客户端渲染,**预览与导出使用同一条渲染管线**,所见即所得 - 三套模板:经典单列 / 现代左栏 / 紧凑双栏 - 中文黑体与衬线字体子集 + 合成斜体(Noto Sans/Serif SC) - 支持纸张大小(A4 / Letter)、字号行距、主题色、正文加粗 ### 样式与模板 - 模板、主题色、字体、纸张、字号/行距全局一键切换 - 命名样式模板保存、应用、删除(登录后可同步云端) ### 数据 - **本地优先**:Zustand + localStorage 防抖自动保存,离线可用 - **云同步**:登录后自动双向同步(编辑自动上传、登录自动拉取),多设备恢复,无需手动操作 - 版本历史(每份简历最多 20 条快照)、回收站(30 天自动清理)、标签、归档 ### AI 能力 - 简历文件解析(PDF / Word) - LLM 智能评分(满分 100,多维度 + 改进建议) - 本地规则评分(离线兜底) - 支持 DeepSeek(SiliconFlow)/ OpenAI / 自定义 OpenAI 兼容接口 ### 分享与导出 - 分享链接(可设置有效期,软删后自动失效) - 导出 PDF、导出 Word(含实习经历、自定义模块、证件照) ### 账号体系 - 注册 / 登录 / 找回密码 / 修改密码 - 个人中心:默认资料、默认样式、统计 - 管理后台:用户管理(创建/编辑/禁用/重置密码)、全量数据统计、系统 LLM 配置 --- ## 技术架构 ``` ┌─────────────────────────────────────────────────────────────┐ │ 浏览器(前端) │ │ React 18 + TS + Vite │ │ ├─ EditorForm(结构化编辑) ├─ PdfPreview(@react-pdf 渲染) │ │ ├─ useResumeStore(Zustand) ├─ resumeDb(localStorage) │ │ └─ api.ts(云端客户端, 本地优先) │ └───────────────┬─────────────────────────────────────────────┘ │ HTTP /api/*(登录后) ┌───────────────▼─────────────────────────────────────────────┐ │ 后端 Flask │ │ api/(蓝图层:auth/resumes/export/parse/llm/share/styles/admin)│ │ services/(业务:auth/llm/score/rich_text) │ │ repositories/(数据访问:归属隔离/软删除/版本/分享) │ │ models/(SQLAlchemy)→ SQLite │ └──────────────────────────────────────────────────────────────┘ ``` - **内容与版式解耦**:简历内容用统一 JSON 结构存储,模板只负责排版,切换模板不改内容。 - **本地优先**:前端不依赖后端即可完成编辑/预览/导出;后端负责多用户、分享、AI 与云同步。 - **前端与后端共享同一份数据契约**:`frontend/src/types/resume.ts` 与后端存储的 JSON 结构一致。 --- ## 技术栈 | 层 | 技术 | |---|---| | 前端框架 | React 18 + TypeScript | | 构建 | Vite 5 | | 样式 | Tailwind CSS(自研组件库 `src/components/ui/*`) | | 状态管理 | Zustand | | PDF | `@react-pdf/renderer` | | 后端 | Flask 3 + SQLite(Flask-SQLAlchemy) | | 认证 | PyJWT(JWT Bearer Token) | | 限流 | Flask-Limiter | | LLM | httpx(DeepSeek / SiliconFlow / OpenAI 兼容) | | 文件解析 | pdfplumber、python-docx | | 测试 | pytest(后端)、Vitest(前端) | | 部署 | Docker + docker-compose + nginx + gunicorn | --- ## 快速开始 ### 1. 启动后端 ```bash cd backend pip install -r requirements.txt # 开发/测试用 requirements-dev.txt FLASK_ENV=dev python app.py # 默认 http://127.0.0.1:5000 ``` - 首次启动会自动迁移数据库,并创建默认管理员(账号与密码均为 `admin`,存库)。 - 健康检查:`curl http://127.0.0.1:5000/api/health` ### 2. 启动前端 ```bash cd frontend pnpm install pnpm dev # http://localhost:5173(/api 已代理到 127.0.0.1:5000) ``` ### 3. 常用命令 ```bash # 前端 pnpm build # 类型检查 + 生产构建 pnpm lint # ESLint pnpm test # Vitest 单元测试 # 后端 python -m pytest -q ``` --- ## 使用指南 1. **新建简历**:首页「新建简历」或「使用示例简历」,进入编辑器。 2. **填写内容**:左侧按分区填写;工作/实习/项目/教育/自定义模块都支持「添加/排序/删除」。 3. **实时预览**:右侧 PDF 实时同步(输入停顿后刷新),可切换纸张大小。 4. **下载**:右上角「下载 PDF」或「更多 → 导出 Word」。 5. **分享**:「更多 → 生成分享链接」,可设置有效期并复制链接。 6. **评分**:「更多 → 简历评分」,查看规则评分;登录后可用「LLM 智能评分」。 7. **导入**:「更多 → 智能导入」,粘贴旧简历文本或上传 PDF/Word,自动结构化。 8. **版本与回收站**:删除的简历进入回收站(30 天可恢复);编辑过程自动生成版本快照,可从「版本历史」回退。 --- ## 配置说明 环境变量见 `.env.example`: | 变量 | 必填 | 默认 | 说明 | |---|---|---|---| | `FLASK_ENV` | 否 | `dev` | `dev` / `test` / `prod` | | `SECRET_KEY` | 生产必填 | `dev-secret-change-in-prod` | JWT 签名密钥,生产需 ≥16 位随机串,否则拒绝启动 | | `DATABASE_URL` | 生产必填 | `sqlite:///resume.db` | 数据库地址 | | `LLM_API_KEY` | 否 | 空 | 大模型密钥(也可用 `SILICONFLOW_API_KEY`) | > 默认管理员账号与密码均为 `admin`(首次启动自动创建并存库)。 --- ## LLM 配置 配置采用**两级优先级**:用户自定义 > 系统默认。 ### 系统默认(管理员) - 在「管理后台 → 系统 LLM 配置」维护,存储于 `backend/config/llm.yaml`。 - 密钥**不落库**:通过 `LLM_API_KEY` 环境变量注入(`llm.yaml` 中 `api_key` 留空)。 - 支持 `siliconflow` / `openai` / `custom`(自定义 OpenAI 兼容地址)。 ### 用户自定义(普通用户) - 在「个人中心 → 自定义模型配置」填写供应商、Base URL、API Key、模型 ID,并可启用/删除。 - 启用后优先于系统默认;删除后回退到系统默认。 - 评分与建议**按任务类型取模型**:`models.default` / `models.scoring` / `models.suggestions`。 --- ## API 概览 统一响应格式:`{ "code": 0, "message": "ok", "data": ... }`(`code != 0` 表示错误)。 | 模块 | 端点 | 说明 | |---|---|---| | auth | `POST /api/auth/register` `POST /api/auth/login` | 注册 / 登录 | | | `GET /api/auth/me` `PUT /api/auth/me` | 当前用户信息 / 更新 | | | `POST /api/auth/change-password` | 修改密码 | | | `POST /api/auth/forgot-password` `POST /api/auth/reset-password` | 找回 / 重置密码 | | | `GET /api/auth/stats` | 个人统计 | | resumes | `GET/POST /api/resumes` | 列表 / 新建 | | | `GET/PUT/DELETE /api/resumes/` | 详情 / 保存 / 软删 | | | `POST /api/resumes//restore` `DELETE /api/resumes//permanent` | 恢复 / 彻底删除 | | | `POST /api/resumes//share` | 生成分享链接 | | | `GET/POST /api/resumes//versions` | 版本历史 / 快照 | | | `POST /api/resumes//versions//restore` | 回退版本 | | export | `POST /api/export/word` | 导出 Word | | parse | `POST /api/parse/resume` | 上传文件解析 | | llm | `GET/PUT /api/llm/system-config` | 系统配置(管理员) | | | `GET/PUT/DELETE /api/llm/user-config` | 用户配置 | | | `GET /api/llm/effective-config` | 生效配置(脱敏) | | | `POST /api/llm/score` `POST /api/llm/suggestions` | LLM 评分 / 建议 | | share | `GET /api/share/` | 公开分享(无需登录) | | styles | `GET/POST /api/styles` `PUT/DELETE /api/styles/` | 样式模板 | | admin | `GET/POST /api/admin/users` `PUT/DELETE /api/admin/users/` | 用户管理 | | | `POST /api/admin/users//reset-password` | 重置密码 | | | `GET /api/admin/resumes` `DELETE /api/admin/resumes/` | 全量简历 | | | `GET /api/admin/stats` | 数据统计 | | | `GET /api/admin/samples` | 示例简历 | > 除 `/api/auth/register`、`/api/auth/login`、`/api/auth/forgot-password`、`/api/auth/reset-password`、`/api/share/`、`/api/health`、`/api/admin/samples` 外,其余接口均需 `Authorization: Bearer `。 --- ## 数据模型 前端数据契约(`frontend/src/types/resume.ts`)核心结构: ```typescript interface Resume { // 基本信息 name: string jobTitle: string // 求职意向 phone: string email: string city: string // 意向地点 website: string // 个人网站/作品集 photo: string // 证件照(base64) showPhoto: boolean // 内容分区 educations: Education[] works: Work[] // 工作经历 internships: Work[] // 实习经历(结构同工作) projects: Project[] skills: string[] summary: string // 自我评价 certificates: Certificate[] languages: Language[] customModules: CustomModule[] // 用户自建模块 // 版式 templateId: string // classic / modern / compact sections: SectionConfig // 分区显隐 sectionOrder: SectionOrderItem[] // 分区顺序 fontFamily: FontFamily accentColor: string boldBody: boolean style: StyleConfig paperSize: PaperSize // 自定义字段 customFields: CustomField[] // 基本信息自定义字段 sectionFields: Partial> // 分区级 } interface Work { company: string title: string start: string end: string highlights: string[] // 旧版逐行要点(镜像保留) content?: string // 块级富文本(段落 + 有序/无序列表,优先) customFields?: CustomField[] } ``` > 旧数据兼容:`normalizeResume()` 会自动补全缺失字段、把旧版逐行要点迁移为块级内容、为各记录补上 `customFields`。 --- ## 测试 - **后端**:`cd backend && python -m pytest -q`(20 用例,覆盖认证/简历 CRUD/软删/分享/版本/越权/LLM 配置/重置密码等) - **前端**:`cd frontend && pnpm test`(Vitest,覆盖富文本解析/转义/空白折叠、规则评分) --- ## 部署 ### Docker Compose(推荐) ```bash cp .env.example .env # 填写 SECRET_KEY / DATABASE_URL / LLM_API_KEY docker compose up --build ``` - 后端:`backend/Dockerfile`(`gunicorn -w 2 -b 0.0.0.0:5000 wsgi:app`) - 前端:`frontend/Dockerfile`(多阶段构建 → nginx 托管静态产物,`/api` 反代到后端) - 数据卷:`backend/instance`(SQLite 落盘) ### 手动部署 ```bash # 后端(生产 WSGI) cd backend pip install -r requirements.txt gunicorn -w 2 -b 0.0.0.0:5000 wsgi:app # 前端(构建后由任意静态服务器托管,需反代 /api) cd frontend pnpm build # dist/ 部署到 nginx,并配置 /api 反代 ``` ### CI `.github/workflows/ci.yml` 在 push / PR 时自动执行:前端 `pnpm lint && pnpm build`,后端 `python -m pytest -q`。 --- ## 安全说明 - **JWT 鉴权**:`auth_required` 每次请求回查数据库,被禁用/降权/删除的账号立即失效。 - **找回密码**:不返回重置令牌、不泄露用户是否存在。 - **限流**:注册/登录/找回密码/重置密码均有速率限制。 - **密钥管理**:`SECRET_KEY`/`DATABASE_URL` 生产强制;LLM 密钥经环境变量注入,不入库。 - **归属隔离**:简历/样式/版本在 Repository 层统一按 `user_id` 过滤,越权写返回 403。 - **XSS**:富文本使用白名单 HTML,解析时转义并清洗脚本标签。 - **全局异常处理**:后端统一返回 JSON 错误,生产环境不泄露堆栈。 --- ## 目录结构 ``` . ├── backend/ │ ├── api/ # Flask 蓝图(auth/resumes/export/parse/llm/share/styles/admin) │ ├── services/ # 业务逻辑(auth/llm/score/rich_text) │ ├── repositories/ # 数据访问(归属隔离、软删除、版本、分享) │ ├── models/ # SQLAlchemy 模型 │ ├── config/ # LLM 配置(YAML) │ ├── tests/ # pytest │ ├── app.py # 应用工厂 │ ├── config.py # 环境配置(dev/test/prod) │ ├── extensions.py # db/cors/limiter │ ├── db_migrate.py # 数据库迁移 │ └── wsgi.py # 生产 WSGI 入口 ├── frontend/ │ ├── public/fonts/ # 中文字体子集(Noto Sans/Serif SC + 合成斜体) │ ├── src/ │ │ ├── types/ # 数据契约(前后端共享 JSON 结构) │ │ ├── store/ # Zustand 状态与自动保存 │ │ ├── pdf/ # PDF 模板(经典/现代/紧凑)与矢量图标 │ │ ├── components/ # 编辑器、预览、UI 组件 │ │ ├── pages/ # 列表/编辑/预览/分享/个人中心/管理后台 │ │ ├── services/ # api 客户端、本地存储、解析、云同步 │ │ └── lib/ # 富文本、评分等纯函数(含单测) │ ├── Dockerfile │ └── nginx.conf ├── .github/workflows/ci.yml ├── .env.example ├── docker-compose.yml └── README.md ``` --- ## 常见问题 **Q:不登录能用吗?** 可以。编辑、预览、导出、规则评分均为本地功能;登录后解锁云同步、LLM 评分、分享管理、个人中心。 **Q:数据存在哪里?** 默认 localStorage(`resume_library_v1` 等 key)。登录并同步后也会上传到后端 SQLite。 **Q:PDF 中文是斜体吗?** 中文字体本身无官方斜体,本项目通过 fontTools 合成了 12° 斜体子集,PDF 中的斜体为真实倾斜字形。 **Q:LLM 评分为何失败?** 请确认:已登录、管理员已在后台配置系统模型,或你已在个人中心配置自定义模型;且网络可访问对应 API。 **Q:默认管理员账号密码是什么?** 首次启动自动创建,账号与密码均为 `admin`(存库);登录后可通过「修改密码」自行修改。