Files
logiflow/internal/api/api.swagger.yaml

1443 lines
40 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
openapi: 3.0.3
info:
title: Logiflow API
description: API для логистической информационной системы
version: 0.2.0
contact:
name: anxi0uz
servers:
- url: http://localhost:3001
description: Local development
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
# ─── Common ───────────────────────────────────────────────────────────────
ApiResponse:
type: object
properties:
status:
type: integer
nullable: false
data:
type: object
nullable: true
success:
type: boolean
nullable: false
requestID:
type: string
nullable: false
ErrorResponse:
type: object
properties:
status:
type: integer
message:
type: string
requestID:
type: string
# ─── Auth ─────────────────────────────────────────────────────────────────
RegisterRequest:
type: object
required: [email, password, fullName]
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
fullName:
type: string
LoginRequest:
type: object
required: [email, password]
properties:
email:
type: string
format: email
password:
type: string
TokenRefreshRequest:
type: object
required: [refreshToken]
properties:
refreshToken:
type: string
TokenResponse:
type: object
properties:
accessToken:
type: string
refreshToken:
type: string
expiresIn:
type: integer
# ─── User ─────────────────────────────────────────────────────────────────
User:
type: object
properties:
id:
type: string
format: uuid
email:
type: string
format: email
slug:
type: string
fullName:
type: string
nullable: true
avatarUrl:
type: string
nullable: true
role:
type: string
enum: [admin, manager, driver, client]
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
nullable: true
lastLoginAt:
type: string
format: date-time
nullable: true
UserUpdate:
type: object
properties:
fullName:
type: string
minLength: 2
maxLength: 150
nullable: true
avatarUrl:
type: string
format: uri
nullable: true
password:
type: string
minLength: 8
nullable: true
currentPassword:
type: string
minLength: 8
nullable: true
UserDeleteRequest:
type: object
required: [password]
properties:
password:
type: string
# ─── Vehicle ──────────────────────────────────────────────────────────────
Vehicle:
type: object
properties:
id:
type: string
format: uuid
plateNumber:
type: string
brand:
type: string
nullable: true
model:
type: string
nullable: true
year:
type: integer
nullable: true
capacityKg:
type: number
nullable: true
capacityM3:
type: number
nullable: true
status:
type: string
enum: [available, in_transit, maintenance]
slug:
type: string
VehicleCreate:
type: object
required: [plateNumber]
properties:
plateNumber:
type: string
brand:
type: string
nullable: true
model:
type: string
nullable: true
year:
type: integer
nullable: true
capacityKg:
type: number
nullable: true
capacityM3:
type: number
nullable: true
VehicleUpdate:
type: object
properties:
brand:
type: string
nullable: true
model:
type: string
nullable: true
year:
type: integer
nullable: true
capacityKg:
type: number
nullable: true
capacityM3:
type: number
nullable: true
status:
type: string
enum: [available, in_transit, maintenance]
nullable: true
# ─── Warehouse ────────────────────────────────────────────────────────────
Warehouse:
type: object
properties:
id:
type: string
format: uuid
slug:
type: string
name:
type: string
address:
type: string
city:
type: string
nullable: true
latitude:
type: number
nullable: true
longitude:
type: number
nullable: true
status:
type: string
enum: [active, inactive]
createdAt:
type: string
format: date-time
WarehouseCreate:
type: object
required: [name, address]
properties:
name:
type: string
address:
type: string
city:
type: string
nullable: true
latitude:
type: number
nullable: true
longitude:
type: number
nullable: true
WarehouseUpdate:
type: object
properties:
name:
type: string
nullable: true
address:
type: string
nullable: true
city:
type: string
nullable: true
latitude:
type: number
nullable: true
longitude:
type: number
nullable: true
status:
type: string
enum: [active, inactive]
nullable: true
# ─── Manager ──────────────────────────────────────────────────────────────
Manager:
type: object
properties:
id:
type: string
format: uuid
userId:
type: string
format: uuid
warehouseId:
type: string
format: uuid
nullable: true
slug:
type: string
ManagerCreate:
type: object
required: [email, password, fullName]
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
fullName:
type: string
warehouseId:
type: string
format: uuid
nullable: true
# ─── Driver ───────────────────────────────────────────────────────────────
Driver:
type: object
properties:
id:
type: string
format: uuid
userId:
type: string
format: uuid
vehicleId:
type: string
format: uuid
nullable: true
licenseNumber:
type: string
licenseExpiry:
type: string
format: date
rating:
type: number
slug:
type: string
status:
type: string
enum: [available, on_route, off_duty]
DriverCreate:
type: object
required: [email, password, fullName, licenseNumber, licenseExpiry]
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
fullName:
type: string
vehicleId:
type: string
format: uuid
nullable: true
licenseNumber:
type: string
licenseExpiry:
type: string
format: date
DriverUpdate:
type: object
properties:
vehicleId:
type: string
format: uuid
nullable: true
licenseNumber:
type: string
nullable: true
licenseExpiry:
type: string
format: date
nullable: true
status:
type: string
enum: [available, on_route, off_duty]
nullable: true
# ─── Order ────────────────────────────────────────────────────────────────
Order:
type: object
properties:
id:
type: string
format: uuid
createdById:
type: string
format: uuid
nullable: true
driverId:
type: string
format: uuid
nullable: true
managerId:
type: string
format: uuid
nullable: true
originWarehouseId:
type: string
format: uuid
nullable: true
originAddress:
type: string
nullable: true
destinationAddress:
type: string
cargoDescription:
type: string
nullable: true
weightKg:
type: number
nullable: true
volumeM3:
type: number
nullable: true
status:
type: string
enum: [pending, assigned, in_transit, delivered, cancelled]
totalPrice:
type: number
nullable: true
createdAt:
type: string
format: date-time
assignedAt:
type: string
format: date-time
nullable: true
deliveredAt:
type: string
format: date-time
nullable: true
OrderCreate:
type: object
required: [destinationAddress]
properties:
originWarehouseId:
type: string
format: uuid
nullable: true
originAddress:
type: string
nullable: true
destinationAddress:
type: string
cargoDescription:
type: string
nullable: true
weightKg:
type: number
nullable: true
volumeM3:
type: number
nullable: true
OrderStatusUpdate:
type: object
required: [status]
properties:
status:
type: string
enum: [assigned, in_transit, delivered, cancelled]
driverId:
type: string
format: uuid
nullable: true
# ─── Notification ─────────────────────────────────────────────────────────
Notification:
type: object
properties:
id:
type: string
format: uuid
userId:
type: string
format: uuid
title:
type: string
body:
type: string
nullable: true
isRead:
type: boolean
createdAt:
type: string
format: date-time
# ─── Report ───────────────────────────────────────────────────────────────
DriverStatusUpdate:
type: object
required: [status]
properties:
status:
type: string
enum: [available, on_route, off_duty]
# ─── Dashboard ────────────────────────────────────────────────────────────
DashboardDriverStat:
type: object
properties:
id:
type: string
format: uuid
fullName:
type: string
status:
type: string
enum: [available, on_route, off_duty]
rating:
type: number
completedOrders:
type: integer
DashboardReport:
type: object
properties:
revenue:
type: object
properties:
total:
type: number
thisMonth:
type: number
orders:
type: object
properties:
total:
type: integer
delivered:
type: integer
inTransit:
type: integer
pending:
type: integer
cancelled:
type: integer
drivers:
type: array
items:
$ref: "#/components/schemas/DashboardDriverStat"
# ─── Route ────────────────────────────────────────────────────────────────
Coordinate:
type: array
items:
type: number
minItems: 2
maxItems: 2
description: "[longitude, latitude] — ORS format"
Route:
type: object
properties:
id:
type: string
format: uuid
orderId:
type: string
format: uuid
driverId:
type: string
format: uuid
nullable: true
coordinates:
type: array
items:
$ref: "#/components/schemas/Coordinate"
description: Массив координат маршрута от ORS
currentIndex:
type: integer
description: Текущая позиция водителя в массиве координат
startedAt:
type: string
format: date-time
nullable: true
finishedAt:
type: string
format: date-time
nullable: true
distanceKm:
type: number
nullable: true
durationSec:
type: integer
nullable: true
status:
type: string
enum: [pending, active, finished]
RoutePosition:
type: object
description: Сообщение WebSocket — текущая позиция водителя
properties:
currentIndex:
type: integer
coordinate:
$ref: "#/components/schemas/Coordinate"
status:
type: string
enum: [active, finished]
paths:
# ─── Auth ───────────────────────────────────────────────────────────────────
/auth/register:
post:
operationId: authRegister
summary: Регистрация клиента
description: Публичный эндпоинт — создаёт аккаунт с ролью client. Для создания менеджеров и водителей используйте POST /managers и POST /drivers (только admin).
tags: [Auth]
security: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RegisterRequest"
responses:
"200":
description: Пользователь создан, токены выданы
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"400":
description: Некорректные данные
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"409":
description: Email уже занят
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/auth/login:
post:
operationId: authLogin
summary: Авторизация
tags: [Auth]
security: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/LoginRequest"
responses:
"200":
description: Успешный вход
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"401":
description: Неверный email или пароль
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/auth/refresh:
post:
operationId: authRefresh
summary: Обновление access-токена
tags: [Auth]
security: []
responses:
"200":
description: Токены обновлены
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"401":
description: Недействительный refresh-токен
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/auth/logout:
post:
operationId: authLogout
summary: Выход из системы
tags: [Auth]
responses:
"200":
description: Успешный выход
"401":
description: Не авторизован
# ─── Me ─────────────────────────────────────────────────────────────────────
/me:
get:
operationId: getMe
summary: Текущий пользователь
tags: [Me]
responses:
"200":
description: Данные пользователя
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"401":
description: Не авторизован
patch:
operationId: updateMe
summary: Обновить профиль
tags: [Me]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UserUpdate"
responses:
"200":
description: Профиль обновлён
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"400":
description: Некорректные данные
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"401":
description: Не авторизован
delete:
operationId: deleteMe
summary: Удалить аккаунт
tags: [Me]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UserDeleteRequest"
responses:
"200":
description: Аккаунт удалён
"400":
description: Неверный пароль
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"401":
description: Не авторизован
/me/trips:
get:
operationId: getMyTrips
summary: Поездки текущего водителя
tags: [Me]
description: Доступно только для роли driver. Возвращает маршруты, назначенные на текущего водителя.
responses:
"200":
description: Список маршрутов
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"403":
description: Доступно только водителям
# ─── Vehicles ───────────────────────────────────────────────────────────────
/vehicles:
get:
operationId: listVehicles
summary: Список транспортных средств
tags: [Vehicles]
responses:
"200":
description: Список ТС
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"401":
description: Не авторизован
post:
operationId: createVehicle
summary: Добавить ТС
tags: [Vehicles]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/VehicleCreate"
responses:
"200":
description: ТС создано
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"400":
description: Некорректные данные
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/vehicles/{slug}:
parameters:
- name: slug
in: path
required: true
schema:
type: string
get:
operationId: getVehicle
summary: Получить ТС по slug
tags: [Vehicles]
responses:
"200":
description: Данные ТС
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"404":
description: Не найдено
put:
operationId: updateVehicle
summary: Обновить ТС
tags: [Vehicles]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/VehicleUpdate"
responses:
"200":
description: ТС обновлено
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"404":
description: Не найдено
delete:
operationId: deleteVehicle
summary: Удалить ТС
tags: [Vehicles]
responses:
"200":
description: ТС удалено
"404":
description: Не найдено
# ─── Warehouses ─────────────────────────────────────────────────────────────
/warehouses:
get:
operationId: listWarehouses
summary: Список складов
tags: [Warehouses]
responses:
"200":
description: Список складов
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
post:
operationId: createWarehouse
summary: Создать склад
tags: [Warehouses]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/WarehouseCreate"
responses:
"200":
description: Склад создан
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"400":
description: Некорректные данные
/warehouses/{slug}:
parameters:
- name: slug
in: path
required: true
schema:
type: string
get:
operationId: getWarehouse
summary: Получить склад по slug
tags: [Warehouses]
responses:
"200":
description: Данные склада
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"404":
description: Не найдено
put:
operationId: updateWarehouse
summary: Обновить склад
tags: [Warehouses]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/WarehouseUpdate"
responses:
"200":
description: Склад обновлён
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
delete:
operationId: deleteWarehouse
summary: Удалить склад
tags: [Warehouses]
responses:
"200":
description: Склад удалён
# ─── Managers ───────────────────────────────────────────────────────────────
/managers:
get:
operationId: listManagers
summary: Список менеджеров
tags: [Managers]
responses:
"200":
description: Список менеджеров
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
post:
operationId: createManager
summary: Создать менеджера
description: Только для роли admin. Создаёт пользователя с ролью manager и профиль менеджера в одной транзакции.
tags: [Managers]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ManagerCreate"
responses:
"200":
description: Менеджер создан
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"400":
description: Некорректные данные
/managers/{slug}:
parameters:
- name: slug
in: path
required: true
schema:
type: string
get:
operationId: getManager
summary: Получить менеджера по slug
tags: [Managers]
responses:
"200":
description: Данные менеджера
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"404":
description: Не найдено
delete:
operationId: deleteManager
summary: Удалить менеджера
tags: [Managers]
responses:
"200":
description: Менеджер удалён
# ─── Drivers ────────────────────────────────────────────────────────────────
/drivers:
get:
operationId: listDrivers
summary: Список водителей
tags: [Drivers]
parameters:
- name: status
in: query
required: false
schema:
type: string
enum: [available, on_route, off_duty]
responses:
"200":
description: Список водителей
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
post:
operationId: createDriver
summary: Создать водителя
description: Только для роли admin. Создаёт пользователя с ролью driver и профиль водителя в одной транзакции.
tags: [Drivers]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DriverCreate"
responses:
"200":
description: Водитель создан
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"400":
description: Некорректные данные
/drivers/{slug}:
parameters:
- name: slug
in: path
required: true
schema:
type: string
get:
operationId: getDriver
summary: Получить водителя по slug
tags: [Drivers]
responses:
"200":
description: Данные водителя
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"404":
description: Не найдено
put:
operationId: updateDriver
summary: Обновить данные водителя
tags: [Drivers]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DriverUpdate"
responses:
"200":
description: Данные обновлены
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
delete:
operationId: deleteDriver
summary: Удалить водителя
tags: [Drivers]
responses:
"200":
description: Водитель удалён
/drivers/me/status:
patch:
operationId: updateMyDriverStatus
summary: Водитель меняет свой статус
tags: [Drivers]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DriverStatusUpdate"
responses:
"200":
description: Статус обновлён
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"403":
description: Доступно только водителям
# ─── Orders ─────────────────────────────────────────────────────────────────
/orders:
get:
operationId: listOrders
summary: Список заявок
tags: [Orders]
description: >
Клиент видит только свои заявки, менеджер — заявки своего склада,
водитель — назначенные на него, администратор — все.
parameters:
- name: status
in: query
required: false
schema:
type: string
enum: [pending, assigned, in_transit, delivered, cancelled]
- name: driverId
in: query
required: false
schema:
type: string
format: uuid
responses:
"200":
description: Список заявок
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
post:
operationId: createOrder
summary: Создать заявку
tags: [Orders]
description: >
Создаёт заявку и запрашивает маршрут в OpenRouteService по адресам.
Координаты сохраняются в таблице routes.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrderCreate"
responses:
"200":
description: Заявка создана
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"400":
description: Некорректные данные или ORS недоступен
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/orders/{id}:
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
get:
operationId: getOrder
summary: Получить заявку
tags: [Orders]
responses:
"200":
description: Данные заявки
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"404":
description: Не найдено
delete:
operationId: cancelOrder
summary: Отменить заявку
tags: [Orders]
description: Доступно только для статуса pending.
responses:
"200":
description: Заявка отменена
"400":
description: Нельзя отменить заявку в текущем статусе
"403":
description: Нет доступа
/orders/{id}/status:
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
patch:
operationId: updateOrderStatus
summary: Обновить статус заявки
tags: [Orders]
description: Менеджер назначает водителя (assigned), водитель обновляет (in_transit / delivered).
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrderStatusUpdate"
responses:
"200":
description: Статус обновлён
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"400":
description: Недопустимый переход статуса
"403":
description: Нет доступа
# ─── Routes ─────────────────────────────────────────────────────────────────
/orders/{id}/route:
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
get:
operationId: getRoute
summary: Получить маршрут заявки
tags: [Routes]
description: Возвращает весь маршрут с координатами и текущим индексом.
responses:
"200":
description: Данные маршрута
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"404":
description: Маршрут не найден
/orders/{id}/route/ws:
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
get:
operationId: routeWebSocket
summary: WebSocket трекинг маршрута
tags: [Routes]
description: >
Upgrades to WebSocket. Сервер отправляет RoutePosition каждые N секунд,
двигая current_index по массиву координат в горутине.
Соединение закрывается когда статус маршрута становится finished.
responses:
"101":
description: Switching Protocols — WebSocket установлен
"404":
description: Маршрут не найден
# ─── Notifications ───────────────────────────────────────────────────────────
/notifications:
get:
operationId: listNotifications
summary: Список уведомлений текущего пользователя
tags: [Notifications]
parameters:
- name: unreadOnly
in: query
required: false
schema:
type: boolean
responses:
"200":
description: Список уведомлений
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"401":
description: Не авторизован
/notifications/{id}/read:
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
patch:
operationId: markNotificationRead
summary: Отметить уведомление как прочитанное
tags: [Notifications]
responses:
"200":
description: Отмечено
"404":
description: Не найдено
# ─── Reports ─────────────────────────────────────────────────────────────────
/reports/orders:
get:
operationId: getOrdersReport
summary: Отчёт по заявкам
tags: [Reports]
description: Доступно для ролей admin и manager. Возвращает агрегированные данные по завершённым заявкам за период.
parameters:
- name: from
in: query
required: false
schema:
type: string
format: date
- name: to
in: query
required: false
schema:
type: string
format: date
- name: status
in: query
required: false
schema:
type: string
enum: [pending, assigned, in_transit, delivered, cancelled]
- name: driverId
in: query
required: false
schema:
type: string
format: uuid
- name: warehouseId
in: query
required: false
schema:
type: string
format: uuid
responses:
"200":
description: Отчёт сформирован
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"403":
description: Нет доступа
/reports/dashboard:
get:
operationId: getDashboard
summary: Дашборд менеджмента
description: Доступно для ролей admin и manager. Возвращает агрегированную статистику по выручке, заявкам и водителям.
tags: [Reports]
responses:
"200":
description: Данные дашборда
content:
application/json:
schema:
$ref: "#/components/schemas/ApiResponse"
"403":
description: Нет доступа