docs: add inter-plugin communication (RPC + discovery) docs to README
This commit is contained in:
parent
d9c87aef0a
commit
11e1827031
144
README.md
144
README.md
|
|
@ -19,6 +19,7 @@ SDK для створення плагінів ERP-платформи. Міст
|
||||||
- [Інтерфейси](#інтерфейси)
|
- [Інтерфейси](#інтерфейси)
|
||||||
- [Attribute Access Control (ABAC)](#attribute-access-control-abac)
|
- [Attribute Access Control (ABAC)](#attribute-access-control-abac)
|
||||||
- [Події та RabbitMQ](#події-та-rabbitmq)
|
- [Події та RabbitMQ](#події-та-rabbitmq)
|
||||||
|
- [Міжплагінна комунікація](#міжплагінна-комунікація)
|
||||||
- [CLI — create-erp-plugin](#cli--create-erp-plugin)
|
- [CLI — create-erp-plugin](#cli--create-erp-plugin)
|
||||||
- [Експорт SDK](#експорт-sdk)
|
- [Експорт SDK](#експорт-sdk)
|
||||||
|
|
||||||
|
|
@ -64,24 +65,32 @@ npx create-erp-plugin my-plugin --port 3007
|
||||||
|
|
||||||
```
|
```
|
||||||
┌───────────────────┐ HTTP/REST ┌──────────────┐
|
┌───────────────────┐ HTTP/REST ┌──────────────┐
|
||||||
│ Plugin (BE) │ ◄──────────────────► │ Core (BE) │
|
│ Plugin A (BE) │ ◄──────────────────► │ Core (BE) │
|
||||||
│ CoreService │ RabbitMQ │ Port 3001 │
|
│ CoreService │ RabbitMQ │ Port 3001 │
|
||||||
│ AttributeAccess │ ◄──────────────────► │ │
|
│ AttributeAccess │ ◄──────────────────► │ │
|
||||||
└────────┬──────────┘ └──────────────┘
|
└────────┬──────────┘ └──────────┬───┘
|
||||||
│
|
│ ┌───────────────────────▲ │
|
||||||
Module Federation
|
│ Plugin→Plugin│ HTTP RPC Proxy │ │
|
||||||
│
|
│ v1.3.0 │ │ │
|
||||||
┌────────▼──────────┐
|
│ ┌──────┴───────┐ │ │
|
||||||
│ Plugin (FE) │
|
│ │ Plugin B (BE)│ │ │
|
||||||
│ React + Vite │
|
│ │ callPlugin │───────────────┘ │
|
||||||
│ host/UIKit │
|
│ └──────────────┘ │
|
||||||
└───────────────────┘
|
│ │
|
||||||
|
Module Federation Module Fed.
|
||||||
|
│ │
|
||||||
|
┌────────▼──────────┐ ┌──────────▼───┐
|
||||||
|
│ Plugin A (FE) │ │ Plugin B(FE)│
|
||||||
|
│ React + Vite │ │ React + Vite│
|
||||||
|
│ host/UIKit │ │ host/UIKit │
|
||||||
|
└───────────────────┘ └──────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
**Комунікація:**
|
**Комунікація:**
|
||||||
1. **HTTP (REST)** — `CoreService.fetchCore()` для запитів до ядра
|
1. **HTTP (REST)** — `CoreService.fetchCore()` для запитів до ядра
|
||||||
2. **RabbitMQ (асинхронно)** — `CoreService.emit()` для подій, `@EventPattern()` для отримання
|
2. **RabbitMQ (асинхронно)** — `CoreService.emit()` для подій, `@EventPattern()` для отримання
|
||||||
3. **Module Federation** — фронтенд плагіна монтується як remote module всередині host-застосунку
|
3. **Plugin→Plugin RPC** (v1.3.0+) — `CoreService.callPluginApi()` для виклику API іншого плагіна через core-proxy
|
||||||
|
4. **Module Federation** — фронтенд плагіна монтується як remote module всередині host-застосунку
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -152,6 +161,40 @@ await coreService.sendNotification({
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `callPluginApi<T>(pluginId, path, body?)`
|
||||||
|
|
||||||
|
Викликати API іншого плагіна через core RPC-проксі. Запит проксується ядром на `backendUrl` цільового плагіна методом POST. JWT-токен автоматично прокидyється.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Викликати ендпоінт плагіна notifications
|
||||||
|
const result = await coreService.callPluginApi('notifications', 'stats', { period: 'week' });
|
||||||
|
|
||||||
|
// Викликати з вкладеним шляхом
|
||||||
|
const user = await coreService.callPluginApi('user-management', 'users/42');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `discoverPlugins()`
|
||||||
|
|
||||||
|
Отримати список усіх зареєстрованих плагінів з їхніми можливостями. Повертає масив маніфестів з полями: `id`, `name`, `label`, `icon`, `routePath`, `backendUrl`, `events`, `objectTypes`, `permissions`, `roles`, `database`, `menu`, `headerActions`.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const plugins = await coreService.discoverPlugins();
|
||||||
|
|
||||||
|
// Знайти плагін за id
|
||||||
|
const notifPlugin = plugins.find(p => p.id === 'notifications');
|
||||||
|
console.log(notifPlugin.backendUrl); // http://notifications:3008
|
||||||
|
|
||||||
|
// Знайти всі плагіни, що оголосили певну подію
|
||||||
|
const listeners = plugins.filter(p =>
|
||||||
|
p.events?.some(e => e.name === 'core.user.created')
|
||||||
|
);
|
||||||
|
|
||||||
|
// Знайти плагіни, що працюють з певним типом об'єктів
|
||||||
|
const dealPlugins = plugins.filter(p =>
|
||||||
|
p.objectTypes?.includes('deal')
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
#### `getDbName()`
|
#### `getDbName()`
|
||||||
|
|
||||||
Отримати назву БД (після `setupDatabase`).
|
Отримати назву БД (після `setupDatabase`).
|
||||||
|
|
@ -552,6 +595,83 @@ async handle(@Payload() data: any) {
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Міжплагінна комунікація
|
||||||
|
|
||||||
|
До версії 1.3.0 плагіни могли спілкуватись тільки через ядро (HTTP до core + RabbitMQ broadcast). Починаючи з v1.3.0 додано підтримку прямого плагін→плагін зв'язку через HTTP RPC проксі.
|
||||||
|
|
||||||
|
### Архітектура
|
||||||
|
|
||||||
|
```
|
||||||
|
Plugin A Core Backend Plugin B
|
||||||
|
| | |
|
||||||
|
|-- discoverPlugins() ----------->| |
|
||||||
|
|<-- [{ id:'notifications', ... }]| |
|
||||||
|
| | |
|
||||||
|
|-- callPluginApi('notifications', | |
|
||||||
|
| 'stats', { period:'week' })-->| |
|
||||||
|
| |-- POST /stats -------------->|
|
||||||
|
| |<-- { sent: 42 } ------------|
|
||||||
|
|<-- { sent: 42 } ----------------| |
|
||||||
|
```
|
||||||
|
|
||||||
|
Всі запити проходять через Core, який:
|
||||||
|
1. **Перевіряє JWT** (як і будь-який захищений ендпоінт)
|
||||||
|
2. **Визначає `backendUrl`** цільового плагіна з реєстру
|
||||||
|
3. **Проксує POST-запит** з автентифікацією та тілом
|
||||||
|
|
||||||
|
### Discover — дізнатись які плагіни доступні
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const plugins = await coreService.discoverPlugins();
|
||||||
|
```
|
||||||
|
|
||||||
|
Кожен плагін має:
|
||||||
|
- `id`, `name`, `label`, `backendUrl` — адреса для RPC
|
||||||
|
- `events: { name, description }[]` — які події оголошує
|
||||||
|
- `objectTypes: string[]` — з якими об'єктами працює
|
||||||
|
- `permissions`, `roles` — права доступу
|
||||||
|
|
||||||
|
### RPC — викликати API іншого плагіна
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const stats = await coreService.callPluginApi('notifications', 'stats');
|
||||||
|
const user = await coreService.callPluginApi('user-management', 'users/42');
|
||||||
|
const result = await coreService.callPluginApi('global-store', 'store/set', {
|
||||||
|
key: 'my-key',
|
||||||
|
value: { foo: 'bar' },
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Обмеження:**
|
||||||
|
- Тільки POST-метод (ядро проксує POST на `backendUrl` цільового плагіна). Для GET-ендпоінтів цільового плагіна — використовуйте `@Post()` контролер з потрібною логікою.
|
||||||
|
- Потребує JWT-токена (як і будь-який захищений API). Токен автоматично прокидyється з контексту запиту.
|
||||||
|
- Якщо плагін не зареєстрований або не має `backendUrl` — повертається 404.
|
||||||
|
|
||||||
|
### Типовий сценарій використання
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// В сервісі плагіна A
|
||||||
|
async function notifyAndLog() {
|
||||||
|
// 1. Discovery — знайти потрібний плагін
|
||||||
|
const plugins = await this.coreService.discoverPlugins();
|
||||||
|
const notifPlugin = plugins.find(p => p.events?.some(e => e.name === 'notification.send'));
|
||||||
|
|
||||||
|
// 2. RPC — викликати API плагіна B
|
||||||
|
if (notifPlugin) {
|
||||||
|
await this.coreService.callPluginApi('notifications', 'send', {
|
||||||
|
userId: 1,
|
||||||
|
title: 'Event occurred',
|
||||||
|
message: 'Plugin A triggered a notification',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Або викликати будь-який кастомний ендпоінт
|
||||||
|
const status = await this.coreService.callPluginApi('audit-logs', 'stats/daily');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## CLI — create-erp-plugin
|
## CLI — create-erp-plugin
|
||||||
|
|
||||||
Генерація нового плагіна:
|
Генерація нового плагіна:
|
||||||
|
|
@ -612,7 +732,7 @@ my-plugin/
|
||||||
|
|
||||||
```
|
```
|
||||||
@erp/plugin-sdk
|
@erp/plugin-sdk
|
||||||
├── CoreService # Головний сервіс (fetchCore, emit, register, ...)
|
├── CoreService # Головний сервіс (fetchCore, emit, register, callPluginApi, discoverPlugins, ...)
|
||||||
├── CoreClientService # RabbitMQ RPC клієнт
|
├── CoreClientService # RabbitMQ RPC клієнт
|
||||||
├── AttributeAccessService # ABAC — керування атрибутами та перевірка доступу
|
├── AttributeAccessService # ABAC — керування атрибутами та перевірка доступу
|
||||||
├── getRabbitMQOptions() # NestJS Microservice options
|
├── getRabbitMQOptions() # NestJS Microservice options
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue