心智模型
三层: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.json4. 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 / dependencies7. 构建与安装产物路径
源码、可安装、已安装是不同目录。安装后页面空白时,检查 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.json8. 布局规则
- 禁止直接导入其他插件 src/
- 用插件名为表、路由、菜单键、registry id 加命名空间
- API 放在 src/api,不要写进页面组件
- 不要手改 available/installed — 用 quan-erp CLI + UI 安装
- backend/frontend 的 @quan-erp/* 版本与 base 镜像对齐
- 不确定时以 sample-es 为准