Ever Gauzy 职位搜索插件(@gauzy/plugin-job-search)实战指南:构建、测试、发布与集成原理

原创2026-09-30 21:28:001,852 阅读
文章标签:企业应用后端前端桌面应用

Ever Gauzy 职位搜索插件(@gauzy/plugin-job-search)实战指南:构建、测试、发布与集成原理

导读

@gauzy/plugin-job-search 是 Ever Gauzy 开放业务管理平台(ERP/CRM/HRM/ATS/PM)中的职位搜索(Job Search)插件,为求职者与雇主双方提供职位检索、匹配与申请能力。本文以插件官方 README(packages/plugins/job-search/README.md)为核心骨架,结合仓库源码深入讲解其安装、构建、单元测试、发布流程,以及背后基于 NestJS、CQRS 与 Gauzy AI 的匹配实现原理,帮助你将该插件正确集成到自己的 Gauzy 部署中。

插件定位与功能概览

面向双方的一站式职位工具

根据 README 概述,该插件被定位为"增强职位搜索体验的强大工具",无论使用者是求职者还是雇主,都能借助它简化流程、提升效率。它对外公开的两大核心特性包括:

  • 高级搜索(Advanced Search):利用高级筛选条件查找符合个人偏好的职位列表;
  • 职位提醒(Job Alerts):设置职位提醒,当出现符合条件的新职位时接收通知。

在 package.json 的 keywords 中,插件被标注为 job-search、recruitment、employment、NestJS、microservices 等,可见其定位是一个部署在服务端、面向招聘与求职场景的 NestJS 微服务模块。

插件在整个平台中的角色

从 project.json 可以确认,它是一个 type:plugin 类型的 Nx 库,且声明了隐式依赖:common、config、contracts、core、plugin、plugin-integration-ai、utils。这意味着插件深度复用了 Gauzy 核心包、契约类型定义,以及 Gauzy AI 集成插件——职位匹配的核心逻辑正是交由 Gauzy AI 服务完成的(下文详述)。

环境要求与依赖

在安装和构建前,请先确认运行环境满足 package.json 中声明的引擎要求:

项目 要求
Node.js >=22
Yarn >=1.22
运行时 peer 依赖 @nestjs/common ^11.1.26、@nestjs/core ^11.1.26

主要运行时依赖还包括:@gauzy/common、@gauzy/config、@gauzy/contracts、@gauzy/core、@gauzy/plugin、@gauzy/plugin-integration-ai、@mikro-orm/nestjs、@nestjs/cqrs、@nestjs/swagger、@nestjs/typeorm、html-to-text、class-validator 等。其中 @nestjs/cqrs 用于命令/查询总线,html-to-text 用于将职位申请提案的 HTML 内容转为纯文本(见 employee-job.service.ts)。

安装插件

根据 README 安装章节,在终端中执行以下任一命令即可安装:

npm install @gauzy/plugin-job-search
# 或
yarn add @gauzy/plugin-job-search

注:当前仓库内该包标记为 "private": true(见 package.json),因此其发布版 @gauzy/plugin-job-search 面向 npm 上的公开发行版本。在仓库内本地联调时,也可通过工作区直接引用源码库。

构建插件库

使用 Nx 构建

README 构建章节 给出的构建命令是:

yarn nx build plugin-job-search

该命令由 project.json 中的 build target 驱动,采用 @nx/js:tsc 执行器,关键配置如下:

  • 输出目录:dist/packages/plugins/job-search;
  • TypeScript 配置:tsconfig.lib.json;
  • 入口文件:packages/plugins/job-search/src/index.ts;
  • 资源拷贝:将 packages/plugins/job-search/*.md(即 README、CHANGELOG 等文档)一并复制到产物目录;
  • 依赖顺序:dependsOn: ["^build"],会先构建其依赖库(common、core、plugin-integration-ai 等)。

仓库内 package.json 还提供了三个便捷脚本,与 Nx 命令等价:

"scripts": {
    "lib:build": "yarn nx build plugin-job-search",
    "lib:build:prod": "yarn nx build plugin-job-search",
    "lib:watch": "yarn nx build plugin-job-search --watch"
}
  • lib:build / lib:build:prod:普通构建与生产构建;
  • lib:watch:开启 watch 模式,源码变更时增量编译,适合开发调试。

构建产物的清单入口(main)指向 ./src/index.js,类型声明为 ./src/index.d.ts(见 package.json)。

插件的公开 API 面

插件的唯一公开导出在 src/index.ts:

export * from './lib/job-search.plugin';

也就是说,使用方只需引入 JobSearchPlugin 类并将其注册进 Gauzy 应用即可。其内部结构(employee-job、employee-job-preset 两个子模块)均为实现细节,不对外暴露。

运行单元测试

README 测试章节 给出的测试命令为:

yarn nx test plugin-job-search

测试通过 Jest:

module.exports = {
    displayName: 'plugin-job-search',
    preset: '../../../jest.preset.js',
    testEnvironment: 'node',
    transform: {
        '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }]
    },
    moduleFileExtensions: ['ts', 'js', 'html'],
    coverageDirectory: '../../../coverage/packages/plugins/job-search'
};

要点说明:

  • testEnvironment: 'node':该插件是纯服务端库,测试运行在 Node 环境而非 jsdom;
  • 使用 ts-jest 配合 tsconfig.spec.json 编译 TypeScript;
  • 覆盖率报告输出至 coverage/packages/plugins/job-search。

在 project.json 中,test target 使用 @nx/jest:jest 执行器,并同样输出覆盖率到 coverage/{projectRoot}。

发布到 npm

README 发布章节 给出了发布步骤:

  1. 先执行构建:yarn nx build plugin-job-search;
  2. 进入产物目录:dist/packages/plugins/job-search;
  3. 执行发布:npm publish。

由于构建 target 配置了 assets: <a href="https://link.gitcode.com/i/ece6d9cc203199efe185c5ab7d8a5047" target="_blank">"packages/plugins/job-search/*.md"],发布包中会携带 README 与 CHANGELOG 文档。仓库侧还通过 [project.json 的 nx-release-publish target 支持 Nx 的发布流程,发布根目录同样指向 dist/{projectRoot},版本号通过 git tag 解析(currentVersionResolver: "git-tag")。发布前请按需修改 package.json 中的 version 字段(当前为 0.1.0)。

源码级原理:插件如何工作

插件生命周期与种子数据

JobSearchPlugin(见 job-search.plugin.ts)实现了 IOnPluginBootstrap、IOnPluginDestroy、IOnPluginSeedable 三个生命周期接口,通过 @Plugin() 装饰器声明其构成:

@Plugin({
    imports: [EmployeeJobPostModule, EmployeeJobPresetModule, SeederModule],
    entities: [...entities],
    configuration: (config: ApplicationPluginConfig) => {
        config.customFields.Employee.push({
            name: 'jobPresets',
            type: 'relation',
            relationType: 'many-to-many',
            pivotTable: 'employee_job_preset',
            joinColumn: 'jobPresetId',
            inverseJoinColumn: 'employeeId',
            entity: JobPreset,
            inverseSide: (it: JobPreset) => it.employees
        });
        return config;
    },
    providers: [JobSeederService]
})
export class JobSearchPlugin implements IOnPluginBootstrap, IOnPluginDestroy, IOnPluginSeedable
  • 生命周期钩子:onPluginBootstrap / onPluginDestroy 分别在插件启动、销毁时通过 chalk 输出绿色/红色日志;
  • 自定义字段:插件启动时向 Employee 实体注入 jobPresets 多对多关系字段,中间表为 employee_job_preset,关联 JobPreset 实体——这是职位预设(Preset)与员工关联的底层机制;
  • 种子数据:onPluginDefaultSeed 调用 JobSeederService.seedDefaultJobsData(),写入默认职位搜索类别与职业类别(详见 job-seeder.service.ts);onPluginRandomSeed 则预留随机数据填充逻辑。

entities 数组(来自 employee-job-preset.module.ts)包含五个实体:JobPreset、JobPresetUpworkJobSearchCriterion、EmployeeUpworkJobsSearchCriterion、JobSearchOccupation、JobSearchCategory,它们构成职位预设、筛选条件、职业类别与搜索类别的数据模型。

两个子模块:职位发布与职位预设

插件内部拆分为两个 NestJS 模块:

1. EmployeeJobPostModule(employee-job.module.ts)

负责"员工—职位"匹配业务,导入 EmployeeModule、IntegrationTenantModule、TenantModule、RolePermissionModule、GauzyAIModule.forRoot() 与 CqrsModule,注册了 EmployeeJobPostController、EmployeeJobPostService 以及一组命令/查询处理器。

2. EmployeeJobPresetModule(employee-job-preset.module.ts)

负责职位搜索预设(Preset)体系,同时注册 TypeORM 与 MikroORM 两套实体特性(TypeOrmModule.forFeature 与 MikroOrmModule.forFeature),暴露四个控制器:JobSearchOccupationController、JobSearchCategoryController、EmployeePresetController、JobSearchPresetController,并向外部导出 JobPresetService、JobSearchCategoryService、JobSearchOccupationService。

职位 API 端点一览

EmployeeJobPostController 挂载于 /employee-job 路径,全部端点受 TenantPermissionGuard 与 PermissionGuard 保护,并按权限细分:

HTTP 方法与路径 权限 用途
GET /employee-job/ ORG_JOB_SEARCH 分页查询员工职位列表
GET /employee-job/statistics ORG_JOB_EMPLOYEE_VIEW 员工职位统计
PUT /employee-job/:id/job-search-status ORG_EMPLOYEES_EDIT、PROFILE_EDIT 更新员工职位搜索状态
POST /employee-job/apply ORG_JOB_APPLY 申请职位
POST /employee-job/updateApplied ORG_JOB_APPLY 更新申请状态
POST /employee-job/hide ORG_JOB_EDIT 隐藏/恢复职位可见性
POST /employee-job/pre-process ORG_JOB_APPLY 创建职位申请预记录
GET /employee-job/application/:employeeJobApplicationId ORG_JOB_APPLY 获取 AI 生成的申请提案
POST /employee-job/generate-proposal/:employeeJobApplicationId ORG_JOB_APPLY 生成 AI 申请提案

代码风格上,命令类操作(如更新搜索状态)通过 CommandBus 派发 CQRS 命令,查询类操作(如统计)通过 QueryBus 派发查询,服务层则承担与 Gauzy AI 的实际交互。

与 Gauzy AI 的协作:高级搜索与职位提醒的底层支撑

高级搜索与职位提醒是 README 宣传的两大特性,它们在源码中主要由 EmployeeJobPostService 与 Gauzy AI 集成插件协同实现:

  • 职位匹配:findAll 方法首先通过 EmployeeService.findAllActive() 获取活跃员工,再检测配置项 env.gauzyAIGraphQLEndpoint(来自 @gauzy/config)是否可用;若可用,则校验 GAUZY_AI 集成与 JOB_MATCHING 实体同步状态,最终调用 GauzyAIService.getEmployeesJobPosts(data) 获取匹配职位。若用户缺少 CHANGE_SELECTED_EMPLOYEE 权限,则自动将筛选范围限定为当前员工 ID——从源码结构看,这是权限控制与数据隔离的默认策略。
  • 职位申请:apply 方法先将 proposal 字段中的 HTML 通过 html-to-text 转为无换行纯文本,再交给 Gauzy AI 服务执行申请。
  • 可见性与申请状态:updateVisibility、updateApplied 均直接委托 GauzyAIService,对应"隐藏职位"与"标记已申请"两个动作,其中是否针对单个员工生效取决于请求中是否携带 employeeId。

可见,该插件的定位是一个"厚集成层":对外提供 REST API 与数据模型,对内将职位匹配、申请等重活委托给 Gauzy AI 服务,这与 project.json 中声明的 plugin-integration-ai 隐式依赖完全吻合。

预设(Preset)体系与种子数据

职位预设体系让雇主可批量定义搜索偏好:JobPreset 与 JobPresetUpworkJobSearchCriterion、EmployeeUpworkJobsSearchCriterion 实体用于存储预设及其 Upwork 搜索条件,JobSearchCategory、JobSearchOccupation 提供类别与职业维度。配套的命令处理器(见 commands/handlers)包括 CreateJobPresetHandler、SaveEmployeePresetHandler、SaveEmployeeCriterionHandler、SavePresetCriterionHandler,覆盖预设创建、员工预设保存、员工条件保存、预设条件保存等场景。

默认数据方面,JobSeederService.seedDefaultJobsData()(job-seeder.service.ts)在插件默认种子阶段执行,通过 createDefaultJobSearchCategories 与 createDefaultJobSearchOccupations(定义于 job-search-category.seed.ts 与 job-search-occupation.seed.ts)写入默认类别与职业数据,并区分生产与非生产环境的日志输出。

常见问题与注意事项

  • 构建失败先查依赖:由于 build target 带有 dependsOn: ["^build"],一次构建会级联编译 common、core、plugin-integration-ai 等上游库,耗时较长属正常现象;
  • 测试环境为 Node:插件不含任何浏览器相关代码,测试必须运行在 testEnvironment: 'node' 下;
  • 职位匹配依赖 Gauzy AI:若未配置 gauzyAIGraphQLEndpoint 或未建立 GAUZY_AI 集成与 JOB_MATCHING 实体同步,findAll 将退化为仅返回本地员工列表(见 employee-job.service.ts),无法获得 AI 匹配职位;
  • 发布前版本管理:仓库内该包为 private,正式对外发布需先在 npm 上具备 @gauzy/plugin-job-search 的发布权限,并按 project.json 的 release 配置管理版本号。

参考文件索引

登录后查看全文
ever-gauzy