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] }