Resume-Matcher 前端 API 客户端层全解析:从 API Base 到 LLM 配置与看板追踪
【免费下载链接】Resume-MatcherThe #1 AI Harness for Building Resumes, PDFs, Cover Letters & more, locally with 100+ LLMs support.项目地址: https://gitcode.com/GitHub_Trending/re/Resume-Matcher
本文基于 docs/agent/apis/front-end-apis.md 撰写,围绕 Resume-Matcher 前端
lib/api/*客户端层展开。Resume-Matcher 是一套本地运行的 AI 简历构建工具(支持简历上传、PDF 生成、求职信与 100+ LLM 接入),本文通过阅读 apps/frontend/lib/api/ 下client.ts、resume.ts、resume-wizard.ts、tracker.ts、config.ts的实际源码,并结合 apps/backend/app/routers/ 中resumes.py、resume_wizard.py、applications.py、config.py的后端实现,完整拆解前端 API 层的模块划分、请求封装、超时策略、错误处理与调用约定。读完本文,你将能熟练定位任何前端功能对应的 API 函数、理解其请求路径与后端行为,并掌握自定义调用(如直接请求 PDF、批量更新看板卡片)的正确姿势。
一、客户端层整体架构:单一入口,统一导出
前端 API 层集中在 apps/frontend/lib/api/ 目录,按业务域拆分为五个模块,并通过 apps/frontend/lib/api/index.ts 统一导出:
| 模块文件 | 业务域 | 核心导出 |
|---|---|---|
client.ts | 基础客户端 | API_URL、API_BASE、apiFetch、apiPost、apiPatch、apiPut、apiDelete、getUploadUrl、DEFAULT_TIMEOUT_MS |
resume.ts | 简历操作 | uploadJobDescriptions、improveResume、previewImproveResume、confirmImproveResume、fetchResume、fetchResumeList、updateResume、deleteResume、downloadResumePdf、downloadCoverLetterPdf及各类生成函数 |
resume-wizard.ts | 简历向导 | postResumeWizardTurn、finalizeResumeWizard、createInitialResumeWizardState及状态类型 |
tracker.ts | 求职追踪看板 | listApplications、createApplication、getApplicationDetail、updateApplication、bulkUpdateStatus、deleteApplication、bulkDeleteApplications |
config.ts | 配置中心 | fetchLlmConfig、updateLlmConfig、testLlmConnection、fetchSystemStatus、API Keys 管理、Feature Flags、语言与 Prompt 配置、PROVIDER_INFO |
从index.ts的导出清单可以看到,它还额外导出了previewImproveResume、confirmImproveResume(改进预览与确认)、fetchPromptConfig、updatePromptConfig等原文档未展开的函数,这些会在后文结合源码逐一说明。index.ts同时导出了全部 TypeScript 类型(如ResumeListItem、LLMConfig、SystemStatus、ResumeWizardState),组件层只需import { fetchResume, API_BASE, PROVIDER_INFO } from '@/lib/api'一条语句即可按需取用。
二、Base Client:请求基座的三个关键设计
2.1 API 地址解析:默认同源代理,支持外部后端
apps/frontend/lib/api/client.ts 定义了 API 地址的完整解析链路:
const DEFAULT_PUBLIC_API_URL = '/'; const INTERNAL_API_ORIGIN = 'http://127.0.0.1:8000'; export const API_URL = normalizeApiUrl(process.env.NEXT_PUBLIC_API_URL ?? DEFAULT_PUBLIC_API_URL); export const API_BASE = resolveRuntimeApiBase(toApiBase(API_URL));解析规则可以归纳为三层:
- 默认值:
NEXT_PUBLIC_API_URL未设置时回退为/(同源部署,由 Next.js 反向代理到后端); - 规范化:
normalizeApiUrl会去掉末尾斜杠,空串或/保持原样,避免拼接出//api/v1这类脏路径; - 运行时修正:
resolveRuntimeApiBase在服务端渲染(SSR)场景下(typeof window === 'undefined'且路径以/开头)自动补全为http://127.0.0.1:8000,保证服务端组件同样能访问后端;浏览器端则直接使用相对路径。
最终API_BASE形如/api/v1(同源)或http://localhost:8000/api/v1(显式配置外部后端),所有业务请求都拼在API_BASE之后。
2.2 三层超时联动机制:一个环境变量驱动全局
client.ts中有一段非常值得注意的超时设计(apps/frontend/lib/api/client.ts):
const rawTimeoutMs = process.env.NEXT_PUBLIC_REQUEST_TIMEOUT_MS; const parsedTimeoutMs = rawTimeoutMs ? Number(rawTimeoutMs) : NaN; export const DEFAULT_TIMEOUT_MS = Number.isFinite(parsedTimeoutMs) ? Math.min(1_800_000, Math.max(30_000, parsedTimeoutMs)) : 240_000;代码注释明确说明:DEFAULT_TIMEOUT_MS必须与后端REQUEST_TIMEOUT_SECONDS(见 apps/backend/app/config.py)以及 Next.js 的proxyTimeout(见 apps/frontend/next.config.ts)保持一致——三层中先到时的层会先中止请求,所以三者的取值统一由同一个NEXT_PUBLIC_REQUEST_TIMEOUT_MS驱动。默认值 240 秒(4 分钟),并通过Math.min(1_800_000, Math.max(30_000, ...))夹在 30 秒到 30 分钟之间。注释特别提醒:本地 LLM(如 Ollama)生成简历通常很慢,240 秒默认值常常不够,需要调大该变量并同步后端REQUEST_TIMEOUT_SECONDS。
2.3 标准 fetch 封装与超时中止
apiFetch(apps/frontend/lib/api/client.ts)是唯一真正发请求的函数:
- 端点路径以
/开头时自动与API_BASE拼接;传入绝对 URL(http(s)://)或/api/开头的路径时则直接使用原值(后一种情况再次经过resolveRuntimeApiBase,保证 SSR 下仍能命中127.0.0.1:8000); - 使用
AbortController实现超时中止,超时后抛出带诊断提示的错误:"如果运行本地 LLM,请增大NEXT_PUBLIC_REQUEST_TIMEOUT_MS(并同步后端REQUEST_TIMEOUT_SECONDS)"; apiPost<T>、apiPatch<T>、apiPut<T>、apiDelete是基于apiFetch的语义化薄封装,自动设置Content-Type: application/json并序列化 body(apiPost额外支持透传timeoutMs,供长耗时调用覆盖默认超时);getUploadUrl()返回${API_BASE}/resumes/upload,供文件上传(multipart/form-data)使用。
需要指出的是,apiFetch采用返回Response而非解析后的 JSON的约定,各业务模块(如postImprove)在拿到Response后自行判断res.ok、读取错误体并抛出自定义错误,这也是错误信息能携带后端detail文本的原因。
三、Resume Operations:简历全生命周期 API
apps/frontend/lib/api/resume.ts 是最大的一块,覆盖 JD 上传、定制化改进、CRUD、PDF 下载与按需内容生成。
3.1 JD 上传与改进管线(upload → improve)
uploadJobDescriptions(descriptions: string[], resumeId):POST /api/v1/jobs/upload,body 为{ job_descriptions, resume_id },从响应中取data.job_id[0]返回单个job_id;improveResume(resumeId, jobId, promptId?):POST /resumes/improve,body 为{ resume_id, job_id, prompt_id },返回完整的ImprovedResult(含改进后的简历数据、逐条 diff 说明等);previewImproveResume(resumeId, jobId, promptId?):POST /resumes/improve/preview——预览模式不落库,返回resume_id: null,供用户确认前对比;confirmImproveResume(payload):POST /resumes/improve/confirm,提交{ resume_id, job_id, improved_data, improvements },把用户确认后的改进结果正式保存为定制版简历。
三个函数都经由私有postImprove走统一错误路径(apps/frontend/lib/api/resume.ts):显式传入DEFAULT_TIMEOUT_MS(改进调用可能很慢)、失败时打印响应体、成功时JSON.parse结果。源码注释表明这条路径对应 issue #776——让NEXT_PUBLIC_REQUEST_TIMEOUT_MS真正作用于耗时的 improve/preview/confirm 调用。
后端对应实现位于 apps/backend/app/routers/resumes.py:improve/preview使用asyncio.wait_for包裹整个改进流程,超时返回 504 并给出同样指向REQUEST_TIMEOUT_SECONDS的提示(resumes.py)。从后端流程可以看到,preview内部执行的是基于 diff 的改进:先generate_skill_target_plan生成技能目标计划并校验,再generate_resume_diffs产出逐条改动、apply_diffs应用并verify_diff_result验证;随后还有一组防御性的安全网——_preserve_personal_info(个人联系方式强制保留原值)、_restore_original_dates(恢复 LLM 可能截断的月份日期)、_preserve_original_skills(技能/证书/语言/奖项绝不允许丢失)、_protect_custom_sections(防自定义段落幻觉)。这些机制解释了为什么预览/确认流程需要完整的improvements列表回传——后端在confirm时会对personalInfo做逐字段一致性校验(_validate_confirm_payload),确保 LLM 不会篡改联系方式。
3.2 简历 CRUD
fetchResume(resumeId):GET /resumes?resume_id=...,返回ResumeResponse['data'],同时携带raw_resume(原始 markdown)与processed_resume(结构化 JSON,若 LLM 解析成功);源码注释提醒:viewer/builder 应优先使用 processed 数据;fetchResumeList(includeMaster = false):GET /resumes/list?include_master=...,默认不包含主简历(master resume),返回按updated_at倒序的ResumeListItem[];updateResume(resumeId, resumeData):PATCH /resumes/{id},把 builder 编辑后的ProcessedResume写回;deleteResume(resumeId):DELETE /resumes/{id};- 另外源码还提供了文档未列出的
renameResume(resumeId, title)(PATCH /resumes/{id}/title)与retryProcessing(resumeId)(POST /resumes/{id}/retry-processing,用于重试失败的 LLM 解析)。
3.3 PDF 下载:模板参数如何传递
downloadResumePdf/getResumePdfUrl是最容易用错的函数,因为它把整套模板排版设置序列化成了 URL 查询参数(apps/frontend/lib/api/resume.ts)。getResumePdfUrl(resumeId, settings?, locale?)生成的 URL 形如:
{API_BASE}/resumes/{resume_id}/pdf?template=swiss-single&pageSize=A4&marginTop=...§ionSpacing=...&lineHeight=...&fontSize=...&accentColor=...&lang=...关键点:
- 传
settings时,模板、纸张(pageSize)、四边距(marginTop/Bottom/Left/Right)、段落间距(sectionSpacing)、行距(lineHeight)、字号与页眉缩放(fontSize)、页眉/正文字体、紧凑模式(compactMode)、联系图标开关(showContactIcons)、强调色(accentColor)都会被序列化为参数; - 不传
settings时只发送template=swiss-single&pageSize=A4两个默认参数——也就是说默认模板是swiss-single、默认纸张是 A4; - 可选
locale追加lang参数,控制 PDF 中的日期/文案本地化。
downloadCoverLetterPdf(resumeId, pageSize = 'A4', locale?)走{API_BASE}/resumes/{id}/cover-letter/pdf,pageSize仅接受'A4' | 'LETTER'。此外源码还提供generateCoverLetter(POST /resumes/{id}/generate-cover-letter)与generateOutreachMessage(POST /resumes/{id}/generate-outreach),它们不返回 Blob 而是返回data.content文本。
3.4 按需生成内容
generateInterviewPrep(resumeId):POST /resumes/{id}/generate-interview-prep,响应体为{ interview_prep: InterviewPrepData },函数内已解包,直接返回InterviewPrepData;fetchJobDescription(resumeId):GET /resumes/{id}/job-description,返回{ job_id, content },用于在定制简历详情页回显当初使用的 JD。
后端配套的interview_prep在数据库中以 JSON 字符串存储,读取时由_parse_interview_prep反序列化并容错(解析失败返回 null 而不报错,见 resumes.py)。
四、Resume Wizard:AI 引导式问答建简历
resume-wizard.ts封装了一个与上传解析相互独立的简历构建流程:不依赖任何 JD,由 LLM 一次一个问题引导用户填出一份通用主简历。
4.1 状态模型
核心类型(apps/frontend/lib/api/resume-wizard.ts):
ResumeWizardSection:intro | contact | summary | workExperience | internships | education | personalProjects | skills | review九个阶段;ResumeWizardStep:intro | question | review | complete四步 UI 状态;ResumeWizardAction:start | answer | skip | back | review五种动作;ResumeWizardState:包含step、resume_data(累积的简历草稿)、current_question、history(含每次回答前的resume_data_before快照,供回退使用)、asked_count、inferred_skills(LLM 推断出的技能)、is_complete、progress({current, total},初始 8 题)、warnings。
createInitialResumeWizardState()在本地直接构造初始状态,第一个问题是固定常量INTRO_QUESTION:"Hi — I'll help you build your master resume. What's your name, and what kind of role are you going for?",progress.total为 8。
4.2 两个后端端点
postResumeWizardTurn(payload):POST /api/v1/resume-wizard/turn,请求体为{ state, action, answer? },响应{ state }——完整状态在请求与响应之间往返。后端行为(apps/backend/app/routers/resume_wizard.py):start直接返回build_initial_wizard_state();back/review走确定性逻辑(apply_back/apply_review),不消耗 LLM 调用;answer/skip调用run_ai_turn执行一次 AI 生成,更新resume_data,返回下一个current_question、inferred_skills与is_complete标志;- 成本护栏:一旦
asked_count >= RESUME_WIZARD_MAX_QUESTIONS(后端常量),answer/skip不再发 LLM 请求,直接转为apply_review。
finalizeResumeWizard(state):POST /api/v1/resume-wizard/finalize,把草稿落库为主简历。后端用normalize_resume_data规范化数据后,通过create_resume_atomic_master原子创建主简历(标题自动生成为"{姓名} Master Resume");若已存在processing_status == "ready"的主简历则返回409。finalize的响应类型ResumeWizardFinalizeResponse承诺processing_status: 'ready'与is_master: true。
原文档特别强调:向导的问题与内容文本使用配置的 content language 生成,而静态 UI 文案走resumeWizard.*i18n 键(对应 apps/frontend/messages/ 下各语言 JSON)。该流程不依赖 JD、也不取代上传解析器——两种方式最终都汇入主简历体系。
五、Application Tracker:七列看板的 API 约定
apps/frontend/lib/api/tracker.ts 实现求职追踪看板,七个状态列是稳定键(不随 i18n 标签变化):saved | applied | no_response | response | interview | accepted | rejected,顺序常量APPLICATION_STATUS_ORDER与后端APPLICATION_STATUS_ORDER(见 apps/backend/app/routers/applications.py)一一对应。
5.1 单卡片与看板
listApplications():GET /applications(注意带credentials: 'include'),返回{ columns: Record<status, Application[]> },后端_group_by_status保证七个键始终存在,未知状态的行被跳过而非让整个看板 500;createApplication(payload):POST /applications,从粘贴的 JD 手动建卡。后端会先create_job,公司/职位缺失时用extract_job_keywords做 best-effort 提取,创建失败时清理孤儿 job(见 applications.py);getApplicationDetail(id):GET /applications/{id},一次往返同时取回内嵌 JD(job_content)与所用简历(resume);简历被删除时返回resume: null而非 500(后端get_application_detail对详情加载全程 try/except);updateApplication(id, payload):PATCH /applications/{id},可更新status/position/notes/company/role/applied_at,后端用model_dump(exclude_unset=True)只更新出现的字段。
5.2 批量操作
bulkUpdateStatus(applicationIds, status):PATCH /applications/bulk,body{ application_ids, status },一次移动多张卡到同一列,返回{ message, affected };bulkDeleteApplications(applicationIds):POST /applications/bulk-delete,body{ application_ids };deleteApplication(id):DELETE /applications/{id}。
5.3 值得借鉴的错误处理
tracker.ts中的extractDetail(apps/frontend/lib/api/tracker.ts)是一个处理 FastAPI 错误体的通用工具:FastAPI 的HTTPException返回字符串detail,而校验错误返回[{ msg, loc, ... }]数组,extractDetail将两者统一转为可读字符串,并兜底把 dict 形式的detailJSON.stringify——保证错误信息永远不会渲染成 "[object Object]"。asJson<T>封装在此基础上统一抛错,可作为前端调用其他 FastAPI 服务的参考模板。
六、Config Operations:配置中心与密钥管理
apps/frontend/lib/api/config.ts 覆盖 LLM 配置、健康检查、API Key 加密存储、功能开关、语言与 Prompt 配置。
6.1 LLM 配置与连接测试
fetchLlmConfig():GET /config/llm-api-key(带credentials: 'include'),返回LLMConfig;updateLlmConfig(config):PUT /config/llm-api-key;testLlmConnection(config?):POST /config/llm-test——可选传入待测试配置(用于保存前预检),不传则测当前存储配置;返回LLMHealthCheck,含healthy、error/error_code、warning/warning_code、test_prompt、model_output、reasoning_content等诊断字段。
6.2 API Key 的加密存储设计(重要变更)
原文档明确标记了一条行为变更:updateLlmApiKey(PUT /config/llm-api-key)已不再持久化密钥,密钥改为通过加密的按 provider 维度/config/api-keys端点管理。源码印证(config.ts 注释):旧设计把单个api_key槽位写入配置,正是导致不同 provider 互相覆盖、遮蔽 per-provider 密钥表的根因;现在request.api_key仅保留在 schema 中用于响应掩码与向后兼容。
新的密钥 API 一族:
fetchApiKeyStatus():GET /config/api-keys,返回{ providers: [{ provider, configured, masked_key }] },masked_key形如sk-a******xxxx(后端_mask_api_key:保留前 4 后 4,中间星号,长度 ≤8 时全星号);updateApiKeys(keys):POST /config/api-keys,可同时更新多个 provider 的密钥,返回{ message, updated_providers };deleteApiKey(provider):DELETE /config/api-keys/{provider};clearAllApiKeys():DELETE /config/api-keys?confirm=CLEAR_ALL_KEYS——清空全部密钥需要显式 confirm 参数,防止误操作;- 配套的
resetDatabase():POST /config/reset,同样需要{ confirm: 'RESET_ALL_DATA' }。
注意两个 provider 命名轴的区别:LLMProvider(活跃 provider)与ApiKeyProvider(密钥存储名)。llmProviderToKeyProvider实现了映射——gemini 的密钥存在google名下(gemini → google),其余 provider 直通,与后端_PROVIDER_KEY_MAP保持一致。
6.3 Feature Flags、语言与 Prompt 配置
fetchFeatureConfig()/updateFeatureConfig():GET/PUT /config/features,三个布尔开关enable_cover_letter、enable_outreach_message、enable_interview_prep,控制定制简历后是否自动生成求职信、外联消息与面试准备内容;fetchLanguageConfig()/updateLanguageConfig():GET/PUT /config/language,SupportedLanguage为'en' | 'es' | 'zh' | 'ja' | 'pt' | 'fr';LanguageConfig区分ui_language(界面语言)与content_language(AI 生成内容语言);fetchPromptConfig()/updatePromptConfig():GET/PUT /config/prompts,切换简历改进默认 Prompt(default_prompt_id+ 可用选项列表);fetchFeaturePrompts()/updateFeaturePrompts():GET/PUT /config/feature-prompts,自定义求职信与外联消息 Prompt。这个函数的错误处理最为细致:422 且detail.code === 'missing_placeholders'时抛出专属FeaturePromptsError(携带缺失占位符列表missing: string[],UI 可精确定位缺了哪些 token);其余情况把字符串/dict/缺失三种 detail 形态分别归一为可读消息;成功路径则不吞 JSON 解析错误,避免静默返回字段缺失的对象。
七、Provider Info:受支持 LLM 提供方清单
config.ts中的PROVIDER_INFO是前端渲染 provider 选择器的数据源(apps/frontend/lib/api/config.ts),当前实际源码比原文档多出一个groq与openai_compatible条目:
| provider | 显示名 | defaultModel | requiresKey |
|---|---|---|---|
openai | OpenAI | gpt-5-nano-2025-08-07 | true |
openai_compatible | OpenAI-Compatible (Local) | custom-model | false |
anthropic | Anthropic | claude-haiku-4-5-20251001 | true |
openrouter | OpenRouter | deepseek/deepseek-chat | true |
gemini | Google Gemini | gemini-3-flash-preview | true |
deepseek | DeepSeek | deepseek-chat | true |
groq | Groq | llama-3.3-70b-versatile | true |
ollama | Ollama (Local) | gemma3:4b | false |
几个实现细节:
openai_compatible是本地模型接入的关键入口:注释明确它面向 llama.cpp、vLLM、LM Studio 等暴露 OpenAI Chat Completions API 的服务器,密钥可选(后端在空白时发送哨兵值),默认模型名占位custom-model,需配合api_base指向本地端点;requiresKey: false的只有openai_compatible与ollama(本地服务无需鉴权);- 默认模型均为硬编码常量,实际生效模型以配置为准(后端
get_llm_config_endpoint优先读 config 文件,再回退settings.llm_model)。
LLMConfig还包含reasoning_effort字段('minimal' | 'low' | 'medium' | 'high' | null),null表示不发送该参数(最大兼容性);updateLlmConfig中传空串''表示清除,null则被服务器忽略。后端同时做了api_base的空值规范化(config.py):空白字符串被归一为None,避免空端点泄漏给 LiteLLM。
八、Usage:最小调用示例与实战建议
原文档给出的调用方式(docs/agent/apis/front-end-apis.md):
import { fetchResume, API_BASE, PROVIDER_INFO } from '@/lib/api';基于以上源码分析,可以补充几个实战调用模式:
// 1. 拉取简历列表(排除主简历)并取回详情 const items = await fetchResumeList(); const detail = await fetchResume(items[0].resume_id); const { processed_resume, cover_letter } = detail; // 2. 定制化:上传 JD → 预览改进 → 确认落库 const jobId = await uploadJobDescriptions([jdText], resumeId); const preview = await improveResume(resumeId, jobId); // 或 previewImproveResume 先预览 await confirmImproveResume({ resume_id: resumeId, job_id: jobId, improved_data: preview.resume_data, improvements: preview.improvements }); // 3. 生成 PDF(注意 settings 序列化为查询参数) const blob = await downloadResumePdf(resumeId, templateSettings, 'zh'); const url = URL.createObjectURL(blob); // 4. 看板批量移动 await bulkUpdateStatus([id1, id2], 'interview'); // 5. 本地模型接入:openai_compatible + 自定义 base await updateLlmConfig({ provider: 'openai_compatible', model: 'qwen2.5:7b', api_base: 'http://localhost:1234/v1' }); await updateApiKeys({ openai_compatible: 'sk-local' }); // 本地服务器要求鉴权时实际使用中的注意事项:
- 超时参数三处同步:任何修改
NEXT_PUBLIC_REQUEST_TIMEOUT_MS的部署,都必须同步后端REQUEST_TIMEOUT_SECONDS与 apps/frontend/next.config.ts 的proxyTimeout,否则最短的一层会先中止; - SSR 场景:
API_BASE在服务端自动解析为http://127.0.0.1:8000,因此后端必须监听 8000 端口或调整INTERNAL_API_ORIGIN;若后端部署在其他地址,需通过NEXT_PUBLIC_API_URL显式配置并保持前后端同源/跨域配置一致; - 密钥管理走新端点:新代码一律使用
updateApiKeys/fetchApiKeyStatus,不要再依赖updateLlmApiKey持久化密钥; - Provider 命名轴:更新密钥前用
llmProviderToKeyProvider(provider)换算存储名(gemini → google); - 看板错误处理:批量操作与卡片更新建议复用
extractDetail语义,展示后端detail而非笼统状态码。
九、与前端组件的对应关系
API 层的调用方分布在 apps/frontend/components/ 与 apps/frontend/hooks/:
resume.ts服务于 dashboard 的简历列表/上传(apps/frontend/components/dashboard/resume-upload-dialog.tsx)、tailor 定制页(apps/frontend/app/(default)/tailor/page.tsx/tailor/page.tsx))与 PDF 预览(apps/frontend/components/preview/paginated-preview.tsx);resume-wizard.ts被 apps/frontend/hooks/use-enrichment-wizard.ts 及 apps/frontend/components/resume-wizard/resume-wizard-page.tsx 使用,配合live-preview.tsx实现边答边预览;tracker.ts支撑 apps/frontend/components/tracker/kanban-board.tsx 与 apps/frontend/components/tracker/manual-add-application-dialog.tsx;config.ts驱动 apps/frontend/app/(default)/settings/page.tsx/settings/page.tsx) 中的 LLM 配置、密钥管理与语言设置面板。
前端测试对 API 层有完整覆盖(如 apps/frontend/tests/api-client.test.ts、apps/frontend/tests/api-resume.test.ts、apps/frontend/tests/api-tracker.test.ts、apps/frontend/tests/resume-wizard-api.test.ts),后端集成测试则位于 apps/backend/tests/integration/(如test_resume_api.py、test_resume_wizard_api.py、test_tracker_autocreate.py、test_config_api.py),阅读这些测试可以进一步确认各端点的精确请求/响应形状与边界行为(如 409 冲突、404 兜底)。
十、小结
Resume-Matcher 前端 API 层的设计可以总结为四个要点:单一基座(client.ts集中管理地址解析、超时与错误)、业务域分模块(resume / resume-wizard / tracker / config 各自封装领域类型与端点)、后端契约驱动(类型定义与 apps/backend/app/schemas/ 的 Pydantic 模型对齐,如ResumeData、ApplicationStatus)、安全与可观测并重(密钥加密存储、masked 返回、三层超时联动、结构化错误透传)。无论是接入本地 LLM、扩展看板行为,还是为定制简历增加新的生成内容,lib/api/*都是前端与后端之间的唯一事实入口——理解它,就等于掌握了整个应用的数据流主干。
【免费下载链接】Resume-MatcherThe #1 AI Harness for Building Resumes, PDFs, Cover Letters & more, locally with 100+ LLMs support.项目地址: https://gitcode.com/GitHub_Trending/re/Resume-Matcher
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考