后端前端企业应用MCP 服务【免费下载链接】ever-gauzyEver® Gauzy™ - Open Business Management Platform (ERP/CRM/HRM/ATS/PM) - https://gauzy.co项目地址https://gitcode.com/GitHub_Trending/ev/ever-gauzy点击查看免费下载Ever® Gauzy™ 是一个开源的一体化业务管理平台ERP/CRM/HRM/ATS/PM在其插件体系中gauzy/plugin-videos承担了视频上传与元数据管理这一垂直能力。本文以该插件为线索完整讲解其安装、构建、测试、发布流程并深入packages/plugins/videos源码剖析其 CQRS 分层、多租户权限模型、存储提供商对接与文件安全防护帮助读者掌握在 Gauzy 中集成视频管理功能的全链路方案。插件定位Gauzy 插件体系中的视频管理模块gauzy/plugin-videos是 Gauzy 插件体系中的一个标准库型插件其 README 明确定义了两个核心能力视频上传与存储Video upload and storage视频元数据管理Video metadata management从项目结构看该插件遵循 Gauzy 统一的插件开发约定tags: [type:plugin]见 project.json与ai-chat、integration-github、job-proposal等插件并列存放于packages/plugins目录下通过 Nx 工作区管理。插件的入口类VideosPlugin使用GauzyCorePlugin装饰器声明并实现了IOnPluginBootstrap与IOnPluginDestroy生命周期钩子见 videos.plugin.tsPlugin({ imports: [VideosModule], entities: [Video], providers: [], exports: [] }) export class VideosPlugin implements IOnPluginBootstrap, IOnPluginDestroy { private logEnabled true; onPluginBootstrap(): void | Promisevoid { if (this.logEnabled) { console.log(chalk.green(${VideosPlugin.name} is being bootstrapped...)); } } onPluginDestroy(): void | Promisevoid { if (this.logEnabled) { console.log(chalk.red(${VideosPlugin.name} is being destroyed...)); } } }VideosPlugin通过imports: [VideosModule]引入业务模块、entities: [Video]注册数据实体平台启动时自动执行onPluginBootstrap、关闭时执行onPluginDestroy默认开启绿色/红色日志输出注释表明该日志开关用于避免事件日志刷屏。而插件对外的公共 API 面则统一在 index.ts 中导出export * from ./lib/videos.plugin;快速开始安装、构建、测试与发布安装README 给出了两种主流包管理器安装方式npm install gauzy/plugin-videos # or yarn add gauzy/plugin-videos该包发布到 npm 后即可作为依赖引入 Gauzy 应用并在应用模块中注册VideosPlugin。构建在仓库内使用 Nx 构建该库yarn nx build plugin-videos构建由nx/js:tscexecutor 驱动见 project.json产物输出到dist/packages/plugins/videostsconfig.lib.json指定编译配置src/index.ts作为入口同时把packages/plugins/videos/*.md文档一并打包进产物。构建时还会因implicitDependencies声明自动先构建其依赖的contracts、core、plugin库。运行单元测试yarn nx test plugin-videos测试经由nx/jest:jestexecutor 执行使用仓库内的 jest.config.ts 配置。现有测试覆盖服务装配与控制器端点见下文测试与验证小节。发布构建完成后进入产物目录执行 npm 发布cd dist/packages/plugins/videos npm publish发布版本号由 Nx 的nx-release-publishtarget 与 git-tag 解析器管理见 project.json 中release.version.currentVersionResolver: git-tag。架构拆解NestJS 模块 CQRS 事件驱动VideosModule是插件的核心业务装配单元见 videos.module.tsModule({ controllers: [VideosController], imports: [ TypeOrmModule.forFeature([Video]), MikroOrmModule.forFeature([Video]), RolePermissionModule, CqrsModule ], providers: [ VideosService, VideoSubscriber, TypeOrmVideoRepository, ...CommandHandlers, ...QueryHandlers ], exports: [VideosService] }) export class VideosModule { }从中可以提取出该插件的分层骨架层次代表文件职责控制器层videos.controller.ts暴露 HTTP 端点参数校验权限守卫命令层写commands/CreateVideoCommand/UpdateVideoCommand/DeleteVideoCommand及对应 Handler查询层读queries/GetVideosQuery/GetVideoQuery/GetVideoCountQuery及对应 Handler服务层services/videos.service.ts继承TenantAwareCrudServiceVideo封装 CRUD数据访问层repositories/TypeORM 与 MikroORM 双仓储实现实体层entities/video.entity.ts数据库映射与字段校验事件层subscribers/video.subscriber.ts实体加载/删除后的存储联动这种控制器只做参数与权限处理业务逻辑通过CommandBus/QueryBus派发到 HandlerHandler 再调用服务层的 CQRS 模式与 Gauzy 平台其他模块保持一致例如GET /列表请求在控制器中仅一行this.queryBus.execute(new GetVideosQuery(params))POST创建请求执行CreateVideoCommand读写完全分离。数据模型Video 实体与 IVideo 契约实体字段与校验规则Video实体继承TenantOrganizationBaseEntity自带租户与组织归属字段实现IVideo接口见 video.model.ts。核心字段及其校验约束见 video.entity.ts字段类型约束与说明titlestring必填3~255 字符仅允许各语言字母、数字、空格与连字符/^[\p{L}\p{N}\s-]$/ufilestring必填必须是 MP4 文件名/^[\w-]\.(mp4)$/i实际存储的是文件 keyrecordedAtDate可选ISO 8601 时间字符串且不得晚于当前时间durationnumber可选≥0单位为秒存储为real类型sizenumber可选0 ~ 10GB10737418240 字节上限fullUrlstring可选合法的 http/https URL由订阅器在实体加载时自动生成descriptionstring可选≤1000 字符仅允许字母、数字、空格与基础标点storageProviderenum可选取值于FileStorageProviderEnum序列化时被Exclude隐藏resolutionstring可选格式WIDTH:HEIGHT如1920:1080默认VideoResolutionEnum.FullHDcodecstring可选2~20 字符默认VideoCodecEnum.libx264frameRatenumber可选1~240 fps默认 15timeSlotId/uploadedByIdUUID可选关联TimeSlot与Employee的外键均建有索引预定义枚举分辨率与编码video.model.ts中定义了两套标准枚举为元数据提供统一的取值范围VideoResolutionEnum覆盖 SD640:480、HD1280:720、FullHD1920:1080、QHD2560:1440、UHD4K3840:2160、UHD5K、UHD6K、UHD8K、DCI4K4096:2160、Cinema2K2048:1080、WXGA、SXGA、UXGA、VGA640:360、PAL720:576、NTSC720:480共 16 档。VideoCodecEnumlibx264、libx265、libvpx、libaom、mpeg4、h263、h264、h265、theora、vp8、vp9共 11 种。实体关系实体与两个平台核心实体建立多对一关联且均配置onDelete: CASCADE与JoinColumn()timeSlot时间片视频可归属到某个TimeSlot时间追踪体系的最小时间单元关联字段timeSlotId校验 UUID v4uploadedBy上传者记录哪位员工上传了视频关联字段uploadedById同样校验 UUID v4 并建立索引。从源码结构看这两个关系使其天然服务于员工时间追踪场景——PermissionsEnum.TIME_TRACKER权限也印证了这一点。HTTP API 全览端点、守卫与权限VideosController以Controller(/plugins/videos)暴露五个 REST 端点见 videos.controller.ts方法路径说明GET/plugins/videos分页获取视频列表支持按时间片/员工筛选EmployeeTrackedDataGuardPOST/plugins/videos上传视频文件multipart/form-data字段名file并创建记录GET/plugins/videos/count统计当前租户内视频数量可带过滤条件GET/plugins/videos/:id按 UUID 获取单个视频PUT/plugins/videos/:id按 UUID 更新视频元数据DELETE/plugins/videos/:id按 UUID 删除视频可传软删除选项守卫与权限链控制器类级统一挂载两层守卫与权限声明UseGuards(TenantPermissionGuard, PermissionGuard) Permissions(PermissionsEnum.TIME_TRACKER)TenantPermissionGuard校验租户级权限PermissionGuardPermissions(PermissionsEnum.TIME_TRACKER)要求调用者具备时间追踪权限列表、详情与计数三个读端点额外挂EmployeeTrackedDataGuard确保员工只能访问与其追踪记录相关的数据。所有变更端点POST/PUT/DELETE与部分读端点还叠加了UseValidationPipe({ whitelist: true, transform: true, forbidNonWhitelisted: true })——白名单模式会剔除未声明字段、禁止非白名单字段传入有效防御参数注入。ID 参数统一经UUIDValidationPipe校验。数据隔离租户 组织 员工三级过滤以列表查询 Handler 为例见 get-videos.handler.ts查询逻辑展示了完整的数据隔离策略where基础条件固定为tenantId与organizationId若当前用户不具备PermissionsEnum.CHANGE_SELECTED_EMPLOYEE权限则强制where.uploadedById RequestContext.currentEmployeeId()——员工只能看到自己上传的视频无员工上下文时直接返回空分页结果若提供了startDate/endDate则使用moment-timezone将本地时区默认UTC换算为 UTC 后以Between区间过滤recordedAt具备权限的管理者可通过employeeIds数组以In操作符批量过滤上传者关键安全细节服务端生成的 where 条件排在客户端参数之后where: { ...params.where, ...where }以覆盖方式防止调用方通过?where[uploadedById]他人ID越权读取其他员工的录像——源码注释明确指出该缺陷曾可用于读取他人记录。计数端点getCount见 get-video-count.handler.ts执行同样的租户、组织与员工权限校验并在参数缺失时抛出BadRequestException组织 ID 与租户 ID 均必填且无权限时无法确定当前员工也会报错。文件上传安全防线与存储对接POST创建端点是本插件最复杂的环节其安全设计值得专门拆解见 videos.controller.ts。上传拦截器UseInterceptors( LazyFileInterceptor(file, { storage: () FileStorageFactory.create(videos), fileFilter: videoUploadFileFilter }) )LazyFileInterceptor是 Gauzy 核心gauzy/core提供的懒加载文件拦截器按需创建存储实例FileStorageFactory.create(videos)按业务目录创建存储提供商实例videoUploadFileFilter在文件落盘前过滤 MIME 类型。三道防线的防脚本注入机制源码注释明确引用了 GHSA-p334-cm7f-php5 类安全通告视频文件经/public/key无鉴权路由按扩展名推断 Content-Type 对外提供若一个伪装成video/mp4的.svg/.html文件成功落盘就会在应用同源下执行脚本。为此插件建立三道防线拦截器层videoUploadFileFilter在接收阶段过滤不合法的视频 MIMEDTO 层file.dto.ts 对文件元数据做严格校验——key必须匹配/\.(mp4)$/mimetype必须匹配/^video\/(mp4)$/size必须为正数url上限 2083 字符、path上限 1024 字符字节级复核shouldScanForMarkup(file.size)判断是否需要对已存储文件内容做标记语言markup扫描大文件因需整体读入内存而跳过随后assertNotMarkupContent(await provider.getFile(file.key))直接读取已落盘字节重新检查——即使客户端伪造 MIME 与文件名恶意标记内容也无法在磁盘上存活。失败清理与字段兜底创建流程对任何异常都执行provider.deleteFile(file.key)最佳努力清理避免脏文件残留成功路径则将tenantId、organizationId、uploadedById从请求上下文兜底RequestContext.currentTenantId()/currentEmployeeId()并把storageProvider以大写形式记录入库。最终CreateVideoHandler见 create-video.handler.ts把file.key写入Video.file字段后落库。存储生命周期FileStorage 与实体订阅器视频文件的实际读写由 Gauzy 核心的FileStorage抽象负责它支持多存储提供商FileStorageProviderEnum视频插件只需按 key 操作而无需关心底层是本地磁盘、S3 还是其他云存储。VideoSubscriber见 subscribers/video.subscriber.ts以 TypeORMEventSubscriber方式把文件生命周期与数据库事件绑定afterEntityLoad加载后读取实体的storageProvider与file通过new FileStorage().setProvider(storageProvider).getProviderInstance().url(file)生成完整访问 URL 并写入fullUrl缺失关键字段时仅记录警告日志afterEntityDelete删除后调用provider.deleteFile(file)同步删除存储中的物理文件成功删除输出Successfully deleted file for entity ID ...日志失败则记录错误日志而不阻断删除流程。这意味着数据库记录与存储文件的生命周期是联动的删除视频记录会自动回收存储对象加载记录会自动补全可访问 URL调用方无需手动管理两处状态。测试与验证插件包含两组 Jest 测试可用yarn nx test plugin-videos运行videos.service.spec.ts通过 NestJSTest.createTestingModule注入 TypeORM/MikroORM 仓储 mock验证VideosService可被正确实例化videos.controller.spec.ts验证控制器装配videos-employee-scope.spec.ts专门覆盖员工可见范围的数据隔离逻辑呼应上文第 5 节的权限过滤设计。小结gauzy/plugin-videos是一个麻雀虽小五脏俱全的 Gauzy 插件范例它演示了Plugin装饰器 生命周期钩子的插件接入方式NestJS 模块与 CQRS 命令/查询的完整分层TenantOrganizationBaseEntity多租户数据模型与三级数据隔离以及围绕视频上传构建的多层安全防线MIME 过滤、DTO 白名单、字节级 markup 扫描、失败文件清理。如果要在 Ever Gauzy 中为团队增加录像/演示视频上传与检索能力或想参考其模式开发自己的业务插件本文覆盖的 videos.plugin.ts、videos.controller.ts、video.entity.ts 与 video.subscriber.ts 是最佳的入手路径。赞分享后端前端企业应用MCP 服务【免费下载链接】ever-gauzyEver® Gauzy™ - Open Business Management Platform (ERP/CRM/HRM/ATS/PM) - https://gauzy.co项目地址https://gitcode.com/GitHub_Trending/ev/ever-gauzy点击查看免费下载相关推荐Ever Gauzy 视频管理 UI 插件 gauzy/plugin-videos-ui 完整实战指南Ever Gauzy 视频管理 UI 插件 gauzy/plugin videos ui 完整实战指南 gauzy/plugin videos ui 是 E后端前端企业应用MCP 服务Ever Gauzy 插件系统深度指南基于 gauzy/plugin 的模块化插件开发实战Ever Gauzy 插件系统深度指南基于 gauzy/plugin 的模块化插件开发实战 本指南以 Ever Gauzy 开源仓库中的 gauzy/pl后端前端企业应用MCP 服务Ever Gauzy Camshot 插件实战摄像头快照上传、存储与管理全解析Ever Gauzy Camshot 插件实战摄像头快照上传、存储与管理全解析 本指南以 Ever Gauzy 开源仓库中的 gauzy/plugin ca后端前端企业应用MCP 服务创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考