Add OpenAPI specification for system-log service.
This commit is contained in:
parent
5f7fe11748
commit
f184c7b8d9
427
apps/system-log/openapi.yaml
Normal file
427
apps/system-log/openapi.yaml
Normal file
@ -0,0 +1,427 @@
|
||||
openapi: 3.0.3
|
||||
|
||||
info:
|
||||
title: system-log API
|
||||
version: "1.0.0"
|
||||
description: |
|
||||
REST API сервиса **system-log** (`platform/system-log`) — приём и выборка
|
||||
записей журнала системных событий (кто, над чем и какое действие совершил).
|
||||
|
||||
Сервис написан на Go (фреймворк **Fiber v2**). Роутинг собирается в
|
||||
`internal/controller/http/v0`: базовая группа `/api` → подгруппа `v0` →
|
||||
ресурс `/system_log`. Плюс служебный эндпоинт `/ping`.
|
||||
|
||||
### Аутентификация
|
||||
Аутентификация на уровне приложения не настроена — эндпоинты доступны без
|
||||
авторизации. Ограничение доступа обеспечивается сетевым слоем (ClusterIP /
|
||||
Istio), а не самим сервисом.
|
||||
|
||||
### Пагинация
|
||||
Списочные ответы возвращают объект `{ count, limit, offset, next, prev, result }`.
|
||||
Управление — параметрами `limit` и `offset`. Значения по умолчанию:
|
||||
`limit = 100`, `offset = 0` (константы `_defaultLimit` / `_defaultOffset`
|
||||
в `internal/controller/http/v0/systemlog/controller.go`). Ссылки `next`/`prev`
|
||||
формируются в `pkg/pagination`. У эндпоинта поиска (`POST /search`) полей
|
||||
`next`/`prev` нет.
|
||||
|
||||
### Фильтрация
|
||||
Массивные фильтры (`actor_ids`, `event_names`, `model_names`, `instance_ids`,
|
||||
`target_ids`, `company_ids`, `statuses`, `message`) в GET-запросе передаются
|
||||
списком значений через запятую и парсятся Fiber `QueryParser`. Поля
|
||||
`instance_uuids` и `resource_uuids` разбираются вручную (`strings.Split` +
|
||||
`uuid.Parse`) — при невалидном UUID возвращается `400`.
|
||||
|
||||
### Замечания (расхождения кода)
|
||||
- `metadata` в фильтре объявлено как `map[string]interface{}` с query-тегом,
|
||||
но при передаче в query-строке Fiber не восстановит вложенный объект —
|
||||
фильтрация по `metadata` практически применима через тело `POST /search`.
|
||||
- Поле `is_processed_by_worker` присутствует в фильтре, но отдаётся в выборку
|
||||
наравне с остальными; используется воркером обогащения.
|
||||
- Ответ `POST /system_log/` при успехе — простая строка `"OK"` (не объект).
|
||||
|
||||
servers:
|
||||
- url: https://api.sarex.io
|
||||
description: Production (ingress)
|
||||
- url: https://stage-api.sarex.io
|
||||
description: Stage (ingress)
|
||||
- url: http://backend-svc.system-log.svc.cluster.local
|
||||
description: Внутрикластерный адрес (ClusterIP, порт 80 → 8000)
|
||||
- url: http://localhost:8888
|
||||
description: Локальный запуск (config.env)
|
||||
|
||||
tags:
|
||||
- name: system_log
|
||||
description: Записи журнала системных событий
|
||||
- name: service
|
||||
description: Служебные эндпоинты
|
||||
|
||||
paths:
|
||||
# ==========================================================================
|
||||
# Service
|
||||
# ==========================================================================
|
||||
/ping:
|
||||
get:
|
||||
tags: [service]
|
||||
summary: Проверка живости
|
||||
description: Liveness/readiness-проба (используется в probes деплоймента). Всегда `200 OK` без тела.
|
||||
operationId: ping
|
||||
security: []
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
|
||||
# ==========================================================================
|
||||
# System log
|
||||
# ==========================================================================
|
||||
/api/v0/system_log/:
|
||||
get:
|
||||
tags: [system_log]
|
||||
summary: Список записей журнала (с фильтрами)
|
||||
description: |
|
||||
Возвращает отфильтрованные записи журнала с пагинацией.
|
||||
Массивные параметры принимают список значений через запятую.
|
||||
operationId: getSystemLogRecords
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/Limit'
|
||||
- $ref: '#/components/parameters/Offset'
|
||||
- name: actor_ids
|
||||
in: query
|
||||
description: ID авторов событий; список значений через запятую
|
||||
example: "1,2,3"
|
||||
schema: { type: string }
|
||||
- name: event_names
|
||||
in: query
|
||||
description: Названия событий (напр. create, edit, delete, transfer); через запятую
|
||||
example: "create,edit,delete"
|
||||
schema: { type: string }
|
||||
- name: model_names
|
||||
in: query
|
||||
description: Названия моделей (напр. document, bundle, project); через запятую
|
||||
example: "document,bundle"
|
||||
schema: { type: string }
|
||||
- name: instance_ids
|
||||
in: query
|
||||
description: ID сущностей; список значений через запятую
|
||||
example: "1,2,3"
|
||||
schema: { type: string }
|
||||
- name: instance_uuids
|
||||
in: query
|
||||
description: UUID сущностей; список значений через запятую (валидируются как UUID)
|
||||
example: "3fa85f64-5717-4562-b3fc-2c963f66afa6"
|
||||
schema: { type: string }
|
||||
- name: resource_uuids
|
||||
in: query
|
||||
description: UUID ресурсов; список значений через запятую (валидируются как UUID)
|
||||
schema: { type: string }
|
||||
- name: registered_at_gte
|
||||
in: query
|
||||
description: Нижняя граница времени регистрации (>=)
|
||||
example: "2025-02-16T15:04:05Z"
|
||||
schema: { type: string, format: date-time }
|
||||
- name: registered_at_lte
|
||||
in: query
|
||||
description: Верхняя граница времени регистрации (<=)
|
||||
example: "2025-02-16T15:04:05Z"
|
||||
schema: { type: string, format: date-time }
|
||||
- name: instance_path
|
||||
in: query
|
||||
description: Путь сущности (ltree), точное совпадение
|
||||
example: "1.79899.80131"
|
||||
schema: { type: string }
|
||||
- name: target_ids
|
||||
in: query
|
||||
description: ID целей; список значений через запятую
|
||||
example: "1,2,3"
|
||||
schema: { type: string }
|
||||
- name: target_path
|
||||
in: query
|
||||
description: Путь цели (ltree), точное совпадение
|
||||
example: "4.3.2.1"
|
||||
schema: { type: string }
|
||||
- name: company_ids
|
||||
in: query
|
||||
description: ID компаний; список значений через запятую
|
||||
example: "1,2,3"
|
||||
schema: { type: string }
|
||||
- name: statuses
|
||||
in: query
|
||||
description: Подстатусы события; список значений через запятую
|
||||
example: "add_bundle,delete_bundle,rename_document"
|
||||
schema: { type: string }
|
||||
- name: message
|
||||
in: query
|
||||
description: Сообщения; список значений через запятую
|
||||
schema: { type: string }
|
||||
- name: is_processed_by_worker
|
||||
in: query
|
||||
description: Признак обработки записи воркером обогащения
|
||||
schema: { type: boolean }
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/SystemLogListResponse' }
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalError'
|
||||
post:
|
||||
tags: [system_log]
|
||||
summary: Создать записи журнала
|
||||
description: |
|
||||
Принимает пакет записей в поле `system_logs`. Для каждой записи должно
|
||||
быть задано **ровно одно** из `instance_id` / `instance_uuid`
|
||||
(не оба и не ни одного — иначе `400`). Обязательны `event_name` и
|
||||
`model_name`. При успехе возвращается строка `"OK"`.
|
||||
operationId: createSystemLogRecords
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/SystemLogCreateRequest' }
|
||||
responses:
|
||||
'200':
|
||||
description: Записи созданы
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: string
|
||||
example: "OK"
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalError'
|
||||
|
||||
/api/v0/system_log/search:
|
||||
post:
|
||||
tags: [system_log]
|
||||
summary: Поиск записей журнала (фильтры в теле)
|
||||
description: |
|
||||
Аналог GET-выборки, но фильтры передаются в теле запроса
|
||||
(`filters`). Позволяет использовать сложные фильтры (в т.ч. `metadata`),
|
||||
которые неудобно кодировать в query-строке. В ответе нет `next`/`prev`.
|
||||
operationId: searchSystemLogs
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/SystemLogSearchRequest' }
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/SystemLogSearchResponse' }
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalError'
|
||||
|
||||
# ============================================================================
|
||||
components:
|
||||
parameters:
|
||||
Limit:
|
||||
name: limit
|
||||
in: query
|
||||
description: Кол-во записей на странице
|
||||
schema: { type: integer, format: uint64, default: 100 }
|
||||
Offset:
|
||||
name: offset
|
||||
in: query
|
||||
description: Смещение от начала выборки
|
||||
schema: { type: integer, format: uint64, default: 0, minimum: 0 }
|
||||
|
||||
responses:
|
||||
BadRequest:
|
||||
description: Ошибка разбора/валидации запроса
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/ControllerError' }
|
||||
InternalError:
|
||||
description: Внутренняя ошибка сервиса
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/ControllerError' }
|
||||
|
||||
schemas:
|
||||
# ---- Общие ----
|
||||
ControllerError:
|
||||
type: object
|
||||
description: Формат ошибки (`internal/controller/errors.go`, `ErrorToResponse`).
|
||||
properties:
|
||||
message: { type: string, example: "error parse body" }
|
||||
status_code: { type: integer, example: 400 }
|
||||
|
||||
# ---- Доменная запись ----
|
||||
SystemLog:
|
||||
type: object
|
||||
description: Запись журнала системных событий (`internal/entity/system_log.go`).
|
||||
properties:
|
||||
actor_id:
|
||||
type: integer
|
||||
format: uint64
|
||||
description: ID автора события
|
||||
example: 1023
|
||||
event_name:
|
||||
type: string
|
||||
description: Название события (напр. edit, create, copy)
|
||||
example: "edit"
|
||||
model_name:
|
||||
type: string
|
||||
description: Над какой сущностью произошло событие (напр. document, inspection)
|
||||
example: "document"
|
||||
instance_id:
|
||||
type: integer
|
||||
format: uint64
|
||||
nullable: true
|
||||
description: ID сущности (для моделей с числовым ключом)
|
||||
example: 80131
|
||||
instance_uuid:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
description: UUID сущности (для моделей с UUID-ключом)
|
||||
registered_at:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
description: Время регистрации события
|
||||
example: "2023-05-04T08:09:53.852916Z"
|
||||
instance_path:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Путь сущности (ltree)
|
||||
example: "1.79899.80131"
|
||||
target_id:
|
||||
type: integer
|
||||
format: uint64
|
||||
nullable: true
|
||||
description: ID цели события
|
||||
company_id:
|
||||
type: integer
|
||||
format: uint64
|
||||
nullable: true
|
||||
description: ID компании (может обогащаться воркером)
|
||||
example: 1
|
||||
metadata:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
description: Произвольные дополнительные данные о событии
|
||||
example: { "document_name": "КСГ.pdf", "count_bundle": 3 }
|
||||
message:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Произвольное сообщение
|
||||
example: "bundle was deleted from document"
|
||||
status:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Подстатус события
|
||||
example: "delete_bundle"
|
||||
resource_uuid:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
description: UUID связанного ресурса
|
||||
target_path:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Путь цели (ltree)
|
||||
required: [event_name, model_name]
|
||||
|
||||
# ---- Запросы ----
|
||||
SystemLogCreateRequest:
|
||||
type: object
|
||||
description: >
|
||||
Пакет записей для создания. Для каждой записи обязательно ровно одно из
|
||||
instance_id / instance_uuid.
|
||||
properties:
|
||||
system_logs:
|
||||
type: array
|
||||
minItems: 1
|
||||
items: { $ref: '#/components/schemas/SystemLog' }
|
||||
required: [system_logs]
|
||||
|
||||
SystemLogFilter:
|
||||
type: object
|
||||
description: Набор фильтров выборки (`entity.SystemLogFilter`).
|
||||
properties:
|
||||
limit: { type: integer, format: uint64, default: 100 }
|
||||
offset: { type: integer, format: uint64, default: 0 }
|
||||
actor_ids:
|
||||
type: array
|
||||
items: { type: integer, format: uint64 }
|
||||
event_names:
|
||||
type: array
|
||||
items: { type: string }
|
||||
model_names:
|
||||
type: array
|
||||
items: { type: string }
|
||||
instance_ids:
|
||||
type: array
|
||||
items: { type: integer, format: uint64 }
|
||||
instance_uuids:
|
||||
type: array
|
||||
items: { type: string, format: uuid }
|
||||
registered_at_gte: { type: string, format: date-time, nullable: true }
|
||||
registered_at_lte: { type: string, format: date-time, nullable: true }
|
||||
instance_path: { type: string, nullable: true }
|
||||
target_ids:
|
||||
type: array
|
||||
items: { type: integer, format: uint64 }
|
||||
target_path: { type: string, nullable: true }
|
||||
company_ids:
|
||||
type: array
|
||||
items: { type: integer, format: uint64 }
|
||||
statuses:
|
||||
type: array
|
||||
items: { type: string }
|
||||
message: { type: string, nullable: true }
|
||||
metadata:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
resource_uuids:
|
||||
type: array
|
||||
items: { type: string, format: uuid }
|
||||
is_processed_by_worker: { type: boolean, nullable: true }
|
||||
|
||||
SystemLogSearchRequest:
|
||||
type: object
|
||||
description: Тело запроса поиска (`SearchParams` в `dto.go`).
|
||||
properties:
|
||||
limit: { type: integer, format: uint64, default: 100 }
|
||||
offset: { type: integer, format: uint64, default: 0 }
|
||||
filters: { $ref: '#/components/schemas/SystemLogFilter' }
|
||||
|
||||
# ---- Ответы ----
|
||||
SystemLogListResponse:
|
||||
type: object
|
||||
description: Ответ списочной выборки (`entity.SystemLogRecordsRequest`).
|
||||
properties:
|
||||
count: { type: integer, format: uint64, example: 1226 }
|
||||
limit: { type: integer, format: uint64, nullable: true, example: 100 }
|
||||
offset: { type: integer, format: uint64, nullable: true, example: 0 }
|
||||
next:
|
||||
type: string
|
||||
nullable: true
|
||||
example: "http://localhost:8888/api/v0/system_log?limit=100&offset=100"
|
||||
prev:
|
||||
type: string
|
||||
nullable: true
|
||||
result:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/SystemLog' }
|
||||
required: [count, result]
|
||||
|
||||
SystemLogSearchResponse:
|
||||
type: object
|
||||
description: Ответ поиска (`entity.SystemLogRecordsSearch`) — без next/prev.
|
||||
properties:
|
||||
count: { type: integer, format: uint64, example: 1226 }
|
||||
limit: { type: integer, format: uint64, nullable: true, example: 100 }
|
||||
offset: { type: integer, format: uint64, nullable: true, example: 0 }
|
||||
result:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/SystemLog' }
|
||||
required: [count, result]
|
||||
Loading…
Reference in New Issue
Block a user