news 2026/9/16 7:46:56

Ever Gauzy实战:开源ERP/CRM系统部署与二次开发指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Ever Gauzy实战:开源ERP/CRM系统部署与二次开发指南

最近在给团队做内部信息化选型的时候,我把GitHub上ever-gauzy这个仓库前前后后翻了个底朝天,后来索性直接用它在公司内部搭了一套ERP/CRM系统,跑了将近一个月。先给结论:Ever Gauzy不是一个“玩具项目”,它是一个正经的、可运行、可二次开发的开源企业管理平台,但同时它也不是那种“装完就能用”的成品系统,你需要投入相当的时间去理解它的结构,才能发挥出它的价值。

如果你正在关注ever-gauzy,大概跟我当初一样面临这几个问题:它到底是干嘛的?跟Odoo、ERPNext这些开源系统比有哪些优势?本地能不能跑起来?二次开发难度大不大?这篇文章我会用一个多月实际部署和改造的视角,把这些事一条条讲透,适合正在做技术选型的朋友,也适合准备拿它落地项目的开发者。

1. 先来说说,为什么我会盯上Ever Gauzy这套开源系统

1.1 开源ERP/CRM这个赛道上,Gauzy的位置很特别

市面上的开源业务管理平台,大家听得最多的基本是Odoo、ERPNext、SugarCRM这些。它们各自都有庞大的用户群体,但如果你跟我一样是TypeScript技术栈的团队,会发现一个很尴尬的问题:想改点东西,得先切换到Python那一套体系里去,招人、学习成本都是实打实的。

Ever Gauzy的出现正好补上了这个空白。它是一个基于TypeScript的全栈开源项目,核心代码仓库叫ever-gauzy,主要功能覆盖了CRM、ERP、HRM、会计、库存、项目管理和任务管理。换句话说,它不像某些开源项目只做单一模块,而是试图把一家中小公司的日常经营数据全部收进一套系统里。

我选择它的核心理由也很实际:前后端都是TypeScript,后端基于NestJS,前端基于Angular,团队现有能力可以无缝覆盖。其次是它的数据模型设计比较现代,支持多租户、多货币、多语言,这对后面做跨国业务或者多子公司管理很有帮助。最后一点,它不是一个近几年蹦出来的空壳项目,代码提交历史很完整,社区也一直在更新,底层稳定性经过了长时间验证。

1.2 它不是又一个进销存,而是想打通业务和财务

很多所谓的ERP,实际上只是进销存加一点客户管理,业务数据和财务数据完全是割裂的。Ever Gauzy的设计目标明显更高:它把费用报销、发票、记账、工资核算、订单和项目任务全部关联在一起。举个我们实际遇到的场景:以前销售开一张发票,需要去财务系统里再手动录一次应收款,两边对账经常差几天。现在Gauzy里面订单确认后,可以直接生成对应发票草稿,财务审核后进入应收账款台账,整个链路是通的。

这种“打通”带来的价值,在真正使用之前体会不到,只有当你不再需要天天在Excel之间复制粘贴的时候,才知道有多省事。当然,这也意味着它的数据结构比普通CRM复杂得多,学习曲线是真实存在的。

1.3 适合什么样的团队先来试水

根据我这一个多月的体验,Ever Gauzy最适合的团队是:内部有至少一名能改后端代码的开发者,愿意花一到两周时间做配置和二次开发,业务规模在几十人到几百人之间。如果你的团队完全不懂代码,只是想要一个开箱即用的管理系统,那我不推荐直接从Gauzy上手,它不像Odoo那样有大量商业应用市场可以直接装,很多功能需要自己调整。

如果你的目的跟我一样,是想“拿一套开源底座,长出符合自己业务逻辑的系统”,那ever-gauzy绝对值得深入研究。

2. Ever Gauzy工程结构:一眼看穿这个大型Monorepo

2.1 仓库目录到底长什么样

第一次clone ever-gauzy仓库的时候,我有点懵,因为它的结构比一般项目复杂太多。用一句话概括:这是一个NX搭建的Monorepo,里面同时管理着Angular前端、NestJS后端、Electron桌面端以及一堆公共库。

我印象中几个关键目录分别是:

  • apps/gauzy:Angular前端主应用,所有页面组件都在这里。
  • apps/api:NestJS后端主应用,提供REST API,也承载部分定时任务。
  • apps/server-api:配合Electron部署用的服务入口。
  • packages/contracts:前后端共享的接口定义和DTO,是整个项目的数据契约中心。
  • packages/common:公共工具类、枚举和配置常量。
  • packages/core:核心业务逻辑,包括实体定义、服务层和数据库迁移脚本。

刚开始看的时候不需要每个目录都弄懂,先掌握一个主线:前端调用的API,接口的请求和返回对象定义在packages/contracts里,具体业务逻辑在packages/core对应模块中,再由apps/api注册为HTTP路由。明白了这条链路,后面做二次开发就顺了。

2.2 核心数据模型不是“订单”,而是“组织”

很多人在接触Gauzy的数据结构时,第一反应是去找“订单表”“客户表”,结果找半天找不到。真实情况是,Gauzy的数据模型最上层是“租户”(Tenant),然后每个租户下面有多个“组织”(Organization),而账户、员工、客户、项目这些实体全都挂在组织之下。

我们内部分了两家子公司在用同一套系统,其实就是靠这个模型拆开的。每个组织有自己独立的客户、项目、发票和账单数据,超级管理员可以跨组织查看,普通用户只能看到自己所属组织的数据。这个设计对集团公司或者有多条业务线的企业非常友好,也是我最终选择它的原因之一。

当然,这也带来了权限配置的复杂度。第一次上手时,如果不理解“组织-员工-角色”这个链条,很容易出现用户登录后看不到任何菜单的情况。后面我会讲到这部分具体怎么排查。

2.3 技术选型背后的原因分析

Ever Gauzy不是随意拼凑的技术栈,它的选型有明显的目的:

  • NestJS作为后端框架,模块化设计非常清晰,几乎每个业务域都能对应一个Nest模块,方便多人协作开发。
  • TypeORM作为ORM层,配合PostgreSQL,既能享受关系型数据库的严谨事务能力,又能通过装饰器快速维护实体关系。
  • Redis用来做缓存和任务队列,尤其是邮件发送、报表生成这类异步任务,都依赖Bull队列在后台跑。
  • Angular前端虽然比React“重”,但它的依赖注入和模块体系,跟NestJS的后端结构非常匹配,适合中后台复杂表单和表格页面。

这套组合的缺点是学习资源相对少,尤其在国内社区,能找到的Gauzy中文资料很有限。但只要你对NestJS和Angular有基础,看代码的效率会非常高,因为结构和命名都比较规范。

3. 本地跑起来:从Git clone到浏览器看到登录页

3.1 环境准备:版本比什么都重要

先声明一下,Ever Gauzy对不同环境版本很敏感,不建议直接拿最新版本硬试,最好按照官方文档标注的版本准备。我这里用的版本如下:

依赖推荐版本备注
Node.js18.x 或 20.x LTS过老过新都可能出现编译问题
PostgreSQL14以上低版本有些JSON字段处理会有差异
Redis6.x以上队列功能依赖,生产环境必须稳定
Yarn1.22.x仓库锁定了yarn.lock,npm直接装会出问题
Angular CLI对应项目版本一般跟随项目依赖安装即可

我一开始用了Node 22测试版,编译时报了一堆OpenSSL相关的错误,后来切回Node 20正式版才顺利通过。所以如果你看到类似error:0308010C:digital envelope routines::unsupported,先别急着深挖代码,把Node版本换回LTS,问题大概率直接消失。

3.2 环境变量配置:一次配好不再反复

仓库根目录一般有一个.env.example.env.sample模板文件,复制一份为.env之后再修改。里面最关键的是数据库和Redis连接信息。

我当时的配置文件大致是这样:

DB_HOST=localhost DB_PORT=5432 DB_USER=gauzy DB_PASS=gauzy_user_password DB_NAME=gauzy REDIS_URI=redis://localhost:6379 JWT_SECRET=please_change_this_to_a_long_random_string

有几个变量需要特别留意:

  • JWT_SECRET如果不改,生产环境会有严重安全隐患,本地测试无所谓。
  • DB_NAME对应的数据库要提前创建,Gauzy不会自动创建数据库,只会自动建表。
  • 如果API和前端不在同一台机器,还要配置API_BASE_URL之类的地址变量,否则前端调接口会指向localhost。

3.3 数据库初始化与启动顺序

很多人在这一步栽跟头,是因为不知道Gauzy的初始化分了两个阶段:先跑migration建表,再跑seed灌入基础数据。如果直接启动服务,TypeORM可能会尝试自动同步表结构,但遇到外键依赖时容易失败。

我用的初始化命令大致是:

# 1. 安装依赖 yarn install # 2. 执行数据库迁移 yarn run migration:run # 3. 灌入种子数据(这步会生成一个演示组织和管理员账号) yarn run seed:all

注意,seed:all会往数据库里写入大量演示业务数据,比如客户、商品、员工、项目、发票等。这样做的目的是让你一进入系统就能看到各种功能都在运行。但如果你后续要接入自己公司的数据,最好在想清楚数据结构之后,重新建一个干净的数据库,只执行migration,不跑seed。

初始化完成后再分两个终端启动:

# 终端A:启动后端API,默认监听3000端口 yarn start:api # 终端B:启动前端,默认监听4200端口 yarn start:gauzy

打开http://localhost:4200,如果能跳转到登录页,说明Gauzy本地环境已经搭好了。种子数据里会包含几个账号,用管理员账号登录后,会看到包含“仪表盘”“销售”“会计”“人力资源”等模块的完整侧边栏。

3.4 我踩过的第一个坑:node-gyp编译失败

只要是大型前端项目,本机编译时几乎都绕不开这个问题。Gauzy的依赖里有些npm包需要编译原生模块,本机缺少Python、C++编译环境或者Visual Studio Build Tools时,yarn install会在node-gyp步骤直接报错。

我的解决路径是:Windows系统装好“Visual Studio Build Tools”勾选“Desktop development with C++”,macOS则要确保安装了Xcode Command Line Tools。装完后再执行一次yarn install,如果还有残留的失败记录,可以删掉node_modulesyarn.lock重新装一遍,但最好不要随便动yarn.lock,不然版本漂移可能引发新问题。

这个坑属于一次性的,解决之后再跑其他类似项目都会顺利很多。

4. 生产环境部署记录:Docker化与几个必须处理的坑

4.1 官方Docker Compose一揽子方案

本地跑通只是第一步,真正落地肯定要考虑生产环境。Ever Gauzy官方提供了Docker镜像,也支持用Docker Compose把PostgreSQL、Redis、API和Web前端一起编排起来。相比手动配环境,Docker方式明显更省心。

我当时的docker-compose.yml大致启用了这几个服务:

  • postgres:独立数据库容器,挂载数据卷。
  • redis:缓存和队列容器。
  • gauzy-api:后端API镜像,通过环境变量连接数据库和Redis。
  • gauzy-web:前端静态页面镜像,由Nginx托管并反向代理API请求。

虽然编排很简单,但生产环境有几个问题是文档里没写细的,我花了不少时间才排查清楚。

4.2 生产模式下的环境变量陷阱

第一个陷阱是NODE_ENV切换到production后,API的行为会发生很多变化。例如Swagger文档默认关闭,静态文件路径处理方式改变,甚至某些调试接口不再返回详细错误信息。这本来是为了安全,但如果你第一次部署,连日志都看不懂,排查问题会非常痛苦。

我的建议是,第一轮部署先用NODE_ENV=development跑通全链路,确认业务功能没问题后,再切换成production模式,一次性处理掉所有因环境变化引发的问题。不要上来就直接production,否则遇到页面白屏时,你会分不清是前端构建问题还是后端接口问题。

另外,不管哪种模式,务必将JWT_SECRET替换成强随机字符串,同时设置一个不是默认值的DEFAULT_ADMIN_PASSWORD之类初始密码变量,否则系统一上线就相当于裸奔。

4.3 Redis连接失败导致任务队列静默失败

部署完第二天,我们发现发票生成后,关联的通知邮件一直没发出去。查了API日志没有任何报错,页面操作也正常,这其实是最难排查的一种情况。

后来我把视线放到Bull队列上。Gauzy的异步任务,比如邮件通知、报表导出,都是先写进Redis队列,再由worker进程消费。如果Redis地址配错或密码不对,任务会一直堆积在队列里,而API主进程不一定会报错。

排查方法其实很简单:连上Redis跑一个LLEN bull:email:wait之类的命令,看看队列长度是不是大于0。如果队列积压,基本就是worker没有消费或者消费报错。再打开worker日志,才会看到真实的Redis认证失败信息。这个问题让我意识到,部署Gauzy这类重异步任务系统,Redis的健康监控必须前置配置好。

4.4 HTTPS反向代理与文件上传路径

前端服务用Nginx代理时,除了把location /指向Angular静态文件,还需要单独处理API路径和上传文件路径。Gauzy默认的API前缀大概会包含/api,上传文件会存在某个目录下,由后端静态托管。

如果Nginx只配置了一个根路径,会出现前端能打开、登录接口也通,但头像、产品图片全部404的情况。我当时的解决方法是显式配置两个location块,一个把/api转发到后端服务,另一个把/assets或对应文件路径指向上传目录。同时要注意,如果启用了HTTPS,前端里配置的API基础地址必须也是HTTPS,否则浏览器会直接阻止混合内容请求。

生产部署这件事,本质上是把Gauzy当成了一个普通的前后端分离应用来对待,理解了这一点,很多问题都能用通用技能解决。

5. 二次开发实战:给员工模块加一个自定义评分接口

5.1 先理清Gauzy的模块扩展套路

做二次开发前,先要理解Gauzy后端模块的写法。以员工模块为例,它的代码链路大致是:EmployeeController接收HTTP请求,调用EmployeeService里的方法,EmployeeService通过TypeORM仓库操作Employee实体。

新增功能最好的方式是按照已有模块的代码风格,复制一个类似的模块出来改,而不是在原有文件里堆积大量自定义逻辑。Gauzy的模块化结构让我能很轻松地找到“控制器-服务-实体”三层,然后照葫芦画瓢。

5.2 创建一个简单的API端点

我们内部需要给每个员工加一个不依赖绩效模块的评分字段,用于项目复盘。我不打算改动核心实体表,而是新增一个自定义扩展表。大致思路是先定义一个新的实体EmployeeScore,字段包括员工ID、评分、评价人ID、备注和创建时间。

然后创建对应的Service和Controller。核心代码风格与Gauzy其他模块保持一致:

@ApiTags('EmployeeScore') @Controller('employee-score') export class EmployeeScoreController { constructor( private readonly employeeScoreService: EmployeeScoreService, private readonly tenantService: TenantService ) {} @Post() async create( @Body() input: EmployeeScoreCreateInput, @Request() request: any ) { return this.employeeScoreService.create( input, await this.tenantService.getTenantIdFromRequest(request) ); } }

这里有一个容易忽略的细节:Gauzy几乎所有的业务实体创建时都要带tenantIdorganizationId,否则列表中查不到数据。我第一次写自定义接口时忘了传租户ID,接口返回200,但数据在租户隔离查询下永远看不到。如果你也遇到“能插入但查询不到”的问题,基本可以先检查这两个字段是否写对了。

5.3 把自定义功能接入前端菜单

后端接口写好后,前端接入也不算难。Gauzy的Angular前端把页面模块拆分得很细,我只需要在对应菜单模块里新增一个页面组件,在菜单配置里注册即可。

由于项目结构复杂,我不建议手工修改路由文件去硬编码,而是优先使用Gauzy提供的动态菜单注册机制。新建一个功能模块,然后在模块的init()方法里把菜单项加进去。这样升级的时候,跟官方代码的冲突范围可以控制在最小。

这次二次开发总体下来,我最大的感受是:Gauzy的代码命名规范、分层清晰,只要读懂了其中一个模块,其余模块基本都是类似套路,开发效率比想象中高。前提是你要具备一定的NestJS和Angular基础,纯前端或者纯后端新手可能还是会觉得吃力。

6. 一个月的真实使用反馈:它到底能不能扛住中小团队日常

6.1 让我觉得值回时间成本的地方

这一个多月里,Gauzy确实帮我解决了很多实际问题。首先是数据统一:销售单据、采购订单、项目工时报工、费用报销、发票全部在一个系统里关联,看任何一个客户的完整历史都只需要点几下滑鼠。其次是权限模型,多组织隔离让管理多个子公司数据变得非常轻松,财务和普通员工看到的界面完全不同。再者就是技术栈,改动需求时我能直接从数据库关系查到前端页面,整条链路都掌控在手里,这种确定性是外包软件或者封闭SaaS很难给的。

6.2 让人抓狂的地方也不能回避

先说文档问题,Gauzy的官方文档更新速度赶不上代码迭代,很多API参数只能去源码里翻定义。我至少有三次因为文档过时而浪费时间,最后都是靠着TypeScript类型推断把问题解决的。如果你是一个习惯查Wiki的人,刚上手会有点痛苦。

其次是升级成本,Gauzy的版本迭代涉及数据库结构变更,直接拉最新代码跑migration有可能会遇到不兼容的情况。我目前的做法是锁定一个大版本,稳定运行后不轻易升级,只在有明确安全修复时再做迁移。

还有一个普遍容易吐槽的点:前端构建比较重,首次冷启动可能要两分钟以上,开发时热更新偶尔也会卡顿。这对16G内存的笔记本不太友好,建议开发机内存至少32G,否则同时跑API、前端和数据库会很有压力。

6.3 我的个人选型建议

如果你问我,Ever Gauzy适合什么人?我的答案是有TypeScript开发能力、想要从零搭建一套内部业务管理系统、并且愿意承担一定自定义维护成本的技术团队。它适合作为“数字化底座”,而不适合作为“拿来即用的成品”。

反过来,如果公司没有专职开发,或者业务极其标准化不需要深度定制,那更建议用SaaS产品,至少省去服务器、升级、安全这些日常琐事。Gauzy会让你拥有完全可控的代码,但这份“掌控”是要靠时间和人力换的。

最后分享一个自己的小习惯:接手这类大型开源项目后,我做的第一件事永远是删掉种子数据,建立一套自己的最小测试数据集,把业务主流程全部走通后,再逐步迁移历史数据。大而全的示例数据容易让人迷失,你自己的数据才会暴露真实的配置问题。如果你现在也在部署ever-gauzy,希望这些踩坑记录能帮你少走一些弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 7:46:54

用MATLAB验证披萨定理:等角切圆面积平分与可视化

先说结论:这道题我最后跑出来的面积差通常在 1e-10 量级,基本可以认为两边严格相等。我第一次看到这个题目时,第一反应是“这不就是小学奥数的切披萨吗”。但等真正用 MATLAB 把图形画出来、把面积一块块算完,才发现里面藏着一个很…

作者头像 李华
网站建设 2026/9/16 7:46:01

iPhone Duo 带来的机遇与挑战 -- 肘子的 Swift 周报 #153

iPhone Duo 带来的机遇与挑战 尽管 iPhone Duo 的设计资料早在几个月前就已部分泄漏,而且苹果也是折叠机领域的后来者,但凭借软硬件整合能力,它所带来的交互变化还是给不少消费者带来了惊喜。 不同机构对 iPhone Duo 的初期销量给出了不同口…

作者头像 李华
网站建设 2026/9/16 7:44:37

卡尔曼滤波入门必看:从概率统计到贝叶斯估计的核心基础

打RM这几年,带过几届电控组,发现一个特别有意思的规律:几乎每个新队员入门卡尔曼滤波,都是先打开一篇讲公式推导的博客,然后盯着那个长得吓人的状态方程和更新方程发呆半小时,最后默默关上网页,…

作者头像 李华
网站建设 2026/9/16 7:43:28

我用微信小程序做了一个工具箱:从 0 到上线的完整记录

没有用任何框架,纯原生 npm 包,9 个实用工具,一套墨蓝仪表盘 UI。本文完整记录从需求分析到发布的全过程,附带核心代码。文末有体验入口,欢迎扫码试用。为什么做这个小程序? 事情很简单——我做了 15 年前…

作者头像 李华
网站建设 2026/9/16 7:42:40

ESP8266通用驱动开发:从GPIO映射到串口通信的实践指南

简介:一套面向嵌入式与物联网开发者的ESP8266通用型Wi-Fi驱动,可跨不同C语言平台直接使用,无需为各平台修改代码即可接入,解决设备无线联网与底层AT指令衔接问题。资源包仅3KB,共2个文件:头文件提供模块初始…

作者头像 李华
网站建设 2026/9/16 7:41:57

协同过滤算法在东北特产电商平台的应用与优化

1. 项目背景与核心价值东北特产电商平台面临着传统销售模式下的用户粘性不足和转化率低下的痛点。去年我在为一家吉林人参企业做技术咨询时,发现他们的线上复购率仅有8%,远低于行业平均水平。这正是我们开发这套系统的初衷——通过协同过滤算法实现精准推…

作者头像 李华