Initial: kyrykbaev_i joins the platform

This commit is contained in:
kyrykbaev_i 2026-05-18 09:37:49 +05:00
commit 0d2ab71165
5 changed files with 695 additions and 0 deletions

33
.gitignore vendored Normal file
View File

@ -0,0 +1,33 @@
# secrets
.env
.env.local
.jwt-secret
credentials*.json
secrets.json
*.pem
*.key
id_rsa*
id_ed25519*
# build artifacts
node_modules/
.venv/
venv/
__pycache__/
*.pyc
.next/
dist/
build/
out/
target/
# data
*.sqlite*
*.db
*.log
# OS / IDE
.DS_Store
.claude/
.vscode/
.idea/

23
PRD.md Normal file
View File

@ -0,0 +1,23 @@
# Product Requirements Description
## Что я хочу автоматизировать
<!-- Опиши простыми словами, какую боль ты решаешь -->
## Кто будет пользоваться
<!-- Финансист? Руководитель? Бухгалтер? -->
## Что должно произойти на выходе
<!-- Какой результат ты получишь, и кто его получает? -->
## Шаги взаимодействия
<!-- 1. Пользователь делает X
2. Система проверяет Y
3. Если Z — ... иначе — ... -->
## Что НЕ входит в задачу
<!-- Чтобы не разрастаться -->

26
README.md Normal file
View File

@ -0,0 +1,26 @@
# kyrykbaev_i
Привет, kyrykbaev_i!
Это твоя личная папка в среде telecom.quest.
- VS Code в браузере: https://code.telecom.quest/?folder=/Users/telecom/dev/_hack18may/kyrykbaev_i/
- Бэкап на Gitea: https://git.telecom.quest/kt-innovators/kyrykbaev_i
## Action Plan (как пользоваться)
В этой папке уже лежат три стартовых файла:
- `PRD.md` — здесь ты простыми словами описываешь, что хочешь автоматизировать
- `ZORRO.md` — справочник по системе Zorro (для Claude, не для тебя)
- `TRD.md` — пустой; Claude заполнит его после того, как ты напишешь PRD
**Шаг 1.** Открой `PRD.md` и напиши свою идею.
**Шаг 2.** Открой Claude (Desktop или web). Дай ему `PRD.md` + `ZORRO.md` и попроси: «Сделай TRD.md на основе PRD и ZORRO».
**Шаг 3.** Сохрани результат в `TRD.md`.
**Шаг 4.** Запусти Claude Code в этой папке. Скажи: «Реализуй TRD.md». Получишь рабочий MVP.
## Как сохранять работу
В VS Code открой панель "Source Control" (слева), напиши краткое описание, нажми галочку → "Commit and Push".
Изменения сохранятся в Gitea и будут доступны при следующем входе.
В этой папке уже инициализирован git и подключен remote `origin` → Gitea.

15
TRD.md Normal file
View File

@ -0,0 +1,15 @@
# Technical Requirements Description
<!--
Этот файл создаст Claude.
Открой Claude (Desktop или web), приложи:
1. этот файл (или скажи "сделай TRD.md")
2. PRD.md (твоё описание идеи)
3. ZORRO.md (справочник по Zorro)
Попроси: "Сделай TRD на основе PRD и ZORRO. Опиши какие BPMN-задачи нужны,
какие API-эндпоинты Zorro вызывать, какие данные передавать."
Полученный текст положи сюда (замени этот комментарий).
-->

598
ZORRO.md Normal file
View File

@ -0,0 +1,598 @@
# ZorroBPM Development Guide
Единый справочник для разработки процессов на ZorroBPM.
---
## Содержание
- [Архитектура](#архитектура)
- [Окружения](#окружения)
- [Локальный запуск](#локальный-запуск)
- [Docker Compose — полный стек](#docker-compose--полный-стек)
- [Docker Compose — только фронт (dev)](#docker-compose--только-фронт-dev)
- [Docker Compose — фронт + воркеры](#docker-compose--фронт--воркеры)
- [API Reference](#api-reference)
- [RabbitMQ и внешние воркеры](#rabbitmq-и-внешние-воркеры)
- [Разработка процессов](#разработка-процессов)
- [Тестирование](#тестирование)
- [Примеры](#примеры)
- [Известные ограничения](#известные-ограничения)
---
## Архитектура
```
┌──────────┐ ┌──────────────┐ ┌────────────┐
│ UI │────▶│ REST API │────▶│ PostgreSQL │
│ (nginx) │ │ (Spring Boot)│ │ │
└──────────┘ └──────┬───────┘ └────────────┘
│
▼
┌──────────────┐ ┌────────────────┐
│ RabbitMQ │◀───▶│ External │
│ │ │ Workers (опц.) │
└──────────────┘ └────────────────┘
```
| Компонент | Образ | Описание |
|-----------|-------|----------|
| **api** | `zorrodev/zorrobpm-rest` | BPM движок. Управляет определениями, инстансами, задачами, инцидентами |
| **ui** | `zorrodev/zorrobpm-ui` | Nginx SPA — мониторинг процессов, задач, деплоев |
| **db** | `postgres:18` | Хранит определения, инстансы, переменные, инциденты |
| **rabbitmq** | `rabbitmq:4.0.7-management` | Очереди для serviceTask и событий жизненного цикла |
---
## Окружения
| Окружение | URL | Примечание |
|-----------|-----|------------|
| **LOCAL** | http://localhost:9092 | Docker Compose |
| **PROD** | https://api.bpms.telecom.kz | Через VPN |
| **DEV Studio** | https://studio.zorrobpm.dev | Визуальный редактор |
| **DEV Station** | https://station.zorrobpm.dev | Мониторинг |
| **DEMO (m11s)** | https://api.m11s.zorrobpm.dev | Микросервисная демо-среда |
Swagger UI:
- Local: http://localhost:9092/swagger-ui/index.html
- Demo: https://api.m11s.zorrobpm.dev/swagger-ui/index.html
Аутентификация: не требуется (dev-окружение).
---
## Локальный запуск
```bash
# Запуск полного стека
docker compose -f docker-compose.yaml --env-file .env up -d
# Логи API
docker compose logs api -f
# Остановка
docker compose down
# Остановка + удаление данных
docker compose down -v
```
---
## Docker Compose — полный стек
Полный стек для самостоятельного запуска движка. Используй только если нужен свой локальный инстанс BPM.
```yaml
# docker-compose.yaml — полный стек ZorroBPM
services:
api:
image: zorrodev/zorrobpm-rest
environment:
- DB_URL=jdbc:postgresql://db/${DB_NAME}
- DB_USERNAME=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD}
- APP_FILES_DIR=/files
- RABBITMQ_HOST=rabbitmq
- RABBITMQ_USERNAME=${RABBITMQ_USER}
- RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}
- RABBITMQ_PORT=5672
volumes:
- files:/files
ports:
- 9092:80
db:
image: postgres:18
environment:
- POSTGRES_DB=${DB_NAME}
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
volumes:
- db:/var/lib/postgresql/18/docker
ports:
- "0.0.0.0:5435:5432"
ui:
image: zorrodev/zorrobpm-ui
ports:
- 9091:80
environment:
- ZORROBPM_API_URL=http://zorrobpm.local
rabbitmq:
image: rabbitmq:4.0.7-management
restart: unless-stopped
environment:
- RABBITMQ_DEFAULT_USER=${RABBITMQ_USER}
- RABBITMQ_DEFAULT_PASS=${RABBITMQ_PASSWORD}
volumes:
- rabbitmq-data:/var/lib/rabbitmq
volumes:
rabbitmq-data:
db:
files:
```
`.env`:
```env
DB_NAME=zorrobpm
DB_USER=zorrobpm
DB_PASSWORD=zorrobpm
RABBITMQ_USER=guest
RABBITMQ_PASSWORD=guest
```
---
## Docker Compose — только фронт (dev)
**Для разработки процессов без локального движка.** Подключается к удалённому API (demo, dev или prod). Не нужны PostgreSQL, RabbitMQ, API — только UI.
```yaml
# docker-compose.front.yaml — фронт без движка
services:
ui:
image: zorrodev/zorrobpm-ui
ports:
- 9091:80
environment:
- ZORROBPM_API_URL=${ZORROBPM_API_URL}
```
`.env.front`:
```env
# Указать один из:
ZORROBPM_API_URL=https://api.m11s.zorrobpm.dev # demo
# ZORROBPM_API_URL=https://api.bpms.telecom.kz # prod (VPN)
# ZORROBPM_API_URL=http://localhost:9092 # local
```
```bash
docker compose -f docker-compose.front.yaml --env-file .env.front up -d
```
---
## Docker Compose — фронт + воркеры
**Когда процесс содержит serviceTask с внешними воркерами.** Фронт для мониторинга + RabbitMQ для получения задач + твой воркер.
```yaml
# docker-compose.workers.yaml — фронт + RabbitMQ воркеры
services:
ui:
image: zorrodev/zorrobpm-ui
ports:
- 9091:80
environment:
- ZORROBPM_API_URL=${ZORROBPM_API_URL}
# Пример Java-воркера
worker:
build: ./worker
environment:
- ZORROBPM_API_URL=${ZORROBPM_API_URL}
- RABBITMQ_HOST=${RABBITMQ_HOST}
- RABBITMQ_PORT=${RABBITMQ_PORT:-5672}
- RABBITMQ_USERNAME=${RABBITMQ_USER}
- RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}
depends_on:
- ui
```
`.env.workers`:
```env
ZORROBPM_API_URL=https://api.m11s.zorrobpm.dev
# RabbitMQ — указать хост удалённого брокера, если он открыт,
# или поднять локально (добавить rabbitmq сервис)
RABBITMQ_HOST=rabbitmq.m11s.zorrobpm.dev
RABBITMQ_USER=guest
RABBITMQ_PASSWORD=guest
```
> **Примечание:** если удалённый RabbitMQ недоступен извне, добавь сервис `rabbitmq` из полного стека и настрой API на использование этого брокера.
---
## API Reference
Base URL: `http://localhost:9092` (local) или `https://api.m11s.zorrobpm.dev` (demo)
### Process Definitions
| Метод | Endpoint | Описание |
|-------|----------|----------|
| `POST` | `/process-definitions` | Деплой BPMN |
| `GET` | `/process-definitions` | Список (с пагинацией) |
| `GET` | `/process-definitions/{id}` | По ID |
| `GET` | `/process-definitions/{id}/xml` | BPMN XML |
**Деплой:**
```http
POST /process-definitions
Content-Type: application/json
{ "bpmn": "<bpmn:definitions>...</bpmn:definitions>" }
```
Ответ — `ProcessDefinition`:
```json
{
"id": "uuid",
"key": "string",
"version": 1,
"name": "string",
"sha256": "string",
"createdAt": "date-time",
"startFormKey": "string"
}
```
Query params: `pageIndex`, `pageSize`, `processDefinitionKey`, `processDefinitionVersion`, `latestVersionOnly`
---
### Process Instances
| Метод | Endpoint | Описание |
|-------|----------|----------|
| `POST` | `/process-instances` | Запуск инстанса |
| `GET` | `/process-instances` | Список (с пагинацией) |
**Запуск:**
```http
POST /process-instances
Content-Type: application/json
{
"processDefinitionId": "uuid",
"processDefinitionKey": "string",
"processDefinitionVersion": 1,
"variables": [
{ "name": "var1", "value": "val1", "type": "STRING" }
]
}
```
Можно указать `processDefinitionId` ИЛИ `processDefinitionKey` + `processDefinitionVersion`.
Ответ: `{ "id": "uuid" }`
Query params: `id`, `pageIndex`, `pageSize`, `processDefinitionId`, `processDefinitionKey`, `processDefinitionVersion`
Объект `ProcessInstance`:
```json
{
"id": "uuid",
"parentActivityId": "uuid",
"processDefinitionId": "uuid",
"startedAt": "date-time",
"completedAt": "date-time"
}
```
---
### Service Tasks
| Метод | Endpoint | Описание |
|-------|----------|----------|
| `GET` | `/service-tasks` | Список сервисных задач |
| `POST` | `/service-tasks/{id}/complete` | Завершить задачу |
Query params: `id`, `jobType`, `completed`, `pageIndex`, `pageSize`, `processInstanceId`
Объект `ServiceTask`:
```json
{
"id": "uuid",
"code": "string",
"name": "string",
"processInstanceId": "uuid",
"processDefinitionId": "uuid",
"job": "string",
"createdAt": "date-time",
"completedAt": "date-time"
}
```
**Завершение:**
```http
POST /service-tasks/{id}/complete
Content-Type: application/json
{
"variables": [
{ "name": "result", "value": "done", "type": "STRING" }
]
}
```
---
### User Tasks
| Метод | Endpoint | Описание |
|-------|----------|----------|
| `GET` | `/user-tasks` | Список пользовательских задач |
| `POST` | `/user-tasks/{id}/complete` | Завершить задачу |
Query params: `id`, `assignee`, `candidateGroup`, `candidateUser`, `completed`, `assigned`, `pageIndex`, `pageSize`, `processInstanceId`
Объект `UserTask`:
```json
{
"id": "uuid",
"code": "string",
"name": "string",
"processInstanceId": "uuid",
"processDefinitionId": "uuid",
"formKey": "string",
"createdAt": "date-time",
"completedAt": "date-time"
}
```
**Завершение:**
```http
POST /user-tasks/{id}/complete
Content-Type: application/json
{
"variables": [
{ "name": "action", "value": "approve", "type": "STRING" }
]
}
```
---
### Incidents
| Метод | Endpoint | Описание |
|-------|----------|----------|
| `GET` | `/incidents` | Список инцидентов |
| `POST` | `/incidents/{id}/resolve` | Разрешить инцидент |
Query params: `id`, `processInstanceId`, `processDefinitionId`, `processDefinitionKey`, `processDefinitionVersion`, `bpmnElementId`, `pageIndex`, `pageSize`
Объект `Incident`:
```json
{
"id": "uuid",
"activityId": "uuid",
"message": "string",
"createdAt": "date-time",
"completedAt": "date-time"
}
```
**Разрешение:**
```http
POST /incidents/{id}/resolve
Content-Type: application/json
{
"id": "uuid",
"variables": [
{ "name": "fix", "value": "retried", "type": "STRING" }
]
}
```
---
### Типы переменных
`STRING`, `UUID`, `LONG`, `BOOLEAN`
### Формат пагинации
Все list-эндпоинты возвращают:
```json
{
"pageIndex": 0,
"pageSize": 20,
"totalElements": 100,
"data": [...]
}
```
---
## RabbitMQ и внешние воркеры
### Очереди
| Очередь | Описание |
|---------|----------|
| `zorrobpm.engine.definition-events` | Жизненный цикл определений (deployed, updated) |
| `zorrobpm.engine.runtime-events` | Жизненный цикл инстансов (created, completed) и задач |
| `zorrobpm.jobs.<job_type>` | Очередь для каждого типа serviceTask |
### Как это работает
Когда BPMN `serviceTask` с атрибутом `job="srv_child_work"` достигается движком:
1. Движок публикует сообщение в очередь `zorrobpm.jobs.srv_child_work`
2. Внешний воркер читает из этой очереди
3. Воркер выполняет работу
4. Воркер вызывает `POST /service-tasks/{id}/complete`
### Пример воркера (Java + Spring AMQP)
```java
@RabbitListener(queues = "zorrobpm.jobs.srv_child_work")
public void handleChildWork(ServiceTaskMessage msg) {
// выполнить работу...
api.completeServiceTask(msg.getTaskId());
}
```
### Инспекция очередей
```bash
docker exec zorrobpm-rabbitmq-1 rabbitmqctl list_queues name messages consumers
```
---
## Разработка процессов
### Быстрый старт
1. **Нарисуй BPMN** — в Studio (https://studio.zorrobpm.dev) или любом BPMN-редакторе
2. **Деплой** — `POST /process-definitions` с BPMN XML
3. **Запусти** — `POST /process-instances` с ключом или ID определения
4. **Обрабатывай задачи**:
- `serviceTask` — воркер через RabbitMQ или ручной `POST /service-tasks/{id}/complete`
- `userTask` — UI или ручной `POST /user-tasks/{id}/complete`
### Выбор docker-compose
```
Нужен ли локальный BPM движок?
├── Да → docker-compose.yaml (полный стек)
└── Нет, использую удалённый API
├── Есть serviceTask с воркерами? → docker-compose.workers.yaml
└── Только UI/мониторинг? → docker-compose.front.yaml
```
### Структура проекта (рекомендуемая)
```
my-process/
├── docker-compose.yaml # выбери нужный вариант
├── .env
├── bpmn/
│ ├── myProcess.bpmn
│ └── childProcess.bpmn
├── worker/ # если есть serviceTask
│ ├── Dockerfile
│ └── src/
└── tests/
└── e2e/
```
---
## Тестирование
### Dev-контейнер
```yaml
# docker-compose.dev.yaml
services:
app:
image: maven:3.9-eclipse-temurin-17
container_name: examples-dev
working_dir: /app
volumes:
- .:/app
- maven-cache:/root/.m2
ports:
- "8080:8080"
- "5005:5005" # remote debug
command: sleep infinity
volumes:
maven-cache:
```
### Режимы тестирования
| Режим | Команда | Зависимости | Описание |
|-------|---------|-------------|----------|
| **embedded** | `./test.sh` | Только dev контейнер | Unit тесты, встроенный движок + H2 |
| **local** | `./test.sh local` | Dev + ZorroBPM docker | E2E против `localhost:9092` |
| **remote** | `./test.sh remote` | Dev + интернет | E2E против `api.m11s.zorrobpm.dev` |
| **custom** | `./test.sh http://my-server:8080` | Dev + сервер | E2E против произвольного URL |
```bash
docker compose -f docker-compose.dev.yaml up -d
./test.sh # embedded
./test.sh local # E2E local
./test.sh remote # E2E remote
```
---
## Примеры
### call-activity — вызов дочернего процесса
**Родительский процесс** (`parentProcess.bpmn`):
```
[Start] → [CallActivity: childProcess] → [End]
```
**Дочерний процесс** (`childProcess.bpmn`):
```
[Start] → [ServiceTask: srv_child_work] → [End]
```
**Поток выполнения:**
1. Деплой обоих BPMN
2. Запуск родительского — он входит в `callActivity`, создаёт дочерний инстанс
3. Дочерний работает в **отдельном processInstance**
4. Завершение serviceTask в дочернем → callActivity возобновляется → родитель завершается
**Файлы:**
```
src/main/resources/examples/call-activity/
parentProcess.bpmn
childProcess.bpmn
src/test/java/.../examples/callactivity/
CallActivityTest.java # unit (embedded)
src/test/java/.../e2e/
CallActivityE2ETest.java # E2E
ZorroWebAPI.java # HTTP клиент
```
---
## Известные ограничения
### Нет parentProcessInstanceId
API не поддерживает фильтр `parentProcessInstanceId` в `ProcessInstance`. Поле `parentActivityId` — это UUID активити (callActivity элемента), а не ID родительского инстанса.
**Нельзя напрямую запросить:** "дай все дочерние процессы родителя X".
**Workaround:** найти последний инстанс с `parentActivityId != null` на последней странице. Работает для последовательных тестов, ненадёжно при параллельных.
**Желаемое улучшение API:**
```
GET /process-instances?parentProcessInstanceId={uuid}
```
Плюс добавить поле `parentProcessInstanceId` в объект `ProcessInstance`.