资讯详情

资讯详情

开源ERP ever-gauzy全解析:从部署到二次开发实战指南

如果你正在评估开源 ERP 或一体化管理平台大概率会在搜索过程中撞见ever-gauzy这个仓库。我第一次看到它时第一反应是“这名字真怪”但点进去之后发现这几乎是目前 Node.js 生态里最完整的企业管理系统之一。它不是一个简单的进销存工具而是把预算、人力、客户、项目、工时、发票这些业务模块全部整合到了一起。这篇文章我会从实际部署到二次开发完整拆解我使用 ever-gauzy 的整个过程包括环境配置、踩坑记录、源码结构分析以及如何在此基础上扩展自己的业务模块。如果你正准备选型开源企业管理软件或者想在现有 ERP 上做定制这篇内容应该能帮你少走很多弯路。1. ever-gauzy 到底是什么先把它和常见 ERP 的区别说清楚1.1 它不是一个简单的进销存很多人一看到 ERP 就以为是进销存加财务ever-gauzy 的边界远不止这些。从功能模块看它覆盖了销售管道、客户关系管理、员工花名册、考勤工时、项目任务、费用报销、合同发票、采购库存、会计科目等十几条业务线。更关键的是这些模块不是孤立存在的而是在同一套组织架构下互相联动。比如一个销售订单成交后系统会自动生成应收发票同时关联到对应项目和负责员工的工时记录财务人员可以直接在会计模块看到这笔收入对账。这种端到端的流程闭环是很多开源 ERP 做不到的。1.2 一张表看懂它的模块边界为了让你快速判断它适不适合自己我把它的核心模块按业务域做了个梳理业务域主要功能典型使用场景销售与 CRM交易管道、客户管理、跟进记录销售团队维护潜在客户跟踪商机阶段项目与任务项目计划、任务看板、里程碑项目经理拆解任务并分派给团队成员人事与工时员工档案、考勤、工时表、休假申请HR 统计考勤员工提交工时财务与发票发票、账单、费用报销、会计科目财务按月生成客户账单和内部报销库存与采购产品、仓库、采购订单供应链团队管理库存和采购计划行政与客户门户知识库、客户自助登录查看订单客户进入门户查看项目进度和发票这些模块并非全部开箱即用有些需要额外配置但整体覆盖面在开源领域已经非常难得。1.3 技术栈视角为什么 Node.js 团队看到它会更亲切传统开源 ERP 大多是 PHP 或 Python 技术栈比如 Odoo 和 ERPNext它们的功能确实强大但如果你是 Node.js 技术团队定制和扩展起来会有明显的知识迁移成本。ever-gauzy 的后端基于 NestJS 和 TypeORM前端使用 Angular整个仓库是 monorepo 结构。也就是说从数据库实体到 REST API再到 Angular 服务层全部是 TypeScript 一脉相承。业务团队可以只维护一套语言体系不需要同时养 PHP、Python 和多套前端语言这一点对我这种长期在 Node 生态里开发的人来说非常讨喜。2. 本地跑通的全过程依赖、数据库、seed 数据2.1 环境准备环节最容易翻车的三点我是在一台全新的 Ubuntu 22.04 服务器上做部署测试的踩坑要素基本都集中在三点Node 版本、PostgreSQL 版本、Yarn 版本。ever-gauzy 官方对 Node 版本有明确要求我用的是 Node 18 LTS运行得比较稳。如果你本机装了 Node 20 或更高也可能会遇到一些原生模块编译不兼容的问题。PostgreSQL 建议直接用 14 或 15版本太老会导致 TypeORM 连接驱动报错。另外这套仓库是典型的 Lerna Yarn workspace 结构如果只用 npm 安装依赖大概率会在依赖软链和 hoisting 阶段出问题所以强烈建议统一用 Yarn 1.x 经典版。2.2 安装依赖时的取舍我的第一步是克隆仓库然后复制.env.example为.env接着执行yarn install。这一步耗时相当长慢的时候可能需要十几分钟因为要拉取 API、UI 以及桌面端 Electron 相关的全部依赖。如果网络状况不理想建议设置 yarn 的镜像源。安装过程中如果看到node-sass或者sharp的编译错误先别慌通常是本机缺少构建工具执行一遍sudo apt install build-essential libpng-dev之后重新安装就好。依赖装好后我习惯先跑一次yarn build把前后端的编译结果都生成一遍这样后面seed和start:server的时候会快很多。如果你跳过这步直接启动开发服务器仍然会实时编译但首次启动会比较卡尤其 Angular 项目的 dev server 首次编译可能需要几分钟内存。2.3 数据库初始化与 seed 操作ever-gauzy 默认使用 PostgreSQL需要在.env里填好数据库连接信息。不同版本的环境变量命名会有一点差异但核心字段基本就是DB_NAME、DB_USER、DB_PASS、DB_HOST。我先在 PostgreSQL 里创建了一个名为gauzy的数据库然后执行了yarn seed。这个 seed 命令会自动跑数据结构迁移并写入一套演示组织、员工和系统内置枚举数据对本地预览很有帮助。如果你不想要演示数据只希望建立空库可以直接跑迁移命令而不是完整 seed。我实际测试下来seed 过程大概会持续几分钟期间日志会滚动输出很多 NestJS 的模块初始化信息不用盯着它泡杯茶等它结束就行。seed 完成后再分别启动 API 和 UI 服务浏览器打开localhost:4200就能看到登录页。使用 seed 生成的默认管理员账号登录系统会引导进入工作台。2.4 启动后第一件事登录与控制台登录进系统后我建议先不要急着点各个菜单而是进入设置页面看一下“租户和用户”的配置。ever-gauzy 的权限模型跟大部分单体系统不一样它先有租户Tenant租户下再建立组织Organization用户必须在特定组织下才具备业务数据权限。第一次登录时你会看到一个默认组织这里面包含了销售管道、员工列表等 demo 数据。如果在左侧菜单发现某些模块没有数据不是 bug而是因为你当前用户没有分配到对应组织的角色权限。3. 我踩过的坑从连不上数据库到界面白屏的排查链路3.1 数据库连接报错问题往往不在密码本身部署过程中见过的最高频报错是 API 启动时提示Unable to connect to the database。大多数人会先去检查密码但我的排查结果显示真正的原因通常是.env和数据库实际配置不一致尤其是DB_TYPE或端口被写错。另外如果你在 Windows 上跑 PostgreSQL默认安装经常不会启动服务需要去服务管理器里把postgresql-x64-14服务启动起来。还有一个隐藏很深的点ever-gauzy 支持通过环境变量区分 API 数据库和桌面数据库如果只配了 API 库Electron 桌面端启动时还是会报连接失败。我后来直接把桌面端相关配置统一指向同一个 PostgreSQL 实例才彻底消停。3.2 编译过程中 Node 内存溢出前端 Angular 和整个 monorepo 同时编译时很容易遇到JavaScript heap out of memory。这个问题在我机器上出现过好多次原因是默认 Node 堆内存不够。解决方式是在启动命令前加上NODE_OPTIONS--max_old_space_size4096或者在 package.json 的启动脚本里注入这个参数。如果你用的版本比较老可能还需要显式调整 Angular 的budget配置否则代码量一大就会出现警告甚至中断编译。这一条对任何大型 monorepo 项目都适用建议直接写进你的开发文档里。3.3 seed 出现重复数据的根因yarn seed跑了几次之后我发现页面上组织列表出现了重复的演示组织后来定位到是因为我中途手动中断过 seed导致部分幂等逻辑没有执行完整。再跑 seed 时系统不会自动清理之前已经插入的部分数据于是出现了重复。解决办法也很简单先清空数据库再重新 seed或者直接重建一个库。这个坑提醒我在操作开源 ERP 时不要想当然认为 seed 是可以反复安全执行的最好每次都在干净库上操作。3.4 前端 404 / 白屏路由回退与静态资源路径另一个让我卡到快崩溃的问题是 API 启动正常但前端打开后一直是白屏。浏览器控制台的报错涉及一些静态资源 404同时还伴随 Angular 路由回退问题。排查后发现是因为我直接用localhost:4200访问没问题但一旦通过 Nginx 反代到子路径Angular 的base href没有跟着改所有 JS/CSS 请求都指向了根路径。后来我把 Nginx 配置里的location做了精确匹配并在 index.html 里设置好base href/白屏问题就消失了。4. 核心模块拆解一个成熟开源 ERP 的设计思路4.1 租户与组织的分层权限模型ever-gauzy 的权限模型几乎可以作为 SaaS 后端设计的教科书案例。最上层是租户租户是一个独立数据域下面是组织组织之间业务数据彼此隔离。用户在同一个租户下可以同时属于多个组织但每个组织里的角色权限不同。这种设计在真实企业场景里非常有用集团下多个子公司各自独立管理但集团总部可以跨组织查看汇总数据。API 层通过 JWT 中的租户信息解析当前上下文后端 service 里大量使用了tenantId和organizationId的双重过滤条件。这提醒我们如果要做自己的多租户系统租户隔离必须在数据库查询层统一约束而不是在每个业务接口里各自处理。4.2 基于 TypeORM 的实体关系设计看代码的时候我特别关注了实体关系定义。ever-gauzy 的实体类分散在各自模块中通过装饰器声明关系比如用户和员工是一对一员工和部门是多对一订单和发票是一对多。TypeORM 的RelationId和JoinColumn用法很规范几乎可以作为企业级 TypeScript 项目的代码规范参考。值得注意的一点是它的每张业务表和数据库迁移文件都是独立维护的修改实体后需要手动生成 migration而不是在运行时自动同步表结构。这会增加一点开发心智负担但好处是生产环境可以用迁移脚本来做版本化变更避免数据表结构混乱。4.3 消息队列与实时通知的落地方式在本地开发时你可能察觉不到但 ever-gauzy 设计了不少异步任务比如邮件发送、定时生成任务提醒、报表异步导出。这些场景依赖消息队列来解耦后台框架使用了 NestJS 的bull模块接 Redis。我们做二次开发时如果某个操作特别耗时也应该借鉴这种模式先写一个异步 processor再通过队列在 controller 里触发避免用户请求一直卡住。实际部署时一定要记得把 Redis 服务纳入到运维清单里否则队列任务会不断重试但不会真正执行。4.4 可配置仪表盘的实现思路它的工作台首页不是写死的而是由多个可视化组件动态拼装。每个组件对应一个后端聚合接口比如“本月销售额”“待处理订单数”“员工请假趋势”。这些聚合接口基本都是通过 service 层跑复杂查询再组合成统一的数据结构。整体下来我发现它的数据呈现思路很清晰后端只提供结构化的汇总数据前端负责布局和图表渲染。如果你想自定义首页指标不必大改前端页面只需要新增一个类似的数据聚合服务再挂到一个组件上就能快速上线。5. 二次开发手册从改数字段到新增业务模块5.1 最小改动调整页面字段显示对绝大多数企业来说二次开发第一步都是改字段比如把“客户名称”改成“客户全称”或者在员工表单里加一个“工号”字段。这里我推荐一个低风险的路径直接在 Angular 表单组件里调整显示标签后端实体暂时不动。这样不会影响数据库结构改完刷新页面就能生效。等确认字段确实需要持久化再去 entity 里增加Column属性并生成新 migration。我的经验是先改前端解决业务临时需求再集中做数据库结构调整比一上来就大动干戈要稳妥得多。5.2 新增一个业务模块的标准姿势如果是新增一个完整业务对象比如“资产登记”我通常会在apps/gauzy-api/src下建立一个资产模块包含AssetModule、AssetController、AssetService、AssetEntity四个文件并仿照已有模块的命名风格编写。Controller 中基本只做参数校验和调用 service所有复杂业务逻辑都塞进 service这样单元测试和维护都会简单很多。前端角色也一样新增一个 features 目录下的页面模块在路由配置里指向新组件再通过菜单权限控制入口。整个过程能跑通的前提是前后端使用同一套 TypeScript 类型意识接口返回的结构尽量保持一致。5.3 扩展 API 时需要留意的权限注解修改后端接口时最容易忽略的是权限装饰器。ever-gauzy 的每个可访问接口基本都使用了Permissions()装饰器如果你在自定义接口上漏掉权限描述登录用户即使有页面访问权限也会拿到 403。我在开发一个自定义报表接口时遇到过这个问题后来发现必须同步在PermissionsEnum枚举里增加一个CUSTOM_REPORT_VIEW权限并给角色分配后才生效。另外接口层的 Query 参数里经常会用到TenantBase相关 DTO新增查询条件时要注意类型继承不然请求参数不会被正确解析。5.4 自定义数据源在既有表结构上做接缝扩展很多开源 ERP 的扩展点都在数据库层面。如果你想接入企业已有的系统比如从旧的 CRM 里同步客户比较合理的做法不是去改核心表而是创建一个集成表保留旧系统的主键和同步时间戳再通过后台定时任务把数据映射到 ever-gauzy 的业务表里。这种方法不会在升级版本时和官方实体产生冲突也可以随时回滚。我在实际项目中就用这种方式接入了企业微信通讯录角色同步也只做新增和更新不做物理删除保证误操作后还能恢复数据。6. 生产部署与运维建议6.1 Docker Compose 方式的好处如果只是本地开发直接跑源码服务问题不大但生产环境我更推荐 Docker Compose。ever-gauzy 官方提供了 compose 文件里面包含了 API、UI、PostgreSQL、Redis 等服务。容器化的好处是能够把 Node 版本、数据库版本、系统依赖全部锁定在同一套环境里避免“在我机器上明明能跑”的尴尬。我自己的服务器配置是 4 核 8G跑一套 compose 之后 CPU 和内存都比较宽裕。如果你团队有 Docker 基础这会是最省心的部署路径。6.2 Nginx 反代与 HTTPS生产环境的 UI 往往不是直接暴露 80 端口我会用 Nginx 做反向代理。核心配置是location /api转发到 API 服务端口location /转发到 UI 服务端口同时启用 WebSocket 代理否则系统里的实时通知和在线状态功能会失效。SSL 证书方面我使用 Let’s Encrypt 自动续期没有做特殊配置但要注意 Nginx 里需要正确设置proxy_set_header Host和X-Forwarded-Proto这样系统生成链接时才不会出现 http/https 混用的问题。6.3 数据库备份与迁移数据库是整个系统最核心的资产我在自动化运维脚本里每天执行pg_dump备份备份文件保留最近 7 天并同步到独立的对象存储。除了常规备份建议在每次升级前手动导出一份 SQL因为 seed 或 migration 脚本在升级时可能会改写表结构出错时至少能恢复原状。升级完毕后最少要做一轮“创建订单到生成发票再导出报表”的冒烟测试确保核心链路没有断裂。6.4 版本升级需要注意的事项ever-gauzy 迭代速度不算慢升级时要特别关注两个文件CHANGELOG.md和migration文件夹。正式升级前我会先看发布说明里是否有破坏性变更比如环境变量重命名、数据库表字段修改、API 路由路径调整。然后再在测试环境完整执行一次升级流程等稳定之后再操作生产环境。如果在升级过程中出现自定义模块的依赖包版本冲突先不要盲目改源码优先检查是不是没有同步官方仓库的依赖升级很多时候yarn install一次就能解决。7. 我的真实使用体会从部署 ever-gauzy 到基于它做业务定制我最大的感受是开源 ERP 并不等于“省心”但如果你愿意花时间摸清楚它的设计套路它能省下从零搭建一套企业级后台的大量时间。它的多租户模型和模块拆分方式都很成熟二次开发成本远低于我从前的预期。最让我意外的其实是它的工时和项目管理模块和财务发票链路打通之后整个团队的项目核算都变得清晰了。如果你有长期使用的打算建议从本地 seed 环境开始先用 demo 数据把每个菜单点一遍再决定从哪个业务模块切入改造。毕竟选型这件事实际点了页面才知道合不合适。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →