演示

目录结构

Quan ERP Node 模板全景:仓库根目录、base 运行时、插件源码布局,以及 watch / install 产物路径。

心智模型

三层:plugins/ 写源码;base/available-plugins/ 暂存构建;base/backend/installed-plugins/ 是运行时真正加载的副本。quan-erp CLI 负责 source → available;ERP UI 负责 available → installed。

  • 始终在仓库根目录运行 quan-erp
  • plugins/ 文件夹名必须等于 module.metadata.json 的 name
  • 包名:@quan-erp-plugins/<name>-backend|frontend
  • 禁止直接导入其他插件的 src/

1. 仓库根目录

quan-erp-node-template(或你的 fork)顶层结构:

  • base/ — 用 Docker Compose 运行的平台核心
  • plugins/ — 业务插件源码;参考 sample-es
  • .agents/ — AI agent skills & rules
  • erp — 优先用 quan-erp watch <name>
SHworkspace
1my-quan-erp/ # repo root (run quan-erp here) 2├── erp # CLI binary — watch / build / pack / new 3├── .agents/ # Quan ERP skills & rules for AI agents 4├── .gitignore 5├── README.md 6├── base/ # runnable platform core (Docker) 7│ ├── docker-compose.yaml # db, redis, backend, frontend 8│ ├── available-plugins/ # built plugins waiting to install 9│ │ └── <name>/<version>/ 10│ │ ├── backend/ 11│ │ ├── frontend/ 12│ │ └── module.metadata.json 13│ ├── backend/ 14│ │ ├── Dockerfile 15│ │ ├── .env / .env.sample # local secrets (do not commit real values) 16│ │ ├── installed-plugins/ # active plugins served at runtime 17│ │ │ └── <name>/ 18│ │ │ ├── backend/ 19│ │ │ ├── frontend/ 20│ │ │ └── module.metadata.json 21│ │ └── logs/ # optional host-mounted logs 22│ ├── frontend/ # base UI core image / nginx 23│ └── data/ # optional local volumes (db, redis, uploads) 24└── plugins/ # YOUR source code lives here 25 ├── sample-es/ # reference plugin — copy patterns from here 26 └── <my-plugin>/ # one folder per plugin 27 ├── module.metadata.json # name MUST match folder name 28 ├── backend/ 29 └── frontend/

2. base/ — 平台核心

base 是薄运行时:compose 服务、插件目录与主机配置。业务页面写在 plugins,而不是 base 前端源码里。

  • docker-compose.yaml — Postgres、Redis、backend、frontend
  • available-plugins/<name>/<version>/ — quan-erp watch|build:prod 输出
  • backend/installed-plugins/<name>/ — 已安装插件
  • backend/.env — 密钥(勿提交真实值)
  • frontend/ — 基础核心;插件在运行时注入 UI
  • data/ — 可选本地数据卷

3. plugins/<name>/

一个插件 = metadata + backend 包 + frontend 包。

  • module.metadata.json 与 backend/、frontend/ 同级
  • 按领域拆 feature 目录,避免把一切堆在 src/
  • quan-erp pack:prod 后可能出现 output/(可 gitignore)
SHplugin
1plugins/<my-plugin>/ 2├── module.metadata.json # identity + deps + version contract 3├── backend/ 4│ ├── package.json # @quan-erp-plugins/<name>-backend 5│ ├── tsconfig.json 6│ ├── nest-cli / build config # as shipped by the template 7│ └── src/ 8│ ├── index.ts # IPlugin default export → getRootModule() 9│ ├── export.ts # optional: publish for other plugins 10│ ├── <feature>/ # one folder per domain (recommended) 11│ │ ├── *.controller.ts 12│ │ ├── *.service.ts 13│ │ └── dto/ 14│ └── schema/ # TypeORM entities (plugin tables) 15│ └── *.entity.ts 16└── frontend/ 17 ├── package.json # @quan-erp-plugins/<name>-frontend 18 ├── vite.config.ts 19 ├── tsconfig.json 20 ├── index.html 21 └── src/ 22 ├── index.tsx # PluginModule.register(AppRegistry) 23 ├── export.ts # public API for PluginAPI consumers 24 ├── api/<domain>/ # React Query + axios calls 25 ├── page/<feature>/ # screens / dialogs 26 ├── components/ # plugin-local UI pieces 27 ├── hooks/ # plugin-local hooks (optional) 28 ├── store/ # plugin-local Zustand (optional) 29 ├── locales/ # translation dictionaries (optional) 30 └── lib/ 31 ├── axios.ts # setAxiosClient / getAxiosClient 32 └── metadata.ts # typed module.metadata.json

4. module.metadata.json

供 CLI、发现逻辑与 UI 安装读取的身份文件。

  • name — 必须与 plugins/<name>/ 一致
  • pluginVersion — available-plugins 下的版本目录名
  • requiredBasedVersion — 与 base / @quan-erp/* 对齐
  • moduleEntryObject — 后端根 @Module 类名
  • pluginDependencies — 需先加载的其他插件
JSONmodule.metadata.json
1{ 2 "name": "sample-es", 3 "type": "", 4 "pluginVersion": "1.0.0", 5 "description": "Sample plugin", 6 "moduleEntryObject": "Module", 7 "requiredBasedVersion": "1.0.0", 8 "pluginDependencies": {} 9}

5. 后端布局(详)

默认导出 IPlugin 的 TypeScript 包。控制器、服务、DTO、实体均应带插件命名空间。

  • index.ts — 宿主导入的唯一入口(构建后为 module.js)
  • schema/ — TypeORM 实体;表名加插件前缀
  • dto/ — 校验与传输类型
  • export.ts — 可选的跨插件发布面
  • 不要进入其他插件的 backend/src
SHbackend
1plugins/<name>/backend/src/ 2├── index.ts 3# default-export class implements IPlugin 4# getRootModule() → @Module class 5# getMetadata() → module.metadata.json 6├── export.ts 7# optional — symbols other plugins may consume after publish 8├── <feature>/ # e.g. employee/, leave/, payroll/ 9│ ├── <feature>.controller.ts # @Controller + routes 10│ ├── <feature>.service.ts # @Service business logic 11│ ├── dto/ 12│ │ ├── create-*.dto.ts 13│ │ └── query-*.dto.ts 14│ └── <feature>.module bits # providers registered on root @Module 15└── schema/ 16 ├── <feature>.entity.ts # @Entity — namespace table names 17 └── index.ts # re-export entities for @Module({ entities })

6. 前端布局(详)

Vite React 应用。核心只加载 src/index.tsx 并调用 register(AppRegistry)。

  • index.tsx — 菜单、路由、仪表盘、PluginAPI 等
  • api/ — HTTP + React Query
  • page/ — 路由级页面
  • lib/axios.ts — 宿主客户端桥接
  • lib/metadata.ts — 类型化读取 metadata
  • export.ts — 仅导出其他插件可用的稳定 API
SHfrontend
1plugins/<name>/frontend/src/ 2├── index.tsx 3# default-export PluginModule 4# register(AppRegistry): wire axios, menus, routes, dashboards, … 5├── export.ts 6# stable public surface for PluginAPI.expose / consumers 7├── api/ 8│ └── <domain>/ 9│ ├── <domain>.api.ts # axios + React Query hooks 10│ └── types.ts # request/response types 11├── page/ 12│ └── <feature>/ 13│ ├── <feature>.page.tsx # route screen 14│ ├── <feature>-form.tsx 15│ └── columns.tsx # table defs (optional) 16├── components/ # shared inside this plugin only 17├── hooks/ 18├── store/ 19├── locales/ 20│ ├── en.json 21│ └── mm.json 22└── lib/ 23 ├── axios.ts # host client bridge 24 └── metadata.ts # name / version / dependencies

7. 构建与安装产物路径

源码、可安装、已安装是不同目录。安装后页面空白时,检查 installed-plugins 与 module 表,而不仅是 plugins/。

  • quan-erp watch|build:prod → base/available-plugins/<name>/<version>/
  • ERP UI 安装 → base/backend/installed-plugins/<name>/
  • 若已安装,开发时 watch 也会刷新 installed 副本
  • quan-erp pack:prod → zip(默认 output/ 或你指定的目录)
SHartifacts
1# Source (edit here) 2plugins/<name>/{backend,frontend,module.metadata.json} 3 4# After quan-erp watch|build:prod → staged for install 5base/available-plugins/<name>/<version>/ 6├── backend/ # compiled backend dist 7├── frontend/ # Vite build output 8└── module.metadata.json 9 10# After ERP UI Install → active at runtime 11base/backend/installed-plugins/<name>/ 12├── backend/ 13├── frontend/ 14└── module.metadata.json

8. 布局规则

  • 禁止直接导入其他插件 src/
  • 用插件名为表、路由、菜单键、registry id 加命名空间
  • API 放在 src/api,不要写进页面组件
  • 不要手改 available/installed — 用 quan-erp CLI + UI 安装
  • backend/frontend 的 @quan-erp/* 版本与 base 镜像对齐
  • 不确定时以 sample-es 为准