API Reference
Полный справочник по REST API EFKO Kernel с примерами запросов и ответов.
Общие принципы
Base URL
Все эндпоинты доступны относительно этого базового URL.
Формат данных
- Request Format: JSON (
Content-Type: application/json) - Response Format: JSON
- Date Format: ISO 8601 (
YYYY-MM-DDилиYYYY-MM-DDTHH:mm:ss.sssZ) - UUID Format: Стандартный UUID v4
Аутентификация
Система использует JWT токены:
- Access Token: Короткоживущий токен для аутентификации запросов
- Refresh Token: Долгоживущий токен для обновления сессии
Access токен передается в заголовке:
CSRF Защита
Для браузерных клиентов:
- После логина устанавливается cookie XSRF-TOKEN
- Браузер должен читать эту cookie и передавать её значение в заголовке X-CSRF-Token при каждом мутирующем запросе (POST, PATCH, DELETE)
- GET, HEAD, OPTIONS запросы CSRF не проверяются
Для мобильных клиентов: - CSRF проверка автоматически пропускается (нет cookie механизма) - Refresh токен передается в теле запроса при обновлении сессии
Rate Limiting
Три профиля лимитов применяются глобально:
| Профиль | Лимит |
|---|---|
| short | 20 req / 1 s |
| medium | 100 req / 10 s |
| long | 500 req / 60 s |
Auth endpoints (/auth/register, /auth/login) имеют более строгие отдельные лимиты.
Корреляция запросов
Каждый запрос имеет requestId для трассировки:
- Автоматически генерируется через RequestIdMiddleware
- Может быть передан вручную через заголовок x-request-id
- Пропагируется через все сервисы
Обработка ошибок
Стандартная структура ошибки
HTTP коды ошибок
| Код | Описание |
|---|---|
400 |
Ошибка валидации |
401 |
Не авторизован / невалидный токен |
403 |
Недостаточно прав |
404 |
Ресурс не найден |
409 |
Конфликт (дубликат, недопустимый переход) |
429 |
Rate limit превышен |
503 |
Downstream сервис недоступен |
504 |
Downstream сервис не ответил вовремя (timeout) |
Auth API
Эндпоинты аутентификации и управления пользователями.
POST /auth/register
Регистрация нового пользователя.
Аутентификация: Не требуется
CSRF: Требуется для браузера
Rate Limit: Отдельный строгий лимит
Request Body
{
email: string; // Email пользователя
password: string; // Пароль (минимум 8 символов)
fullName: string; // Полное имя (формат: Фамилия Имя Отчество)
role?: UserRole; // Роль (опционально, по умолчанию EMPLOYEE)
employeeId?: string; // UUID сотрудника (опционально)
}
Response
{
id: string; // UUID пользователя
email: string; // Email
fullName: string; // Полное имя
role: UserRole; // Роль
isActive: boolean; // Статус активности
employeeId: string | null; // ID сотрудника (если привязан)
}
Пример запроса
curl -X POST http://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "ivan@example.com",
"password": "SecurePass123!",
"fullName": "Иванов Иван Иванович",
"role": "admin"
}'
Пример ответа
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"email": "ivan@example.com",
"fullName": "Иванов Иван",
"role": "admin",
"isActive": true,
"employeeId": null
}
Ошибки
400— Некорректный формат email или имени409— Email уже занят (USER_ALREADY_EXISTS)
POST /auth/login
Вход в систему.
Аутентификация: Не требуется
CSRF: Требуется для браузера
Rate Limit: Отдельный строгий лимит
Request Body
Response
Cookies
Устанавливаются в ответе:
- refreshToken — httpOnly cookie для обновления сессии
- XSRF-TOKEN — читаемый JS cookie с CSRF токеном
Пример запроса
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "ivan@example.com",
"password": "SecurePass123!"
}' \
-c cookies.txt
Пример ответа
{
"accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Ошибки
400— Некорректный формат401— Невалидные учетные данные или аккаунт деактивирован (INVALID_CREDENTIALS)
GET /auth/me
Получить профиль текущего пользователя.
Аутентификация: Bearer accessToken
CSRF: Не требуется
Response
{
id: string;
email: string;
fullName: string;
role: UserRole;
isActive: boolean;
employeeId: string | null;
}
Пример запроса
Пример ответа
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"email": "ivan@example.com",
"fullName": "Иванов Иван",
"role": "admin",
"isActive": true,
"employeeId": "d4e5f6a7-b8c9-0123-defa-234567890123"
}
Ошибки
401— Токен недействителен или истек404— Пользователь не найден или деактивирован (USER_NOT_FOUND)
POST /auth/refresh-session
Обновить сессию по refresh токену.
Аутентификация: Refresh токен из httpOnly cookie refreshToken
CSRF: Требуется для браузера (значение cookie XSRF-TOKEN в заголовке X-CSRF-Token)
Endpoint читает refresh токен исключительно из httpOnly cookie. Клиенты без поддержки cookie (например, мобильные без WebView) не могут использовать этот endpoint в текущей реализации.
Response
Cookies
Обновляются в ответе:
- refreshToken — новый refresh токен (rotation)
- XSRF-TOKEN — новый CSRF токен
Пример запроса
curl -X POST http://localhost:3000/api/auth/refresh-session \
-H "X-CSRF-Token: <value from XSRF-TOKEN cookie>" \
-b cookies.txt \
-c cookies.txt
Пример ответа
{
"accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Ошибки
401— Refresh токен отсутствует, отозван (REFRESH_TOKEN_REVOKED), истек (REFRESH_TOKEN_EXPIRED)
POST /auth/logout
Завершение сессии.
Аутентификация: Bearer accessToken
CSRF: Требуется для браузера
Response
Cookies
Очищаются:
- refreshToken
- XSRF-TOKEN
Пример запроса
curl -X POST http://localhost:3000/api/auth/logout \
-H "Authorization: Bearer <accessToken>" \
-H "X-CSRF-Token: <value from XSRF-TOKEN cookie>" \
-b cookies.txt \
-c cookies.txt
Пример ответа
GET /users
Список всех пользователей.
Аутентификация: Bearer accessToken
Роль: Требуется аутентификация; ограничение по роли ADMIN в текущем коде закомментировано
CSRF: Не требуется
Response
{
users: Array<{
id: string;
email: string;
fullName: string;
role: UserRole;
isActive: boolean;
employeeId: string | null;
}>;
}
Пример запроса
Ошибки
403— Недостаточно прав
PATCH /users/:userId
Обновить данные пользователя.
Аутентификация: Bearer accessToken
Роль: ADMIN (требуется)
CSRF: Требуется для браузера
Request Body
Response
{
id: string;
email: string;
fullName: string;
role: UserRole;
isActive: boolean;
employeeId: string | null;
}
Пример запроса
curl -X PATCH http://localhost:3000/api/users/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"fullName": "Иванов Иван Петрович"
}'
Ошибки
403— Недостаточно прав404— Пользователь не найден
POST /users/deactivate
Деактивировать пользователя.
Аутентификация: Bearer accessToken
Роль: ADMIN (требуется)
CSRF: Требуется для браузера
Request Body
Response
Пример запроса
curl -X POST http://localhost:3000/api/users/deactivate \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"userId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}'
Personnel API
Управление кадровыми данными: подразделения, должности, сотрудники, шаблоны смен.
POST /personnel/departments
Создать подразделение.
Аутентификация: Bearer accessToken
Роли: ADMIN, MANAGER
CSRF: Требуется для браузера
Request Body
{
name: string;
code: string;
type: DepartmentType;
parentId?: string | null;
headEmployeeId?: string | null;
}
Response
{
id: string;
name: string;
code: string;
type: DepartmentType;
parentId: string | null;
headEmployeeId: string | null;
sourceSystemId: string | null;
}
Пример запроса
curl -X POST http://localhost:3000/api/personnel/departments \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"name": "Производственный цех №1",
"code": "PROD-001",
"type": "division"
}'
Ошибки
400— Ошибка валидации409— Код уже занят (DEPARTMENT_CODE_ALREADY_EXISTS)
GET /personnel/departments
Список подразделений.
Аутентификация: Bearer accessToken
Роли: ADMIN, MANAGER, SHIFT_MANAGER, ANALYST
CSRF: Не требуется
Query Parameters
type?— Тип подразделенияcode?— Код подразделения
Response
{
departments: Array<{
id: string;
name: string;
code: string;
type: DepartmentType;
parentId: string | null;
headEmployeeId: string | null;
sourceSystemId: string | null;
}>;
}
Пример запроса
curl -X GET "http://localhost:3000/api/personnel/departments?type=DIVISION" \
-H "Authorization: Bearer <accessToken>"
PATCH /personnel/departments/:id
Обновить подразделение.
Аутентификация: Bearer accessToken
Роли: ADMIN, MANAGER
CSRF: Требуется для браузера
Request Body
Response
{
id: string;
name: string;
code: string;
type: DepartmentType;
parentId: string | null;
headEmployeeId: string | null;
}
Пример запроса
curl -X PATCH http://localhost:3000/api/personnel/departments/<id> \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"headEmployeeId": "d4e5f6a7-b8c9-0123-defa-234567890123"
}'
POST /personnel/positions
Создать должность.
Аутентификация: Bearer accessToken
Роли: ADMIN, MANAGER
CSRF: Требуется для браузера
Request Body
Response
Пример запроса
curl -X POST http://localhost:3000/api/personnel/positions \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"title": "Оператор станка",
"code": "OP-001",
"departmentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}'
Ошибки
404— Подразделение не найдено (DEPARTMENT_NOT_FOUND)409— Код должности уже занят (POSITION_CODE_ALREADY_EXISTS)
GET /personnel/positions
Список должностей.
Аутентификация: Bearer accessToken
Роли: ADMIN, MANAGER, SHIFT_MANAGER, ANALYST
CSRF: Не требуется
Query Parameters
departmentId?— UUID подразделения
Response
PATCH /personnel/positions/:id
Обновить должность.
Аутентификация: Bearer accessToken
Роли: ADMIN, MANAGER
CSRF: Требуется для браузера
Request Body
Response
POST /personnel/employees
Создать сотрудника.
Аутентификация: Bearer accessToken
Роли: ADMIN, MANAGER
CSRF: Требуется для браузера
Request Body
{
personnelNumber: string;
fullName: string;
dateOfBirth: string; // ISO date
departmentId: string;
positionId: string;
hireDate: string; // ISO date
employmentType: EmploymentType;
sourceSystemId?: string | null;
}
Response
{
id: string;
personnelNumber: string;
fullName: string;
departmentId: string;
positionId: string;
status: EmployeeStatus;
}
Пример запроса
curl -X POST http://localhost:3000/api/personnel/employees \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"personnelNumber": "EMP-0001",
"fullName": "Иванов Иван Иванович",
"dateOfBirth": "1985-05-15",
"departmentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"positionId": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"hireDate": "2025-01-01",
"employmentType": "main"
}'
Ошибки
400— Некорректное имя (INVALID_FULL_NAME)404— Подразделение или должность не найдены
GET /personnel/employees
Список сотрудников.
Аутентификация: Bearer accessToken
Роли: ADMIN, MANAGER, SHIFT_MANAGER, ANALYST
CSRF: Не требуется
Query Parameters
departmentId?— UUID подразделенияpositionId?— UUID должностиstatus?— Статус (ACTIVE, TERMINATED, ON_LEAVE)employmentType?— Тип занятости
Response
{
employees: Array<{
id: string;
personnelNumber: string;
fullName: string;
status: EmployeeStatus;
employmentType: EmploymentType;
departmentId: string;
positionId: string;
hireDate: string;
dateOfBirth: string;
terminationDate: string | null;
}>;
}
PATCH /personnel/employees/:id
Обновить данные сотрудника.
Аутентификация: Bearer accessToken
Роли: ADMIN, MANAGER
CSRF: Требуется для браузера
Request Body
{
fullName?: string;
departmentId?: string;
positionId?: string;
employmentType?: EmploymentType;
dateOfBirth?: string; // ISO date
}
Response
{
id: string;
personnelNumber: string;
fullName: string;
dateOfBirth: string;
departmentId: string;
positionId: string;
hireDate: string;
terminationDate: string | null;
employmentType: EmploymentType;
status: EmployeeStatus;
sourceSystemId: string | null;
}
POST /personnel/employees/:id/terminate
Уволить сотрудника.
Аутентификация: Bearer accessToken
Роли: ADMIN, MANAGER
CSRF: Требуется для браузера
Request Body
Response
Пример запроса
curl -X POST http://localhost:3000/api/personnel/employees/<id>/terminate \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"terminationDate": "2025-06-30"
}'
Ошибки
409— Сотрудник уже уволен (EMPLOYEE_ALREADY_TERMINATED)
POST /personnel/shift-templates
Создать шаблон смены.
Аутентификация: Bearer accessToken
Роли: ADMIN, MANAGER, SHIFT_MANAGER
CSRF: Требуется для браузера
Request Body
{
name: string;
shiftType: ShiftType;
startTime: string; // HH:MM
endTime: string; // HH:MM
workDaysPattern: string; // Бинарная строка, например "1111100"
}
Response
{
id: string;
name: string;
shiftType: ShiftType;
startTime: string;
endTime: string;
workDaysPattern: string;
}
Пример запроса
curl -X POST http://localhost:3000/api/personnel/shift-templates \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"name": "Дневная смена",
"shiftType": "day_shift",
"startTime": "08:00",
"endTime": "20:00",
"workDaysPattern": "1111100"
}'
GET /personnel/shift-templates
Список шаблонов смен.
Аутентификация: Bearer accessToken
Роли: ADMIN, MANAGER, SHIFT_MANAGER, ANALYST
CSRF: Не требуется
Response
{
templates: Array<{
id: string;
name: string;
shiftType: ShiftType;
startTime: string;
endTime: string;
workDaysPattern: string;
}>;
}
PATCH /personnel/shift-templates/:id
Обновить шаблон смены.
Аутентификация: Bearer accessToken
Роли: ADMIN, MANAGER, SHIFT_MANAGER
CSRF: Требуется для браузера
Request Body
{
name?: string;
shiftType?: ShiftType;
startTime?: string;
endTime?: string;
workDaysPattern?: string;
}
Response
{
id: string;
name: string;
shiftType: ShiftType;
startTime: string;
endTime: string;
workDaysPattern: string;
}
Production API
Управление производственными данными: продукты, заказы, выпуск, качество, датчики, KPI.
POST /production/products
Создать продукт.
Аутентификация: Bearer accessToken
CSRF: Требуется для браузера
Request Body
{
code: string;
name: string;
category: ProductCategory;
brand?: string;
unitOfMeasure: string;
shelfLifeDays?: number;
requiresQualityCheck?: boolean;
}
Response
Пример запроса
curl -X POST http://localhost:3000/api/production/products \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"code": "PROD-001",
"name": "Творог 5%",
"category": "finished_product",
"brand": "Домик в деревне",
"unitOfMeasure": "kg",
"shelfLifeDays": 30,
"requiresQualityCheck": true
}'
Ошибки
409— Код продукта уже занят (PRODUCT_CODE_ALREADY_EXISTS)
GET /production/products
Список продуктов.
Аутентификация: Bearer accessToken
CSRF: Не требуется
Query Parameters
category?— Категория продуктаbrand?— Бренд
Response
{
products: Array<{
id: string;
code: string;
name: string;
category: ProductCategory;
brand: string | null;
unitOfMeasure: string;
shelfLifeDays: number | null;
requiresQualityCheck: boolean;
}>;
}
POST /production/orders
Создать производственный заказ.
Аутентификация: Bearer accessToken
CSRF: Требуется для браузера
Request Body
{
externalOrderId?: string;
productId: string;
targetQuantity: number;
unitOfMeasure: string;
productionLine: string;
plannedStart: string; // ISO datetime
plannedEnd: string; // ISO datetime
}
Response
Пример запроса
curl -X POST http://localhost:3000/api/production/orders \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"externalOrderId": "EXT-ORDER-001",
"productId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"targetQuantity": 1000,
"unitOfMeasure": "kg",
"productionLine": "Line-1",
"plannedStart": "2025-01-01T06:00:00Z",
"plannedEnd": "2025-01-10T18:00:00Z"
}'
Ошибки
404— Продукт не найден (PRODUCT_NOT_FOUND)
GET /production/orders
Список заказов.
Аутентификация: Bearer accessToken
CSRF: Не требуется
Query Parameters
status?— Статус заказаproductId?— UUID продуктаproductionLine?— Производственная линияfrom?— Начало периода (ISO date)to?— Конец периода (ISO date)
Response
{
orders: Array<{
id: string;
externalOrderId: string | null;
productId: string;
targetQuantity: number;
actualQuantity: number | null;
unitOfMeasure: string;
status: OrderStatus;
productionLine: string;
plannedStart: string;
plannedEnd: string;
actualStart: string | null;
actualEnd: string | null;
}>;
}
GET /production/orders/:id
Заказ по ID с выпусками.
Аутентификация: Bearer accessToken
CSRF: Не требуется
Response
{
id: string;
externalOrderId: string | null;
productId: string;
targetQuantity: number;
actualQuantity: number | null;
unitOfMeasure: string;
status: OrderStatus;
productionLine: string;
plannedStart: string;
plannedEnd: string;
actualStart: string | null;
actualEnd: string | null;
outputs: Array<{
id: string;
orderId: string;
productId: string;
lotNumber: string;
quantity: number;
qualityStatus: QualityStatus;
productionDate: string;
shift: string;
}>;
}
PATCH /production/orders/:id/status
Обновить статус заказа.
Аутентификация: Bearer accessToken
CSRF: Требуется для браузера
Request Body
Response
{
id: string;
status: OrderStatus;
actualQuantity: number | null;
actualStart: string | null;
actualEnd: string | null;
}
Пример запроса
curl -X PATCH http://localhost:3000/api/production/orders/<id>/status \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"action": "start"
}'
Ошибки
409— Недопустимый переход статуса (INVALID_ORDER_STATUS_TRANSITION)
POST /production/output
Зарегистрировать выпуск продукции.
Аутентификация: Bearer accessToken
CSRF: Требуется для браузера
Request Body
Response
Пример запроса
curl -X POST http://localhost:3000/api/production/output \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"orderId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"productId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"lotNumber": "LOT-2025-001",
"quantity": 500,
"shift": "morning"
}'
GET /production/output
Список выпусков.
Аутентификация: Bearer accessToken
CSRF: Не требуется
Query Parameters
orderId?— UUID заказаproductId?— UUID продуктаlotNumber?— Номер партииfrom?— Дата производства отto?— Дата производства до
Response
{
outputs: Array<{
id: string;
orderId: string;
productId: string;
lotNumber: string;
quantity: number;
qualityStatus: QualityStatus;
productionDate: string;
shift: string;
}>;
}
POST /production/sales
Зарегистрировать продажу.
Аутентификация: Bearer accessToken
CSRF: Требуется для браузера
Request Body
{
externalId: string;
productId: string;
customerName: string;
quantity: number;
amount: number;
saleDate: string; // ISO date
region: string;
channel: SaleChannel;
}
Response
Пример запроса
curl -X POST http://localhost:3000/api/production/sales \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"externalId": "SALE-001",
"productId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customerName": "ООО Ромашка",
"quantity": 100,
"amount": 50000,
"saleDate": "2025-02-01",
"region": "Краснодарский край",
"channel": "retail"
}'
GET /production/sales
Список продаж.
Аутентификация: Bearer accessToken
CSRF: Не требуется
Query Parameters
productId?— UUID продуктаregion?— Регионchannel?— Канал продажfrom?— Дата продажи отto?— Дата продажи до
Response
{
sales: Array<{
id: string;
externalId: string;
productId: string;
customerName: string;
quantity: number;
amount: number;
saleDate: string;
region: string;
channel: SaleChannel;
}>;
}
GET /production/sales/summary
Сводка продаж.
Аутентификация: Bearer accessToken
CSRF: Не требуется
Query Parameters
from?— Начало периодаto?— Конец периодаgroupBy?— Ось группировки (region | channel | product)
Response
{
summary: Array<{
groupKey: string;
totalQuantity: number;
totalAmount: number;
salesCount: number;
}>;
totalAmount: number;
totalQuantity: number;
}
POST /production/inventory
Обновить/создать остаток на складе.
Аутентификация: Bearer accessToken
CSRF: Требуется для браузера
Request Body
{
productId: string;
warehouseCode: string;
lotNumber?: string;
quantity: number;
unitOfMeasure: string;
}
Response
Пример запроса
curl -X POST http://localhost:3000/api/production/inventory \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"productId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"warehouseCode": "WH-01",
"lotNumber": "LOT-2025-001",
"quantity": 200,
"unitOfMeasure": "kg"
}'
GET /production/inventory
Остатки на складах.
Аутентификация: Bearer accessToken
CSRF: Не требуется
Query Parameters
productId?— UUID продуктаwarehouseCode?— Код склада
Response
{
inventory: Array<{
id: string;
productId: string;
warehouseCode: string;
lotNumber: string | null;
quantity: number;
unitOfMeasure: string;
lastUpdated: string;
}>;
}
POST /production/quality
Зарегистрировать результат контроля качества.
Аутентификация: Bearer accessToken
CSRF: Требуется для браузера
Request Body
{
lotNumber: string;
productId: string;
parameterName: string;
resultValue: number;
lowerLimit: number;
upperLimit: number;
testDate: string; // ISO date
}
Response
Пример запроса
curl -X POST http://localhost:3000/api/production/quality \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"lotNumber": "LOT-2025-001",
"productId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"parameterName": "moisture",
"resultValue": 12.5,
"lowerLimit": 10.0,
"upperLimit": 14.0,
"testDate": "2025-01-06"
}'
GET /production/quality
Результаты контроля качества.
Аутентификация: Bearer accessToken
CSRF: Не требуется
Query Parameters
productId?— UUID продуктаlotNumber?— Номер партииdecision?— РешениеinSpec?— Только в норме
Response
{
results: Array<{
id: string;
lotNumber: string;
productId: string;
parameterName: string;
resultValue: number;
lowerLimit: number;
upperLimit: number;
inSpec: boolean;
decision: QualityDecision;
testDate: string;
}>;
}
POST /production/sensors
Записать показание датчика.
Аутентификация: Bearer accessToken
CSRF: Требуется для браузера
Request Body
{
deviceId: string;
productionLine: string;
parameterName: string;
value: number;
unit: string;
quality: SensorQuality;
}
Response
{
id: string;
deviceId: string;
productionLine: string;
parameterName: string;
quality: SensorQuality;
}
Пример запроса
curl -X POST http://localhost:3000/api/production/sensors \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"deviceId": "SENSOR-01",
"productionLine": "Line-1",
"parameterName": "temperature",
"value": 72.5,
"unit": "°C",
"quality": "good"
}'
GET /production/sensors
Показания датчиков.
Аутентификация: Bearer accessToken
CSRF: Не требуется
Query Parameters
productionLine?— Производственная линияparameterName?— Название параметраquality?— Качество сигналаfrom?— Начало диапазона (ISO datetime)to?— Конец диапазона (ISO datetime)
Response
{
readings: Array<{
id: string;
deviceId: string;
productionLine: string;
parameterName: string;
value: number;
unit: string;
quality: SensorQuality;
recordedAt: string;
}>;
}
GET /production/kpi
KPI производства.
Аутентификация: Bearer accessToken
CSRF: Не требуется
Query Parameters
from?— Начало периодаto?— Конец периодаproductionLine?— Производственная линия
Response
{
totalOutput: number;
defectRate: number;
completedOrders: number;
totalOrders: number;
oeeEstimate: number;
}
Пример запроса
curl -X GET "http://localhost:3000/api/production/kpi?from=2025-01-01&to=2025-12-31" \
-H "Authorization: Bearer <accessToken>"
ETL API
Интеграция с внешними системами (1C-ZUP, 1C-ERP, MES, SCADA, LIMS).
POST /etl/import
Загрузить пакет данных (JSON body).
Аутентификация: Bearer accessToken
Роль: ADMIN (требуется)
CSRF: Требуется для браузера
Request Body
{
source_system: SourceSystem; // '1c_zup' | '1c_erp' | 'mes' | 'scada' | 'lims'
import_type: ImportType; // 'employees' | 'departments' | 'positions' | 'products' | 'orders' | 'sensors' | 'quality'
data: Array<Record<string, any>>;
}
Response
{
import_id: string; // MongoDB ObjectId операции импорта
status: ImportStatus; // 'pending' | 'processing' | 'completed' | 'failed'
records_count: number;
source_file_id?: string; // ID файла в GridFS (только при file upload)
warnings?: string[]; // Предупреждения парсера
parse_errors?: Array<{ index: number; field: string; message: string }>; // Ошибки валидации
}
Пример запроса
curl -X POST http://localhost:3000/api/etl/import \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <value>" \
-d '{
"source_system": "1c_zup",
"import_type": "employees",
"data": [
{
"ТабельныйНомер": "EMP-0001",
"ФИО": "Иванов Иван Иванович",
"ДатаРождения": "1985-05-15"
}
]
}'
POST /etl/import/file
Загрузить файл (xlsx/json).
Аутентификация: Bearer accessToken
Роль: ADMIN (требуется)
CSRF: Требуется для браузера
Max file size: 20 MB
Request Body (multipart/form-data)
Response
{
import_id: string; // MongoDB ObjectId операции импорта
status: 'processing';
records_count: number;
source_file_id?: string; // ID файла в GridFS
format?: 'xlsx' | 'json';
warnings?: string[];
parse_errors?: Array<{ index: number; field: string; message: string }>;
}
Пример запроса
curl -X POST http://localhost:3000/api/etl/import/file \
-H "Authorization: Bearer <accessToken>" \
-H "X-CSRF-Token: <value>" \
-F "file=@data.xlsx" \
-F "source_system=1c_zup" \
-F "import_type=employees"
Ошибки
400— Неподдерживаемый формат файла или превышен размер
GET /etl/imports
Список импортов.
Аутентификация: Bearer accessToken
Роль: ADMIN (требуется)
CSRF: Не требуется
Query Parameters
source_system?— Источник:1c_zup|1c_erp|mes|scada|limsstatus?— Статус:pending|processing|completed|failedlimit?— Количество записей (1–500, по умолчанию 20)
Response
Array<{
import_id: string; // MongoDB ObjectId
source_system: SourceSystem;
import_type: ImportType;
status: ImportStatus;
records_count: number;
source_file_id?: string; // ID файла в GridFS (если был file upload)
source_file_format?: 'xlsx' | 'json';
created_at: string; // ISO datetime
processed_at: string | null;
}>
GET /etl/imports/:id
Детали импорта.
Аутентификация: Bearer accessToken
Роль: ADMIN (требуется)
CSRF: Не требуется
Response
{
import_id: string;
source_system: SourceSystem;
import_type: ImportType;
status: ImportStatus;
records_count: number;
source_file_id?: string;
source_file_format?: 'xlsx' | 'json';
created_at: string;
processed_at: string | null;
stats: {
total: number;
success: number;
error: number;
skipped: number;
};
errors: Array<{ field: string; message: string; record_index?: number }>;
}
Ошибки
404— Импорт не найден
GET /etl/imports/:id/file
Скачать исходный файл импорта.
Аутентификация: Bearer accessToken
Роль: ADMIN (требуется)
CSRF: Не требуется
Response
Бинарный поток файла (application/octet-stream или исходный MIME)
Ошибки
404— Импорт или файл не найден
POST /etl/imports/:id/retry
Повторить импорт.
Аутентификация: Bearer accessToken
Роль: ADMIN (требуется)
CSRF: Требуется для браузера
Response
Пример запроса
curl -X POST http://localhost:3000/api/etl/imports/<id>/retry \
-H "Authorization: Bearer <accessToken>" \
-H "X-CSRF-Token: <value>"
Ошибки
400— Импорт не может быть повторен (не в статусе failed)404— Импорт не найден
Enum значения
UserRole
ADMIN— АдминистраторMANAGER— МенеджерSHIFT_MANAGER— Менеджер сменыANALYST— АналитикEMPLOYEE— Сотрудник
DepartmentType
DIVISION— ДивизионDEPARTMENT— ОтделSECTION— СекцияUNIT— Юнит
EmploymentType
MAIN— ОсновнойPART_TIME— Неполный
EmployeeStatus
ACTIVE— АктивенTERMINATED— УволенON_LEAVE— В отпуске
ShiftType
DAY_SHIFT— Дневная сменаNIGHT_SHIFT— Ночная сменаROTATING— Ротирующаяся
ProductCategory
RAW_MATERIAL— СырьеSEMI_FINISHED— ПолуфабрикатFINISHED_PRODUCT— Готовая продукцияPACKAGING— Упаковка
OrderStatus
PLANNED— ЗапланированIN_PROGRESS— В работеCOMPLETED— ЗавершенCANCELLED— Отменен
QualityStatus
PENDING— ОжидаетAPPROVED— ОдобреноREJECTED— Отклонено
QualityDecision
APPROVED— ОдобреноREJECTED— ОтклоненоPENDING— Ожидает
SaleChannel
RETAIL— РозницаWHOLESALE— ОптHORECA— HoReCaEXPORT— Экспорт
SensorQuality
GOOD— ХорошееDEGRADED— УхудшенноеBAD— Плохое