34 KiB
User Reader — документация для разработчиков
HTTP-сервис на FastAPI, читает данные Merakomis из MySQL и отдаёт JSON. Предназначен для потребления другими микросервисами и внешними приложениями: синхронизация каталога сотрудников, справочники проектов, сводки трудозатрат, запись табеля.
Интерактивная схема: /docs (Swagger UI), /redoc.
Справочник только по API, доступу и работе с эндпоинтами: docs/user-reader-api.md.
Содержание
- Быстрый старт для интеграции
- Сеть и развёртывание
- Аутентификация
- Общие соглашения API
- Модель данных Merakomis
- Справочник эндпоинтов
- Сотрудники
- Трудозатраты (read)
- Табель (read / write)
- Сценарии интеграции
- Коды ошибок
- Примеры запросов
- Запуск и сборка
Быстрый старт для интеграции
Минимальный цикл подключения другого сервиса:
- Проверить доступность —
GET /api/health(без ключа). - Узнать схему сотрудников —
GET /api/metaс API-ключом. - Синхронизировать сотрудников —
GET /api/employeesили инкрементGET /api/employees/delta. - Получить сводку часов за период —
GET /api/work-report?date_from=…&date_to=…. - (Опционально) Записать часы —
PUT /api/time-entriesс заголовкамиX-Api-KeyиX-Acting-Emp-Id.
Ваш сервис user-reader (:8090) MySQL
| X-Api-Key: … | |
| GET /api/work-report -------->| SELECT tMerakomisTime … |
|<-------- JSON items -----------| |
Рекомендуемые эндпоинты для интеграции:
| Задача | Эндпоинт |
|---|---|
| Каталог сотрудников | /api/employees, /api/employees/delta |
| Сводка часов (основной контракт) | /api/work-report |
| Сводка по проектам | /api/project-report |
| Участники проектов | /api/project-members |
| Запись в состав проекта | PUT /api/project-members |
| Разделы проекта (для формы) | /api/project-sections |
| Запись часов | PUT /api/time-entries |
Сеть и развёртывание
Docker Compose (этот репозиторий)
| Сервис | Контейнер | Порт на хосте | Внутри сети compose |
|---|---|---|---|
| user-reader | meraproject-user-reader |
8090 | http://user-reader:8090 |
| MySQL | meraproject-mysqldb |
3307 | db:3306 |
Переменные окружения user-reader заданы в docker-compose.yml:
MYSQL_HOST: db
MYSQL_DATABASE: j7508239_tracker
USER_READER_API_KEY: "local-dev-key-change-in-prod" # сменить на проде
С другого контейнера в той же compose-сети обращайтесь к http://user-reader:8090.
С хоста или другого сервера — http://<IP_хоста>:8090.
CORS: включён для всех origin (*). Браузерные клиенты с другого домена могут вызывать API при наличии ключа.
uvicorn локально
cd services/user-reader
pip install -r requirements.txt
# задать MYSQL_* и USER_READER_API_KEY
uvicorn app.main:app --host 0.0.0.0 --port 8090
Статические страницы-превью (без отдельного фронтенда)
| URL | Назначение |
|---|---|
GET / |
Сотрудники |
GET /labor |
Проекты, разделы, сырые записи |
GET /summary |
UI над /api/work-report |
GET /project-report |
UI над /api/project-report |
GET /time-entry |
Форма записи часов (PUT /api/time-entries) |
GET /project-member |
Форма записи состава (PUT /api/project-members) |
Аутентификация
Два независимых уровня.
1. Service-to-service: API-ключ
Если задан непустой USER_READER_API_KEY, все эндпоинты с пометкой «защищённый» требуют:
- заголовок
X-Api-Key: <ключ>, или - заголовок
Authorization: Bearer <ключ>
Если ключ не задан (пустая строка) — проверки нет (только для локальной отладки).
Ответ при ошибке: 401, тело FastAPI {"detail": "…"}.
2. Табель: идентичность сотрудника
Эндпоинты записи и чтения табеля (кроме справочников) дополнительно требуют:
| Заголовок / поле | Назначение |
|---|---|
X-Acting-Emp-Id |
Кто действует (аналог PHP-сессии fg_emp_id) |
emp_id в query/body |
За кого операция; если опущен → равен acting |
Права проверяются по правилам Merakomis (админ, РП, делегат и т.д.) — см. GET /api/labor/permissions.
Общие соглашения API
Формат ответов
- Кодировка: UTF-8, тело — JSON.
- Даты в query:
YYYY-MM-DD. - Пагинация:
limit+offset; в ответе обычно естьtotal,count. - Числа с плавающей точкой (часы): до 2 знаков в агрегатах.
Сериализация значений из MySQL
| Тип MySQL | JSON |
|---|---|
datetime |
ISO-строка с пробелом и секундами |
date |
YYYY-MM-DD |
Decimal |
float |
bytes |
UTF-8 с заменой ошибок |
Секретные поля
В выдаче сотрудников никогда не попадают колонки с паролями: суффикс _pass, подстроки password, secret.
Имена полей
- В таблицах MySQL колонки имеют префикс
tMerakomisProject_codeи т.п. - В JSON API — короткие алиасы:
code,project_name,step_name.
Модель данных Merakomis
Ключевые таблицы (физические имена в MySQL обычно в нижнем регистре).
| Логическое имя | Таблица | Назначение |
|---|---|---|
| Сотрудник | tMerakomisEmp |
Каталог сотрудников |
| Проект | tMerakomisProject |
Проекты компании |
| Стадия проекта | tMerakomisDStep |
Справочник стадий (ПД, РД, К…) |
| Раздел | tMerakomisDSection |
Разделы внутри проекта (ОВ1, ТХ…) |
| Участник команды | tMerakomisTeamMember |
Сотрудник ↔ команда ↔ раздел |
| Запись времени | tMerakomisTime |
Часы по дням |
| Отсутствие | tMerakomisTimeAbsence |
Отпуск, больничный… |
| Тип отсутствия | tMerakomisDAbsence |
Справочник типов |
| Должность / отдел | tMerakomisPost → tMerakomisDDepartment |
Орготдел сотрудника (АР, ОВ…) |
Стадия проекта (step / step_name)
- В проекте: колонка
tMerakomisProject_step→ в API полеstep(целое id). - Название стадии: справочник
tMerakomisDStep(id,name,text).name— краткое обозначение: ПД, РД, К, АН…text— полное описание («Проектная документация»).
- В эндпоинтах, где есть
project_name, дополнительно отдаётсяstep_name(краткое название из справочника; пустая строка, если стадия не задана).
Статус проекта (status / status_name / archive)
- В проекте:
tMerakomisProject_status→ в APIstatus(целое 0…3),status_name— подпись из портала Merakomis (eStatus.php). - Архив:
tMerakomisProject_archive(0/1),tMerakomisProject_archive_date→archive_date(YYYY-MM-DDилиnull). - В эндпоинтах с
project_name(сводки, состав команды) поляstatus,status_name,archive,archive_dateидут рядом со стадией.
status |
status_name |
|---|---|
0 |
Не определён |
1 |
В работе |
2 |
Завершён |
3 |
Пауза |
Не путать: поле
stepвtMerakomisDSection— фильтр разделов по стадии, это другая сущность.
Переработки (is_over)
is_over |
Смысл |
|---|---|
0 |
Рабочие часы |
1 |
Переработка |
В агрегатах:
over1— переработка в рабочий день;over2— переработка в выходной/праздник или день отсутствия;over=over1+over2;total=hours+over.
Раздел проекта в сводках берётся из членства в команде (TeamMember.section), а не из строки времени.
Справочник эндпоинтов
| Метод | Путь | Ключ | Acting | Назначение |
|---|---|---|---|---|
| GET | /api/health |
— | — | Живость и БД |
| GET | /api/meta |
✓ | — | Мета сотрудников |
| GET | /api/employees |
✓ | — | Список сотрудников |
| GET | /api/employees/delta |
✓ | — | Инкремент сотрудников |
| GET | /api/labor/meta |
✓ | — | Имена таблиц трудозатрат |
| GET | /api/projects |
✓ | — | Справочник проектов |
| GET | /api/sections |
✓ | — | Справочник разделов |
| GET | /api/project-members |
✓ | — | Участники проектов |
| GET | /api/project-sections |
✓ | — | Разделы, допустимые на проекте |
| GET | /api/member-roles |
✓ | — | Справочник ролей в команде |
| GET | /api/time-entries |
✓ | — | Сырые записи времени |
| GET | /api/labor-summary |
✓ | — | Агрегат (внутренние поля) |
| GET | /api/work-report |
✓ | — | Сводка для интеграции |
| GET | /api/project-report |
✓ | — | Сводка по проектам |
| GET | /api/calendar-days |
✓ | — | Производственный календарь |
| GET | /api/absence-types |
✓ | — | Типы отсутствий |
| GET | /api/labor/permissions |
✓ | ✓ | Проверка прав |
| GET | /api/time-summary |
✓ | ✓ | Сводка табеля (месяц/год) |
| GET | /api/time-calendar |
✓ | ✓ | Данные календаря табеля |
| PUT | /api/time-entries |
✓ | ✓ | Запись часов |
| PUT | /api/project-members |
✓ | ✓ | Запись состава проекта |
| POST | /api/batch |
✓ | — | Пакет до 25 GET-запросов |
| PUT | /api/absences |
✓ | ✓ | Отсутствия по датам |
| PUT | /api/absences/range |
✓ | ✓ | Отсутствия за диапазон |
✓ в колонке «Ключ» = нужен USER_READER_API_KEY, если он задан в окружении.
✓ в колонке «Acting» = обязателен заголовок X-Acting-Emp-Id.
Переменные окружения
| Переменная | Назначение |
|---|---|
MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE |
Подключение к MySQL |
USER_READER_API_KEY |
Service-to-service ключ; пусто = без проверки |
EMP_TABLE |
Явное имя таблицы сотрудников |
USER_TABLE / USER_READER_FALLBACK_TABLE |
Резервная таблица, если нет tMerakomisEmp |
DEBUG |
1 — в ответе 500 может быть traceback |
Сотрудники
Режимы схемы таблицы
Сервис определяет таблицу через resolve_emp_table():
merakomis_emp— колонкиtMerakomisEmp_*; в JSON поля без префикса. Фильтрremoved = 0, если колонка есть.generic_user_table— произвольная таблица; все несекретные колонки.
PHP-ориентир: php_model: "themes/merakomis/emp/model.php".
GET /api/health
Без API-ключа.
{ "ok": true, "db": true, "database": "j7508239_tracker" }
GET /api/meta — защищённый
Метаданные: физическая таблица, режим схемы, поля выдачи, колонка для delta.
| Поле | Описание |
|---|---|
schema_mode |
merakomis_emp или generic_user_table |
delta_field |
Поле для инкрементальной синхронизации (updated или эвристика) |
selected_fields |
Имена полей в /api/employees |
where_removed |
Колонка «удалён» в БД |
GET /api/employees — защищённый
| Параметр | По умолчанию | Ограничения |
|---|---|---|
limit |
100 |
1…500 |
offset |
0 |
≥ 0 |
Ответ: total, limit, offset, items[].
Дополнительные поля (Merakomis):
| Поле | Описание |
|---|---|
department |
Коды отдела через запятую: АР, ГП, ОВ… |
department_codes |
Массив кодов |
departments |
department_id, name, short, code |
staffing_ids, staffing_names, staffing_title, staffings |
Должность (Архитектор, ГИП, ГАП…) из tMerakomisDStaffing |
staffing |
Сырой JSON-массив id должностей в БД |
Источник отделов: tMerakomisPost → tMerakomisDDepartment. Поле roles — не должность, а служебный фильтр подразделения в портале.
GET /api/employees/delta — защищённый
Инкремент: строки, у которых время изменения строго больше since_updated (Unix, секунды).
| Параметр | По умолчанию |
|---|---|
since_updated |
0 |
limit |
500 |
Ответ: since_updated, max_updated, delta_column, count, items.
Цикл синхронизации:
since = 0
loop:
GET /api/employees/delta?since_updated={since}&limit=500
обработать items
since = max_updated
пока count == limit
Трудозатраты (read)
Мета-информация: GET /api/labor/meta — физические имена таблиц.
GET /api/projects — защищённый
Справочник tMerakomisProject.
| Параметр | По умолчанию | Описание |
|---|---|---|
limit |
100 |
1…500 |
offset |
0 |
|
include_removed |
false |
Включать removed = 1 |
include_archive |
true |
Не фильтровать архивные |
Поля items: id, code, name, director, step (id стадии), status, status_name, team, archive, archive_date, removed, date, date_end.
Для человекочитаемой стадии и статуса используйте join через /api/project-members или агрегаты ниже (step_name, status_name).
GET /api/sections — защищённый
Справочник tMerakomisDSection: id, name, parent, step.
| Параметр | Описание |
|---|---|
step |
Фильтр разделов по стадии (id из tMerakomisDSection.step) |
GET /api/project-members — защищённый
Связь сотрудник ↔ проект ↔ раздел команды.
| Параметр | По умолчанию | Описание |
|---|---|---|
project_id, emp_id |
— | Фильтры |
active_only |
true |
Только активные в команде |
limit |
100 |
1…500 |
offset |
0 |
Поля items:
| Поле | Описание |
|---|---|
member_id |
id записи TeamMember |
emp_id, emp_name |
Сотрудник |
project_id, project_code, project_name |
Проект |
step_name |
Краткое название стадии (ПД, РД…) |
status, status_name |
Статус проекта |
archive, archive_date |
Архив и дата архивации |
section_id, section_name |
Раздел в команде |
role |
Роль в команде |
active |
Активен в команде |
GET /api/project-sections — защищённый
Разделы, допустимые для проекта (tMerakomisProjectSection → tMerakomisDSection).
| Параметр | Обязательно |
|---|---|
project_id |
да |
Ответ: project_id, total, items[] с section_id, section_name.
GET /api/member-roles — защищённый
Справочник ролей в команде (порт eMemberRole).
| Параметр | Описание |
|---|---|
role |
Включить архивную роль при редактировании |
Ответ: total, items[] с id, title.
PUT /api/project-members — защищённый + Acting
Upsert участника команды: если (team, emp) уже есть — обновление, иначе вставка.
Тело:
{
"project_id": 86,
"emp_id": 46,
"section_id": 12,
"role": 22,
"active": true,
"text": ""
}
| Поле | Обязательно | Описание |
|---|---|---|
project_id |
да | id проекта |
emp_id |
да | id сотрудника |
section_id |
да | id из GET /api/project-sections |
role |
да | id из GET /api/member-roles |
active |
По умолчанию true |
|
text |
Комментарий |
Права: порт Rules::isRwMember (админ, РП, ГИП, директор отдела).
Ответ 200: ok: true и поля как у элемента GET /api/project-members.
GET /api/time-entries — защищённый
Сырые строки tMerakomisTime.
| Параметр | Описание |
|---|---|
date_from, date_to |
YYYY-MM-DD |
emp_id, project_id |
Фильтры |
is_over |
0 — рабочие, 1 — переработка |
limit |
1…2000 (по умолчанию 500) |
Поля: id, emp, project, date, duration, is_over.
GET /api/work-report — защищённый ⭐ основной контракт
Агрегат за период: сотрудник × проект с орготделом, разделом, стадией и часами.
Обязательно: date_from, date_to (YYYY-MM-DD, включительно).
| Параметр | По умолчанию | Описание |
|---|---|---|
emp_id |
— | Фильтр по сотруднику |
project_id |
— | Фильтр по проекту |
limit |
500 |
1…2000 |
offset |
0 |
Пагинация |
Поля элемента items:
| Поле | Тип | Описание |
|---|---|---|
id |
int | ID сотрудника |
employee |
string | ФИО |
department |
string | null | Орготдел (коды через запятую) |
staffing_title |
string | null | Должность (Архитектор, ГИП…) |
section |
string | null | Раздел в проекте |
project_code |
string | Код проекта |
step_name |
string | Стадия (ПД, РД…) |
status |
int | null | Код статуса проекта |
status_name |
string | null | Подпись статуса |
archive |
int | 0 / 1 |
archive_date |
string | null | Дата архивации |
project_name |
string | Название проекта |
hours, over, over1, over2, total |
number | Часы (см. модель данных) |
Пример строки:
{
"id": 46,
"employee": "Агапова Анастасия Михайловна",
"department": "ОВ",
"staffing_title": "Инженер",
"section": "ОВ1",
"project_code": "2025-0016",
"step_name": "РД",
"status": 1,
"status_name": "В работе",
"archive": 0,
"archive_date": null,
"project_name": "ЖК Машкова",
"hours": 8.0,
"over": 0.0,
"over1": 0.0,
"over2": 0.0,
"total": 8.0
}
Пагинация длинного периода: увеличивайте offset шагами до limit пока offset + count < total. Delta-режима нет — каждый запрос пересчитывает период.
GET /api/project-report — защищённый
Суммарные часы по проекту с разбивкой по орготделу и разделу (все сотрудники).
Обязательно: date_from, date_to.
| Параметр | Описание |
|---|---|
project_id |
Фильтр по проекту |
limit, offset |
Пагинация (1…2000) |
Поля items: id (project_id), project_code, step_name, status, status_name, archive, archive_date, project_name, department, section, hours, over, over1, over2, total.
Одна строка = уникальная тройка проект + department + section.
GET /api/labor-summary — защищённый
Низкоуровневый агрегат (те же расчёты, что у /api/work-report), с внутренними id Merakomis. Для интеграции предпочтительнее /api/work-report.
Поля строки: emp_id, emp_name, department, staffing_title, project_id, project_code, step_name, status, status_name, archive, archive_date, project_name, section_id, section_name, role, hours, over, over1, over2, total.
Табель (read / write)
Полная спецификация write-логики и портирования PHP: docs/change-proposal-labor-api-write.md.
GET /api/calendar-days — защищённый
Производственный календарь за период.
| Параметр | Обязательно |
|---|---|
date_from, date_to |
да |
GET /api/absence-types — защищённый
Справочник типов отсутствий. В items всегда есть элемент id: 0 («снять отсутствие»).
GET /api/labor/permissions — защищённый + Acting
| Параметр | Описание |
|---|---|
target_emp_id |
За кого проверяем (обязательно) |
project_id |
Для проверки записи часов в проект |
Ответ: can_read, can_write_time, can_write_absence, can_write_member, is_admin, is_delegate_writer.
| Параметр | Описание |
|---|---|
target_emp_id |
Обязательно |
project_id |
Для can_write_time и can_write_member |
member_id |
Опционально, для проверки прав на редактирование записи |
GET /api/time-calendar — защищённый + Acting
Данные календаря табеля сотрудника (формат, близкий к PHP getTimeTable).
| Параметр | По умолчанию | Описание |
|---|---|---|
emp_id |
acting | Чей табель |
project_id |
0 |
0 — сводный табель; иначе — по проекту |
GET /api/time-summary — защищённый + Acting
Сводка за текущий месяц и год (блоки month, year с разбивкой по проектам).
PUT /api/time-entries — защищённый + Acting
Запись или обновление часов за день (аналог PHP addFromCalendar).
Тело (JSON):
{
"emp_id": 46,
"project_id": 86,
"date": "2026-06-10",
"time": 8,
"over": 0
}
| Поле | Описание |
|---|---|
emp_id |
Опционально; по умолчанию = acting |
project_id |
Обязательно |
date |
YYYY-MM-DD |
time |
Часы, 0…24 |
over |
0 — рабочие, 1 — переработка |
time: 0 удаляет запись за этот день/тип.
Ответ 200: ok, id, duration, info, limits (применённые лимиты дня).
PUT /api/absences — защищённый + Acting
{
"emp_id": 46,
"type": 3,
"dates": ["2026-06-10", "2026-06-11"]
}
type: 0 — снять отсутствие. При установке отсутствия рабочие часы за день удаляются.
PUT /api/absences/range — защищённый + Acting
{
"emp_id": 46,
"absence_id": 3,
"begin": "2026-06-10",
"end": "2026-06-20"
}
absence_id: 0 — очистить диапазон (удалить отсутствия и рабочие часы).
Сценарии интеграции
A. Периодическая синхронизация сотрудников
- Храните у себя
last_since_updated(Unix). - Вызывайте
/api/employees/delta?since_updated={last}&limit=500. - Upsert по
id; обновляйтеlast_since_updated = max_updated. - Раз в сутки — полная сверка через
/api/employeesс пагинацией.
B. Отчёт по трудозатратам за месяц
GET /api/work-report?date_from=2026-05-01&date_to=2026-05-31&fetch_all=true— один запрос на весь период.- Или
POST /api/batchс несколькими периодами вrequests[]. - Группируйте у себя по
department,step_name,project_codeпри необходимости.
C. Список проектов сотрудника для UI
GET /api/project-members?emp_id={id}&active_only=true — в ответе project_code, step_name, status_name, archive, project_name.
D. Запись часов из мобильного/бота
- Проверить права:
GET /api/labor/permissions?target_emp_id={id}&project_id={pid}. - Записать:
PUT /api/time-entriesсX-Acting-Emp-Idи телом. - Обработать
403(нет прав),400(невалидная дата).
E. Сводка по проектам для руководства
GET /api/project-report?date_from=…&date_to=… — агрегат по проект + отдел + раздел.
F. Управление составом проекта из внешнего приложения
GET /api/project-sections?project_id={pid}— допустимые разделы.GET /api/member-roles— роли.GET /api/labor/permissions?target_emp_id={acting}&project_id={pid}→can_write_member.PUT /api/project-membersсX-Acting-Emp-Idи телом.- Проверка:
GET /api/project-members?project_id={pid}.
Коды ошибок
| Код | Когда |
|---|---|
400 |
Невалидные параметры, date_from > date_to, нет колонки для delta, нет X-Acting-Emp-Id |
401 |
Неверный или отсутствующий API-ключ |
403 |
Нет прав на табель / запись |
404 |
Сотрудник или проект не найден |
500 |
Ошибка MySQL, не найдена таблица Merakomis |
Write-эндпоинты часто возвращают структурированный detail:
{ "code": "forbidden", "message": "Нет прав на запись часов" }
Примеры запросов
Локальный ключ из docker-compose.yml: local-dev-key-change-in-prod.
Замените HOST на IP/имя хоста.
# Health (без ключа)
curl -s http://HOST:8090/api/health
# Мета сотрудников
curl -s -H "X-Api-Key: local-dev-key-change-in-prod" \
http://HOST:8090/api/meta
# Сводка часов (основной контракт интеграции)
curl -s -H "X-Api-Key: local-dev-key-change-in-prod" \
"http://HOST:8090/api/work-report?date_from=2026-05-01&date_to=2026-05-31&limit=2000"
# Участники проекта со стадией
curl -s -H "X-Api-Key: local-dev-key-change-in-prod" \
"http://HOST:8090/api/project-members?emp_id=46&active_only=true"
# Состав проекта: запись
curl -s -X PUT "http://HOST:8090/api/project-members" \
-H "X-Api-Key: local-dev-key-change-in-prod" \
-H "X-Acting-Emp-Id: 1" \
-H "Content-Type: application/json" \
-d '{"project_id":86,"emp_id":46,"section_id":12,"role":22,"active":true}'
# Инкремент сотрудников
curl -s -H "X-Api-Key: local-dev-key-change-in-prod" \
"http://HOST:8090/api/employees/delta?since_updated=0&limit=500"
# Запись часов
curl -s -X PUT "http://HOST:8090/api/time-entries" \
-H "X-Api-Key: local-dev-key-change-in-prod" \
-H "X-Acting-Emp-Id: 46" \
-H "Content-Type: application/json" \
-d '{"project_id":86,"date":"2026-06-10","time":8,"over":0}'
Пример на Python (httpx)
import httpx
BASE = "http://user-reader:8090"
HEADERS = {"X-Api-Key": "local-dev-key-change-in-prod"}
def fetch_work_report(date_from: str, date_to: str) -> list[dict]:
items: list[dict] = []
offset = 0
limit = 2000
while True:
r = httpx.get(
f"{BASE}/api/work-report",
headers=HEADERS,
params={
"date_from": date_from,
"date_to": date_to,
"limit": limit,
"offset": offset,
},
timeout=60.0,
)
r.raise_for_status()
data = r.json()
items.extend(data["items"])
offset += data["count"]
if offset >= data["total"]:
break
return items
Запуск и сборка
Зависимости: services/user-reader/requirements.txt.
Точка входа: app.main:app (uvicorn).
Исходники схем:
| Модуль | Назначение |
|---|---|
app/emp_schema.py |
Сотрудники |
app/merakomis_schema.py |
Проекты, время, стадии |
app/labor.py |
Read API трудозатрат |
app/labor_write.py |
Write API табеля |
app/project_members_read.py |
Read: project-sections, member-roles |
app/project_members_write.py |
Write: PUT project-members |
app/labor_calendar.py |
Read API табеля |
app/labor_permissions.py |
Права |
Сборка образа и ошибка failed to solve
При docker compose build user-reader сообщение failed to solve: python:... — Docker не смог скачать базовый образ с Hub.
Базовый образ: python:3.12-slim-bookworm.
Вариант A — есть интернет:
docker pull python:3.12-slim-bookworm
docker compose build user-reader
docker compose up -d --no-deps user-reader
Вариант B — сервер без Hub:
.\services\user-reader\scripts\export-image.ps1
# скопировать user-reader-image.tar на сервер
.\services\user-reader\scripts\import-image.ps1
Вариант C — зеркало registry в daemon.json.
Связанные документы
| Документ | Содержание |
|---|---|
| docs/user-reader-api.md | API, доступ, эндпоинты, сценарии вызова |
docs/change-proposal-labor-api-write.md |
Детальная спецификация write API и портирования PHP |
docs/integration-external-app-employees.md |
Legacy PHP API (cookie); для новых интеграций используйте user-reader |