diff --git a/api/openapi.yaml b/api/openapi.yaml
index c18a19e..25dea2c 100644
--- a/api/openapi.yaml
+++ b/api/openapi.yaml
@@ -87,6 +87,51 @@ paths:
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: Принять идемпотентную отметку терминала
@@ -165,6 +210,40 @@ components:
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
diff --git a/docs/DESIGN-BRIEF-MANAGER-PORTAL.md b/docs/DESIGN-BRIEF-MANAGER-PORTAL.md
new file mode 100644
index 0000000..b129425
--- /dev/null
+++ b/docs/DESIGN-BRIEF-MANAGER-PORTAL.md
@@ -0,0 +1,15 @@
+# Design brief: кабинет руководителя
+
+- **Назначение:** ежедневный контроль присутствия, сотрудников и ручное заполнение табеля руководителем небольшой организации.
+- **Контекст:** защищённый операционный кабинет, а не маркетинговая страница.
+- **Направление:** спокойный плотный рабочий интерфейс с природной зелёной основой и золотым акцентом бренда Krona.
+- **Отличительная идея:** хронология отметок и табель остаются главным рабочим полотном, а управление сотрудниками доступно рядом и не уводит на отдельную техническую страницу.
+- **Ограничения:** существующий Fastify/PWA без нового frontend-фреймворка; адаптивность от мобильного браузера до рабочего монитора; клавиатурная навигация; reduced motion; никакой биометрии и секретов в браузере.
+
+## Локальная система
+
+- Цвета: тёплый рабочий фон, светлые поверхности, зелёный primary, золотой brand accent, семантические danger/info состояния.
+- Типографика: Georgia для крупных смысловых заголовков, Segoe UI для плотных управляющих элементов и таблиц.
+- Плотность: 44 px минимальная высота интерактивного элемента, компактные строки таблицы, адаптивный toolbar.
+- Формы: явные подписи, видимый focus, диалог для карточки сотрудника, встроенная строка создания записи табеля.
+- Движение: только короткие переходы состояния; полностью отключается через `prefers-reduced-motion`.
diff --git a/src/portal-ui.ts b/src/portal-ui.ts
index dbee8e5..085d781 100644
--- a/src/portal-ui.ts
+++ b/src/portal-ui.ts
@@ -43,20 +43,21 @@ export const portalHtml = `
Последние события
Отметки терминала
● в реальном времени
-
+
- Учёт времени
Табель за 40 дней
Изменения сохраняет руководитель| Дата | Сотрудник | Часы | Статус | Примечание | |
|---|
+ Учёт времени
Табель за 40 дней
Изменения сохраняет руководитель| Дата | Сотрудник | Часы | Статус | Примечание | |
|---|
+