fleet-ble-monitor/frontend/docs/backend-domain-model.md

931 lines
21 KiB
Markdown
Raw Permalink 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.

# Fleet BLE Monitor Backend Contract Draft
Черновик backend-модели, GraphQL-like API и use-cases для `fleet-ble-monitor`.
Документ написан в формате, близком к GraphQL Docs: у сущности сразу перечислены поля, рядом указаны связанные enum/input/page-типы. Это не финальная схема, а база для обсуждения со старшим.
## Общие скаляры
```graphql
scalar DateTime
scalar Date
```
`DateTime` — ISO-строка даты и времени.
`Date` — календарная дата в формате `YYYY-MM-DD`.
## User
Пользователь системы. Используется для авторизации, прав доступа и как получатель отчетов.
```graphql
type User {
id: ID!
lastName: String!
firstName: String!
middleName: String
email: String!
login: String!
role: UserRole!
createdAt: DateTime!
updatedAt: DateTime
}
```
### UserRole
Роль пользователя.
```graphql
enum UserRole {
ADMIN
USER
}
```
`ADMIN` — администратор.
`USER` — пользователь.
### UsersPage
Страница пользователей для таблицы.
```graphql
type UsersPage {
totalPages: Int!
totalElements: Int!
page: [User!]!
}
```
### UserSortField
Поле сортировки пользователей.
```graphql
enum UserSortField {
ID
NAME
DATE
}
```
### SortDirection
Общее направление сортировки.
```graphql
enum SortDirection {
ASC
DESC
}
```
### LoginPayload
```graphql
input LoginPayload {
loginOrEmail: String!
password: String!
}
```
### CreateUserPayload
```graphql
input CreateUserPayload {
lastName: String!
firstName: String!
middleName: String
email: String!
login: String!
password: String!
role: UserRole!
}
```
### UpdateUserPayload
```graphql
input UpdateUserPayload {
lastName: String
firstName: String
middleName: String
email: String
login: String
password: String
role: UserRole
}
```
## Machine
АТТ / единица техники. Основная бизнес-сущность мониторинга.
```graphql
type Machine {
id: ID!
name: String!
licensePlate: String!
type: MachineType!
department: Department!
description: String
beacon: Beacon
lastKnownState: MachineStateCode!
lastDataReceivedAt: DateTime
createdAt: DateTime!
updatedAt: DateTime!
}
```
### MachineType
Справочник типов АТТ.
```graphql
type MachineType {
id: ID!
name: String!
description: String
createdAt: DateTime!
updatedAt: DateTime!
}
```
Примеры: каток, самосвал, погрузчик, экскаватор.
### Department
Справочник подразделений, участков или объектов.
```graphql
type Department {
id: ID!
name: String!
description: String
createdAt: DateTime!
updatedAt: DateTime!
}
```
### MachineStateCode
Последнее известное базовое состояние АТТ.
```graphql
enum MachineStateCode {
IDLE
ENGINE_ON
MOVING
NO_DATA
}
```
`IDLE` — стоит.
`ENGINE_ON` — заведена.
`MOVING` — в движении.
`NO_DATA` — нет данных.
### MachinesPage
```graphql
type MachinesPage {
totalPages: Int!
totalElements: Int!
page: [Machine!]!
}
```
### MachineSortField
```graphql
enum MachineSortField {
ID
NAME
DATE
}
```
### CreateMachinePayload
```graphql
input CreateMachinePayload {
name: String!
licensePlate: String!
typeId: ID!
departmentId: ID!
description: String
}
```
### UpdateMachinePayload
```graphql
input UpdateMachinePayload {
name: String
licensePlate: String
typeId: ID
departmentId: ID
description: String
}
```
## Beacon
BLE-маяк. Хранит идентификатор, MAC-адрес, статус привязки, последнюю связь.
```graphql
type Beacon {
id: ID!
identifier: String!
macAddress: String!
status: BeaconStatus!
boundMachine: Machine
lastSeenAt: DateTime
createdAt: DateTime!
updatedAt: DateTime!
}
```
### BeaconStatus
```graphql
enum BeaconStatus {
FREE
BOUND
}
```
`FREE` — маяк свободен.
`BOUND` — маяк привязан к АТТ.
### BeaconTelemetryPacket
Сырое сообщение от маяка.
```graphql
type BeaconTelemetryPacket {
id: ID!
beacon: Beacon!
machine: Machine
mac: String!
vibration: Float!
duration: Int!
timeMillis: Long!
receivedAt: DateTime!
}
```
### BeaconTelemetryPayload
Payload входящего сообщения от маяка.
```graphql
input BeaconTelemetryPayload {
mac: String!
vibration: Float!
duration: Int!
timeMillis: Long!
}
```
`duration` — длительность замера/пакета в секундах.
`timeMillis` — время события на стороне маяка или шлюза.
## MachineStateDefinition
Справочник состояний АТТ без привязки к конкретным значениям акселерометра.
```graphql
type MachineStateDefinition {
id: ID!
name: String!
icon: String!
color: String!
description: String
isSystem: Boolean!
createdAt: DateTime!
updatedAt: DateTime!
}
```
Примеры:
- `Стоит`
- `Заведена`
- `В движении`
- `Работа с нагрузкой`
- `Нет данных`
`Нет данных` — системное состояние, его нельзя удалять и нельзя использовать в ручном правиле калибровки.
### CreateMachineStateDefinitionPayload
```graphql
input CreateMachineStateDefinitionPayload {
name: String!
icon: String!
color: String!
description: String
}
```
### UpdateMachineStateDefinitionPayload
```graphql
input UpdateMachineStateDefinitionPayload {
name: String
icon: String
color: String
description: String
}
```
## MachineCalibrationRule
Правило калибровки для конкретной АТТ. Связывает диапазон значений вибрации с состоянием из справочника.
```graphql
type MachineCalibrationRule {
id: ID!
machine: Machine!
stateDefinition: MachineStateDefinition!
vibrationMin: Float!
vibrationMax: Float!
createdAt: DateTime!
updatedAt: DateTime!
}
```
### CreateMachineCalibrationRulePayload
```graphql
input CreateMachineCalibrationRulePayload {
machineId: ID!
stateDefinitionId: ID!
vibrationMin: Float!
vibrationMax: Float!
}
```
### UpdateMachineCalibrationRulePayload
```graphql
input UpdateMachineCalibrationRulePayload {
stateDefinitionId: ID
vibrationMin: Float
vibrationMax: Float
}
```
## MachineStateInterval
Распознанный интервал состояния АТТ.
```graphql
type MachineStateInterval {
id: ID!
machine: Machine!
stateDefinition: MachineStateDefinition
stateCode: MachineStateCode
startedAt: DateTime!
endedAt: DateTime
durationSeconds: Int!
vibrationMin: Float
vibrationMax: Float
vibrationAvg: Float
sampleCount: Int!
isNoData: Boolean!
}
```
Если `stateDefinition` равен `null`, участок считается нераспознанным.
Если `isNoData = true`, участок относится к системному состоянию `Нет данных`.
### MachineStateHistoryPage
```graphql
type MachineStateHistoryPage {
totalPages: Int!
totalElements: Int!
page: [MachineStateInterval!]!
}
```
## MachineUsageSummary
Краткая статистика по АТТ за период.
```graphql
type MachineUsageSummary {
machine: Machine!
periodStart: DateTime!
periodEnd: DateTime!
movingSeconds: Int!
engineOnSeconds: Int!
idleSeconds: Int!
noDataSeconds: Int!
stateChangesCount: Int!
utilizationPercent: Int!
}
```
## FleetReportSchedule
Настройка ежедневной рассылки отчета по парку АТТ.
```graphql
type FleetReportSchedule {
id: ID!
name: String!
recipients: [User!]!
reportFormat: ReportFormat!
sendTime: String!
period: ReportPeriod!
timezone: String!
enabled: Boolean!
createdAt: DateTime!
updatedAt: DateTime!
}
```
### ReportFormat
Формат отчета.
```graphql
enum ReportFormat {
PDF
XLSX
}
```
### ReportPeriod
Период отчета.
```graphql
enum ReportPeriod {
PREVIOUS_DAY
}
```
`PREVIOUS_DAY` — предыдущий календарный день относительно timezone расписания.
### CreateFleetReportSchedulePayload
```graphql
input CreateFleetReportSchedulePayload {
recipientUserIds: [ID!]!
reportFormat: ReportFormat!
sendTime: String!
}
```
### UpdateFleetReportSchedulePayload
```graphql
input UpdateFleetReportSchedulePayload {
recipientUserIds: [ID!]
reportFormat: ReportFormat
sendTime: String
enabled: Boolean
}
```
## FleetReportDelivery
История конкретной попытки отправки отчета.
```graphql
type FleetReportDelivery {
id: ID!
schedule: FleetReportSchedule
reportDate: Date!
reportFormat: ReportFormat!
recipients: [User!]!
status: ReportDeliveryStatus!
fileName: String
errorMessage: String
createdAt: DateTime!
sentAt: DateTime
}
```
### ReportDeliveryStatus
```graphql
enum ReportDeliveryStatus {
CREATED
GENERATING
SENT
FAILED
}
```
`CREATED` — задача создана.
`GENERATING` — отчет формируется.
`SENT` — отчет отправлен.
`FAILED` — ошибка генерации или отправки.
## FleetDailyReport
Доменная модель дневного отчета по парку АТТ.
```graphql
type FleetDailyReport {
date: Date!
generatedAt: DateTime!
summary: FleetDailyReportSummary!
machines: [FleetDailyReportMachineRow!]!
history: [FleetDailyReportHistoryRow!]!
}
```
### FleetDailyReportSummary
```graphql
type FleetDailyReportSummary {
totalMachines: Int!
boundMachines: Int!
unboundMachines: Int!
machinesWithMovement: Int!
machinesWithoutData: Int!
movingSeconds: Int!
engineOnSeconds: Int!
idleSeconds: Int!
noDataSeconds: Int!
stateChangesCount: Int!
}
```
### FleetDailyReportMachineRow
```graphql
type FleetDailyReportMachineRow {
machine: Machine!
movingSeconds: Int!
engineOnSeconds: Int!
idleSeconds: Int!
noDataSeconds: Int!
stateChangesCount: Int!
utilizationPercent: Int!
}
```
### FleetDailyReportHistoryRow
```graphql
type FleetDailyReportHistoryRow {
machine: Machine!
startedAt: DateTime!
endedAt: DateTime!
stateDefinition: MachineStateDefinition
stateCode: MachineStateCode
durationSeconds: Int!
}
```
### GenerateFleetDailyReportPayload
```graphql
input GenerateFleetDailyReportPayload {
date: Date!
format: ReportFormat!
}
```
### ReportFile
Ссылка на готовый файл отчета.
```graphql
type ReportFile {
fileName: String!
mimeType: String!
downloadUrl: String!
expiresAt: DateTime
}
```
Физическая отдача файла может быть не через GraphQL, а через REST endpoint или object storage URL. GraphQL в таком случае возвращает `downloadUrl`.
## Query
```graphql
type Query {
currentUser: User
getUsers(
page: Int!
pageSize: Int
query: String
roles: [UserRole!]
sortDirection: SortDirection!
sortField: UserSortField!
): UsersPage!
getUser(id: ID!): User
getMachines(
page: Int!
pageSize: Int
query: String
sortDirection: SortDirection!
sortField: MachineSortField!
): MachinesPage!
getMachine(id: ID!): Machine
getMachineTypes: [MachineType!]!
getDepartments: [Department!]!
getBeacons: [Beacon!]!
getFreeBeacons: [Beacon!]!
getBeaconTelemetry(
beaconId: ID
machineId: ID
startDate: DateTime!
endDate: DateTime!
): [BeaconTelemetryPacket!]!
getMachineStateDefinitions: [MachineStateDefinition!]!
getMachineCalibrationRules(machineId: ID!): [MachineCalibrationRule!]!
getMachineStateHistory(
machineId: ID!
startDate: DateTime!
endDate: DateTime!
page: Int
pageSize: Int
): MachineStateHistoryPage!
getMachineUsageSummary(
machineId: ID!
startDate: DateTime!
endDate: DateTime!
): MachineUsageSummary!
getUnrecognizedTelemetryIntervals(
machineId: ID!
startDate: DateTime!
endDate: DateTime!
): [MachineStateInterval!]!
getFleetReportSchedules: [FleetReportSchedule!]!
getFleetReportDeliveries(
scheduleId: ID
dateFrom: Date
dateTo: Date
): [FleetReportDelivery!]!
getFleetDailyReport(date: Date!): FleetDailyReport!
createFleetDailyReportDownloadUrl(
payload: GenerateFleetDailyReportPayload!
): ReportFile!
}
```
## Mutation
```graphql
type Mutation {
login(payload: LoginPayload!): User!
logout: Boolean!
createUser(payload: CreateUserPayload!): User!
updateUser(
id: ID!
payload: UpdateUserPayload!
): User!
deleteUser(id: ID!): Boolean!
createMachine(payload: CreateMachinePayload!): Machine!
updateMachine(
id: ID!
payload: UpdateMachinePayload!
): Machine!
deleteMachine(id: ID!): Boolean!
bindBeaconToMachine(
machineId: ID!
beaconId: ID!
): Machine!
unbindBeaconFromMachine(machineId: ID!): Machine!
registerBeaconTelemetryPacket(
payload: BeaconTelemetryPayload!
): Boolean!
createMachineType(name: String!): MachineType!
updateMachineType(
id: ID!
name: String!
): MachineType!
deleteMachineType(id: ID!): Boolean!
createDepartment(name: String!): Department!
updateDepartment(
id: ID!
name: String!
): Department!
deleteDepartment(id: ID!): Boolean!
createMachineStateDefinition(
payload: CreateMachineStateDefinitionPayload!
): MachineStateDefinition!
updateMachineStateDefinition(
id: ID!
payload: UpdateMachineStateDefinitionPayload!
): MachineStateDefinition!
deleteMachineStateDefinition(id: ID!): Boolean!
createMachineCalibrationRule(
payload: CreateMachineCalibrationRulePayload!
): MachineCalibrationRule!
updateMachineCalibrationRule(
id: ID!
payload: UpdateMachineCalibrationRulePayload!
): MachineCalibrationRule!
deleteMachineCalibrationRule(id: ID!): Boolean!
recognizeMachineStates(
machineId: ID!
startDate: DateTime!
endDate: DateTime!
): [MachineStateInterval!]!
createFleetReportSchedule(
payload: CreateFleetReportSchedulePayload!
): FleetReportSchedule!
updateFleetReportSchedule(
id: ID!
payload: UpdateFleetReportSchedulePayload!
): FleetReportSchedule!
deleteFleetReportSchedule(id: ID!): Boolean!
sendFleetDailyReport(
scheduleId: ID!
reportDate: Date!
): FleetReportDelivery!
}
```
## Use-Cases
### Пользователи
`LoginUserUseCase` — авторизует пользователя по логину/email и паролю.
`GetCurrentUserUseCase` — возвращает текущего авторизованного пользователя.
`GetUsersUseCase` — возвращает список пользователей с поиском, сортировкой и пагинацией.
`CreateUserUseCase` — создает пользователя.
`UpdateUserUseCase` — редактирует данные пользователя.
`DeleteUserUseCase` — удаляет пользователя или блокирует, если будет выбран soft-delete подход.
### АТТ
`GetMachinesUseCase` — возвращает список АТТ с поиском, сортировкой и пагинацией.
`GetMachineByIdUseCase` — возвращает карточку конкретной АТТ.
`CreateMachineUseCase` — создает новую АТТ.
`UpdateMachineUseCase` — редактирует данные АТТ.
`DeleteMachineUseCase` — удаляет АТТ или переводит в архив.
`BindBeaconToMachineUseCase` — привязывает свободный маяк к АТТ.
`UnbindBeaconFromMachineUseCase` — отвязывает маяк от АТТ.
### Маяки и телеметрия
`RegisterBeaconTelemetryPacketUseCase` — принимает сырое сообщение от маяка и сохраняет его.
`ResolveBeaconByMacUseCase` — находит маяк по MAC-адресу из входящего пакета.
`AttachTelemetryPacketToMachineUseCase` — определяет, к какой АТТ относится пакет, если маяк привязан.
`GetBeaconTelemetryUseCase` — возвращает сырые показания маяка за период.
`GetFreeBeaconsUseCase` — возвращает список свободных маяков.
### Калибровка
`GetMachineStateDefinitionsUseCase` — возвращает справочник состояний АТТ.
`CreateMachineStateDefinitionUseCase` — создает новое состояние в справочнике.
`UpdateMachineStateDefinitionUseCase` — редактирует состояние справочника.
`DeleteMachineStateDefinitionUseCase` — удаляет состояние, если оно не используется правилами.
`GetMachineCalibrationRulesUseCase` — возвращает правила калибровки конкретной АТТ.
`CreateMachineCalibrationRuleUseCase` — создает правило калибровки для АТТ.
`UpdateMachineCalibrationRuleUseCase` — редактирует правило калибровки.
`DeleteMachineCalibrationRuleUseCase` — удаляет правило калибровки.
`ValidateMachineCalibrationRuleUseCase` — проверяет правило на конфликты с уже существующими диапазонами.
`RecognizeMachineStatesUseCase` — по сырым данным акселерометра и правилам калибровки строит интервалы состояний.
`GetUnrecognizedTelemetryIntervalsUseCase` — возвращает участки телеметрии, которые не попали ни под одно правило.
### История и аналитика
`GetMachineStateHistoryUseCase` — возвращает историю состояний АТТ за период.
`GetMachineUsageSummaryUseCase` — собирает краткую статистику по АТТ за период.
`GetMachineDailyUsageStatsUseCase` — возвращает дневную статистику по АТТ для графиков.
`AggregateMachineStateIntervalsUseCase` — агрегирует интервалы состояний из телеметрии.
### Отчеты
`GetFleetReportSchedulesUseCase` — возвращает настройки рассылок отчетов.
`CreateFleetReportScheduleUseCase` — создает настройку ежедневной рассылки отчета.
`UpdateFleetReportScheduleUseCase` — редактирует настройку рассылки.
`DeleteFleetReportScheduleUseCase` — удаляет настройку рассылки.
`GenerateFleetDailyReportUseCase` — собирает дневной отчет по парку АТТ за выбранную дату.
`ExportFleetDailyReportToPdfUseCase` — формирует PDF-файл дневного отчета.
`ExportFleetDailyReportToXlsxUseCase` — формирует Excel-файл дневного отчета.
`DownloadFleetDailyReportUseCase` — отдает файл отчета пользователю по запросу из интерфейса.
`RunScheduledFleetReportsUseCase` — периодически запускает активные расписания рассылок.
`SendFleetDailyReportUseCase` — генерирует отчет и отправляет его выбранным пользователям.
`CreateFleetReportDeliveryUseCase` — создает запись о попытке отправки отчета.
`MarkFleetReportDeliveryAsSentUseCase` — помечает отправку как успешную.
`MarkFleetReportDeliveryAsFailedUseCase` — сохраняет ошибку отправки.
## Доменные сервисы
`MachineStateRecognitionService` — определяет состояние АТТ по телеметрии и правилам калибровки.
`MachineAnalyticsService` — считает агрегаты: время в движении, заведена, стояла, нет данных, смены состояний.
`FleetDailyReportBuilder` — собирает доменную модель дневного отчета.
`FleetReportExporter` — общий интерфейс для экспорта отчета в файл.
`PdfFleetReportExporter` — экспортирует отчет в PDF.
`XlsxFleetReportExporter` — экспортирует отчет в Excel.
`MailService` — отправляет письма с вложениями.
`ReportScheduler` — запускает ежедневные рассылки по расписанию.