# nest_langchain **Repository Path**: vmto/nest_langchain ## Basic Information - **Project Name**: nest_langchain - **Description**: 简历答题是一个基于 pnpm workspace 的全栈简历演示项目。它把 VueFlow 无限画布、NestJS 模块化后端、跨端 Zod 契约、技术答题、RAG 检索和 AI 内容优化组织成一条可运行的完整业务链路。 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-11-02 - **Last Updated**: 2026-11-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 简历答题 · 无限画布简历 简历答题是一个基于 pnpm workspace 的全栈简历演示项目。它把 VueFlow 无限画布、NestJS 模块化后端、跨端 Zod 契约、技术答题、RAG 检索和 AI 内容优化组织成一条可运行的完整业务链路。 项目包含两个应用和三个公共包: - `apps/resume-web`:Vue 3 前端。 - `apps/resume-api`:NestJS 后端。 - `packages/contracts`:跨端类型、常量与运行时 Schema。 - `packages/reactivity`:Vue 响应式组合式函数。 - `packages/shared`:无框架通用工具。 ## 实际功能 ### 用户与鉴权 - 注册、登录、刷新会话和退出。 - access token 短期有效,refresh token 使用 HttpOnly Cookie。 - 前端统一处理 `401` 刷新与请求重放。 - 管理员与普通用户共享登录体系,通过 `is_admin` 区分权限。 ### 模板与画布 - 首页展示产品能力,不直接堆叠模板列表。 - `/canvas` 同页切换“精选模板”和“我的画布”。 - 精选模板支持全部、VIP、免费筛选。 - 模板应用前显示 Popconfirm;同一用户对同一模板只能应用一次。 - 从模板创建或空白创建独立的简历文档。 - 简历卡片支持编辑、预览、删除和投稿。 - 我的画布支持导入 `.resume-canvas.json`,可将文件拖入项目区域,创建一份完整还原节点、连线和终点样式的新简历;当前画布从编辑器顶部导出。 ### VueFlow 简历编辑器 - 六类内容节点:个人简介、工作经历、项目经历、教育经历、专业技能、AI 建议;另有一个不可删除的简历生成终点。 - 左侧节点名称作为新节点默认标题;节点顶部不再重复显示类型标题。 - 双击内容节点可编辑标题、内容和成果列表,支持多个同类型节点。 - 支持添加、编辑、拖动、缩放、平移、连接终点和右键删除连线。 - 节点之间不能互相连接,所有入简历内容必须先连接终点。 - 只有连接到终点的节点会进入简历预览和 AI 整稿分析,未连接节点只保留在画布中。 - 只有终点节点提供“AI 整稿分析”和“生成简历”按钮。 - 双击终点可打开已连接节点排序,拖拽交换两个节点坐标并同步简历顺序;断线节点不会出现在排序列表。 - 节点编辑弹窗分别对“内容”和“成果列表”提供 AI 润色,按钮位于对应字段标题右侧;两项可独立预览、应用或取消。 - 只有终点节点可选择主题色和装饰线颜色,所有简历 section 统一使用该全局外观。 - 后台模板编辑与画布终点共用同一套主题色、装饰线令牌;后台保存后直接写入模板终点,`skinKey` 不再隐式覆盖颜色。 - 后台模板编辑弹窗实时渲染真实模板简历;画布修改外观时,已打开的独立预览窗口通过同源频道即时同步,无需刷新。 - 自动保存使用 1.2 秒防抖。 - 编辑器历史记录以左侧浮层覆盖节点组件栏;点击条目只读渲染并暂停自动保存,不会自动新增历史;用户仍可手动点击“保存”将预览内容写为新版本。 - 保存请求携带版本号,冲突时返回 `409`,允许载入服务端版本后继续编辑。 - 编辑器顶部支持导出当前画布,以及追加导入画布文件;导入时自动重映射节点 ID,并通过终点恢复有效的简历引用关系。 - `/preview/:id` 只展示简历 section 与页尾,不包含站点导航、简历页头、标题或操作工具栏,可直接打印。 ### AI 能力 - LangChain 负责 Prompt、聊天模型和结构化输出调用。 - LangGraph 负责 `generate -> critique -> repair` 条件修复流程。 - Ollama 是默认主模型,本地服务不可用且配置了 DeepSeek Key 时自动兜底。 - 单节点生成结果经过 Zod 校验后才返回前端。 - 模型不可用时使用本地安全规则生成可编辑建议。 - AI 只生成建议,用户确认后通过统一简历保存接口写回。 - DeepSeek 未配置或同样不可用时,使用本地安全规则继续生成可编辑建议。 - Embedding 不可用时使用确定性本地向量,不阻塞答题检索。 ### 技术答题与动态 VIP - 三个题库分类:前端、后端、AI 工程。 - 每个分类每次固定 10 题,服务端判分。 - 首次答题使用静态基础题,后续从数据库题库确定性随机抽取。 - RAG 返回相关证据、来源、向量相关度和综合相关度。 - 历史均分覆盖所有答题记录:均分达到 80 时启用 VIP,跌破 80 时自动失效。 ### 投稿与管理后台 - 用户可将本人简历投稿为精选模板,并可更新投稿内容。 - 管理员可管理用户状态和管理员权限。 - 管理员可审核投稿、调整 VIP 要求、启用或禁用模板。 - 管理员模板管理将“投稿审核”和“全部模板”合并为单视图 Tab,Tab 与当前筛选位于同一工具栏行。 - 管理员可编辑模板标题、选择动态皮肤文件、预览模板、开关模板并删除模板。 - 管理员可查看全部答题记录,并按题库分类筛选。 ### 设计系统 - 科技蓝主题由 CSS 变量和 Tailwind 语义 token 驱动。 - 统一 hover、active、focus-visible、disabled、loading 和 reduced-motion 状态。 - 页面与业务组件使用 Tailwind `@apply` 和语义化 class。 - 全局最小正文为 14px;独立数字徽标使用 12px,并扩大容器避免裁切。 - 所有实际路由使用统一 `AppNavigation`,移动端自动折叠。 ## 全栈架构 ```mermaid flowchart LR Browser[浏览器] Web[apps/resume-web
Vue 3 + Vite] API[apps/resume-api
NestJS] DB[(MySQL)] Browser --> Web Web -->|/api · Axios| API API -->|TypeORM| DB Contracts[packages/contracts] Reactivity[packages/reactivity] Shared[packages/shared] Contracts -. 类型与 Zod .-> Web Contracts -. 类型与 Zod .-> API Reactivity -. 响应式状态 .-> Web Shared -. 纯工具函数 .-> Web Shared -. 纯工具函数 .-> API ``` ### 请求链路 1. 页面通过 `src/api/*` 调用 `/api`。 2. Axios 客户端附加 access token,并在必要时刷新登录态。 3. Nest Controller 接收请求,Guard 校验登录或管理员权限。 4. Service 执行归属校验、事务、乐观锁和业务规则。 5. TypeORM 读写 MySQL,统一返回 `{ code, msg, data }`。 6. 前端使用 `@resume/contracts` 中的类型消费响应。 ### 后端模块 ```text AuthModule 登录、注册、刷新、会话 TemplatesModule 精选模板与 VIP 可见性 ResumesModule 简历文档、历史快照、保存、恢复、删除、模板克隆 SubmissionsModule 投稿与个人投稿状态 ResumeAiModule LangChain / LangGraph / 整稿分析 QuizModule 题库、判分、历史均分、动态 VIP RagModule 知识文档、分块、向量与证据召回 AdminModule 用户、投稿、模板和答题记录管理 ``` TypeORM 采用 `synchronize: false`,表结构通过 `terminal/apply-*-schema.mjs` 迁移脚本维护。业务表共 10 张: ```text demo_user demo_user_session demo_resume_template demo_resume_document demo_resume_history demo_resume_submission demo_quiz_attempt demo_knowledge_document demo_knowledge_chunk demo_quiz_question ``` ## 五个子包 | 子包 | 简介 | 关键内容 | | --- | --- | --- | | [`@resume/web`](apps/resume-web/readme.md) | Vue 3 前端应用 | 路由、Pinia、VueFlow、页面、模板、答题、后台、设计系统 | | [`@resume/api`](apps/resume-api/readme.md) | NestJS 后端应用 | 鉴权、简历、投稿、题库、RAG、AI、管理员接口 | | [`@resume/contracts`](packages/contracts/readme.md) | 跨端契约包 | 领域类型、常量、Zod Schema、默认图数据 | | [`@resume/reactivity`](packages/reactivity/readme.md) | Vue 状态逻辑包 | `useAsyncTask`、`useDebouncedSave`、`useResumeGraph` | | [`@resume/shared`](packages/shared/readme.md) | 无框架工具包 | JSON、防抖、日期、VIP 判断、本地向量、余弦相似度 | ### `@resume/web` 负责所有用户可见界面:首页、登录、画布工作台、简历编辑器、独立预览、个人中心、答题中心和管理后台。API 调用、登录态、路由守卫和设计令牌都在应用内部收口。 ### `@resume/api` 负责 API、鉴权、权限、事务和持久化。Controller 只处理 HTTP 和当前用户,Service 负责业务规则,Entity 跟随业务模块;`AppModule` 只组合模块。 ### `@resume/contracts` 同时服务前后端的唯一协议来源。新增接口时先定义类型与 Zod Schema,再实现 API 和页面,避免两端结构漂移。 ### `@resume/reactivity` 封装编辑器内可复用的响应式状态生命周期。它不依赖 Router、Toast 或具体 API,通过回调解耦网络请求。 ### `@resume/shared` 提供浏览器和 Node.js 都可使用的纯 TypeScript 工具。不得依赖 Vue、NestJS、DOM 或数据库。 ## 前端路由 | 路径 | 功能 | 权限 | | --- | --- | --- | | `/` | 产品首页 | 公开 | | `/login` | 登录/注册 | 公开 | | `/canvas` | 精选模板 + 我的画布 | 模板公开,个人内容需登录 | | `/editor/:id` | 简历编辑器 | 登录 | | `/preview/:id` | 新窗口预览 | 登录 | | `/user` | 个人中心 | 登录 | | `/quiz` | 技术答题 | 登录 | | `/skins/:skin` | 动态简历皮肤预览 | 公开 | | `/admin/users` | 用户管理 | 管理员 | | `/admin/templates` | 模板与投稿审核 | 管理员 | | `/admin/quiz-attempts` | 答题记录 | 管理员 | ## 目录结构 ```text nomorepo-demo/ ├─ apps/ │ ├─ resume-api/ # NestJS 后端 │ └─ resume-web/ # Vue 3 前端 ├─ packages/ │ ├─ contracts/ # 跨端契约 │ ├─ reactivity/ # Vue 响应式工具 │ └─ shared/ # 通用纯函数 ├─ scripts/ │ ├─ resume.js # 公共包 esbuild 构建器 │ └─ resume_demo.sql # 数据库结构与演示数据入口 ├─ terminal/ # 检查、种子、启动和冒烟脚本 ├─ temp/ # 运行日志、状态和验收产物 ├─ pnpm-workspace.yaml └─ package.json ``` `apps/resume-web/src/components/skins` 抽离皮肤纸张、页头、页尾、section、section 标题和装饰线;`apps/resume-web/src/pages/skins` 通过动态路由匹配四个皮肤页面。 ## 本地启动 环境要求: - Node.js - pnpm 10 - MySQL 8 - Ollama 主模型;DeepSeek 作为可选兜底,仅在配置 API Key 时启用 安装依赖: ```text pnpm install ``` 准备数据库并参考 `apps/resume-api/.env.example` 配置后端环境变量。启动前后端: ```text node terminal/start-stack.mjs ``` 脚本会探测空闲端口,并将实际 Web/API 地址写入 `temp/stack-state.json`。停止: ```text node terminal/stop-stack.mjs ``` 也可以分别运行: ```text pnpm --filter @resume/api start:dev pnpm --filter @resume/web dev ``` ## 数据初始化 常用脚本: ```text node terminal/seed-resume-demo.mjs node terminal/apply-admin-quiz-schema.mjs node terminal/seed-rag-knowledge.mjs ``` 种子脚本应保持幂等;不要在重复执行时清空用户已有简历或未知数据。 ## 构建与校验 公共包: ```text node terminal/check-contracts.mjs ``` 后端: ```text node terminal/check-api.mjs ``` 前端: ```text node terminal/check-web.mjs ``` 数据库与文档: ```text node terminal/check-db.mjs node terminal/check-readmes.mjs php terminal/check-files.php ``` 核心 HTTP 冒烟: ```text node terminal/smoke-resume-demo.mjs ``` 全部 Node/PHP 检查脚本都从仓库根目录执行,日志和临时文件写入 `temp/`。 ## 核心约束 - 客户端不能提交或覆盖 `user_id`,资源归属以服务端登录态为准。 - 简历保存必须使用乐观锁,不允许静默覆盖版本冲突。 - 画布交换文件必须包含版本标记并通过共享 Zod Schema 校验;导入追加节点,不覆盖当前画布,文件上限为 5MB。 - 模板克隆、投稿和 AI 建议不能直接共享可变图对象。 - 答案和判分逻辑保留在服务端。 - VIP 由历史答题均分实时计算,不是永久标记。 - 新接口先更新公共契约,再修改前后端。 - 主题色和装饰线的可选值统一来自 `RESUME_SKIN_COLOR_TOKENS`;皮肤文件只负责纸张明暗和结构,不覆盖颜色令牌。 - 密码、JWT、Cookie、数据库凭据和模型 API Key 不得进入前端或日志。 - 命令执行和自动化检查优先使用 Node/PHP 脚本,避免 Windows 命令壳吞掉特殊字符。 ## 延伸文档 - [全栈工程实践系列](docs/article/README.md) - [后端应用说明](apps/resume-api/readme.md) - [前端应用说明](apps/resume-web/readme.md) - [跨端契约](packages/contracts/readme.md) - [响应式工具](packages/reactivity/readme.md) - [通用工具](packages/shared/readme.md) - [Ollama 与模型兜底说明](docs/ollama.md)