263 lines
9.3 KiB
YAML
263 lines
9.3 KiB
YAML
openapi: 3.1.0
|
||
info:
|
||
title: Krona Staff API
|
||
version: 0.2.5
|
||
description: API посещаемости Krona Staff для кабинета сотрудника, терминала и табеля руководителя.
|
||
license:
|
||
name: Proprietary
|
||
url: https://git.ochenstarik.ru/ochenstarik/krona-staff/src/branch/main/LICENSE
|
||
servers:
|
||
- url: /api/v1/staff
|
||
security: []
|
||
paths:
|
||
/live:
|
||
get:
|
||
summary: Check process liveness
|
||
operationId: getLiveness
|
||
tags: [Operations]
|
||
responses:
|
||
'200':
|
||
description: Process is alive
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Health' }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
/ready:
|
||
get:
|
||
summary: Check dependency readiness
|
||
operationId: getReadiness
|
||
tags: [Operations]
|
||
responses:
|
||
'200':
|
||
description: Required dependencies are ready
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Health' }
|
||
'503': { description: A required dependency is unavailable }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
/version:
|
||
get:
|
||
summary: Read runtime build identity
|
||
operationId: getVersion
|
||
tags: [Operations]
|
||
responses:
|
||
'200':
|
||
description: Runtime build identity
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Version' }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
/session:
|
||
post:
|
||
summary: Открыть защищённую сессию администратора
|
||
operationId: createStaffSession
|
||
tags: [Authentication]
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: false
|
||
required: [access_token]
|
||
properties:
|
||
access_token: { type: string, minLength: 32, maxLength: 4096, writeOnly: true }
|
||
responses:
|
||
'200':
|
||
description: Сессия открыта; токен перенесён в HttpOnly Secure cookie
|
||
'401': { description: Ключ недействителен }
|
||
'403': { description: Ключ не имеет прав администратора }
|
||
delete:
|
||
summary: Завершить сессию администратора
|
||
operationId: deleteStaffSession
|
||
tags: [Authentication]
|
||
responses:
|
||
'204': { description: Сессия завершена }
|
||
'403': { description: Запрос с постороннего сайта отклонён }
|
||
/portal:
|
||
get:
|
||
summary: Получить доступную пользователю сводку посещаемости и табеля
|
||
operationId: getStaffPortal
|
||
tags: [Attendance]
|
||
security: [{ bearerAuth: [] }]
|
||
responses:
|
||
'200':
|
||
description: Сводка с автоматическим ограничением данными текущего сотрудника
|
||
content:
|
||
application/json:
|
||
schema: { type: object }
|
||
'403': { description: Недостаточно прав }
|
||
/employees:
|
||
post:
|
||
summary: Добавить сотрудника
|
||
operationId: createStaffEmployee
|
||
tags: [Employees]
|
||
security: [{ bearerAuth: [] }]
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/EmployeeCreate'
|
||
responses:
|
||
'201':
|
||
description: Сотрудник создан
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Employee' }
|
||
'403': { description: Недостаточно прав }
|
||
'409': { description: Табельный номер уже используется }
|
||
/employees/{employeeId}:
|
||
patch:
|
||
summary: Изменить карточку или статус сотрудника
|
||
operationId: updateStaffEmployee
|
||
tags: [Employees]
|
||
security: [{ bearerAuth: [] }]
|
||
parameters:
|
||
- in: path
|
||
name: employeeId
|
||
required: true
|
||
schema: { $ref: '#/components/schemas/Ulid' }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/EmployeeUpdate'
|
||
responses:
|
||
'200':
|
||
description: Сотрудник изменён
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Employee' }
|
||
'403': { description: Недостаточно прав }
|
||
'404': { description: Сотрудник не найден }
|
||
/attendance/events:
|
||
post:
|
||
summary: Принять идемпотентную отметку терминала
|
||
operationId: recordAttendanceEvent
|
||
tags: [Attendance]
|
||
security: [{ bearerAuth: [] }]
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: false
|
||
required: [employee_id, event_type, occurred_at, source_event_id]
|
||
properties:
|
||
event_id: { $ref: '#/components/schemas/Ulid' }
|
||
employee_id: { $ref: '#/components/schemas/Ulid' }
|
||
event_type: { enum: [check_in, check_out] }
|
||
occurred_at: { type: string, format: date-time }
|
||
source_event_id: { type: string, minLength: 1, maxLength: 200 }
|
||
device_id: { $ref: '#/components/schemas/Ulid' }
|
||
responses:
|
||
'201': { description: Отметка принята }
|
||
'200': { description: Повтор уже принятой отметки }
|
||
'403': { description: Недостаточно прав }
|
||
/timesheets/{employeeId}/{workDate}:
|
||
put:
|
||
summary: Сохранить строку табеля
|
||
operationId: saveTimesheetEntry
|
||
tags: [Timesheet]
|
||
security: [{ bearerAuth: [] }]
|
||
parameters:
|
||
- in: path
|
||
name: employeeId
|
||
required: true
|
||
schema: { $ref: '#/components/schemas/Ulid' }
|
||
- in: path
|
||
name: workDate
|
||
required: true
|
||
schema: { type: string, format: date }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: false
|
||
required: [minutes_worked, status]
|
||
properties:
|
||
minutes_worked: { type: integer, minimum: 0, maximum: 1440 }
|
||
status: { enum: [draft, submitted, approved, rejected] }
|
||
note: { type: string, maxLength: 1000 }
|
||
responses:
|
||
'200': { description: Строка табеля сохранена }
|
||
'403': { description: Недостаточно прав }
|
||
components:
|
||
securitySchemes:
|
||
bearerAuth:
|
||
type: http
|
||
scheme: bearer
|
||
bearerFormat: JWT
|
||
responses:
|
||
BadRequest:
|
||
description: Invalid request
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Problem' }
|
||
schemas:
|
||
Ulid:
|
||
type: string
|
||
pattern: '^[0-9A-HJKMNP-TV-Z]{26}$'
|
||
examples: [01J00000000000000000000000]
|
||
Health:
|
||
type: object
|
||
additionalProperties: false
|
||
required: [status]
|
||
properties:
|
||
status: { type: string }
|
||
Employee:
|
||
type: object
|
||
additionalProperties: false
|
||
required: [id, personnel_number, display_name, position, gender, status]
|
||
properties:
|
||
id: { $ref: '#/components/schemas/Ulid' }
|
||
core_user_id:
|
||
oneOf:
|
||
- { $ref: '#/components/schemas/Ulid' }
|
||
- { type: 'null' }
|
||
personnel_number: { type: string }
|
||
display_name: { type: string }
|
||
position: { type: string }
|
||
gender: { enum: ['', male, female] }
|
||
status: { enum: [active, blocked, dismissed] }
|
||
EmployeeCreate:
|
||
type: object
|
||
additionalProperties: false
|
||
required: [personnel_number, display_name]
|
||
properties:
|
||
personnel_number: { type: string, minLength: 1, maxLength: 80 }
|
||
display_name: { type: string, minLength: 1, maxLength: 240 }
|
||
position: { type: string, maxLength: 160 }
|
||
gender: { enum: ['', male, female] }
|
||
EmployeeUpdate:
|
||
type: object
|
||
additionalProperties: false
|
||
minProperties: 1
|
||
properties:
|
||
personnel_number: { type: string, minLength: 1, maxLength: 80 }
|
||
display_name: { type: string, minLength: 1, maxLength: 240 }
|
||
position: { type: string, maxLength: 160 }
|
||
gender: { enum: ['', male, female] }
|
||
status: { enum: [active, blocked, dismissed] }
|
||
Problem:
|
||
type: object
|
||
additionalProperties: false
|
||
required: [type, title, status, trace_id]
|
||
properties:
|
||
type: { type: string, format: uri-reference }
|
||
title: { type: string }
|
||
status: { type: integer, minimum: 400, maximum: 599 }
|
||
trace_id: { $ref: '#/components/schemas/Ulid' }
|
||
Version:
|
||
type: object
|
||
additionalProperties: false
|
||
required: [name, version, mode]
|
||
properties:
|
||
name: { const: krona-staff }
|
||
version: { type: string }
|
||
mode: { enum: [standalone, platform] }
|