# Tasks: project-members-write ## 1. Schema and reference data - [x] 1.1 Добавить `PROJECT_SECTION_TABLE` и поле `text` в `merakomis_schema.py` (если колонка есть в БД) - [x] 1.2 Создать `member_roles.py` — статический справочник ролей из `eMemberRole.php` (id, title, archive) - [x] 1.3 Helper `_project_section_ids(cur, db, project_id)` и `_fetch_member_by_id` для ответа PUT ## 2. Permissions - [x] 2.1 Порт `getRoleInProject(acting, project_id)` в `labor_permissions.py` - [x] 2.2 Реализовать `can_write_project_member(...)` по `Rules::isRwMember` - [x] 2.3 Расширить `GET /api/labor/permissions` — query `member_id`, `target_emp_id`, ответ `can_write_member` ## 3. Read endpoints - [x] 3.1 Создать `project_members_read.py` с `GET /api/project-sections` - [x] 3.2 Добавить `GET /api/member-roles` в `project_members_read.py` - [x] 3.3 Подключить роутер в `main.py` ## 4. Write endpoint - [x] 4.1 Создать `project_members_write.py` — Pydantic-модель тела PUT - [x] 4.2 Валидация: project exists, emp not archived/removed, section in project, role > 0 - [x] 4.3 Upsert в `tMerakomisTeamMember` (resolve team из project; INSERT или UPDATE по team+emp) - [x] 4.4 Проверка `can_write_project_member` перед записью; ошибки 400/403/404 - [x] 4.5 Ответ PUT — тот же shape, что item `GET /api/project-members` - [x] 4.6 Подключить роутер write в `main.py` ## 5. Tests - [x] 5.1 Unit-тесты `can_write_project_member` (admin, РП, ГИП, dept director, deny) - [x] 5.2 Unit-тесты валидации section_id и archived employee - [x] 5.3 Unit-тест upsert logic (insert vs update) ## 6. Documentation and preview - [x] 6.1 Обновить `DEVELOPERS.md` — эндпоинты, матрица доступа, сценарий F «управление составом» - [x] 6.2 Обновить `docs/user-reader-api.md` — спецификация PUT, project-sections, member-roles, permissions - [x] 6.3 (Опционально) HTML-превью формы на `static/` по аналогии с `time-entry.html`