PROD-port backend #742 основан на master 4c49f5918e571708f872c532b1f5154fc2a03428.
Сохранены namespace project-analytics и поле current_project_application.
Отсутствующие на PROD DEV-имена helpers не добавляются как копии: виджет использует
существующие селекторы legacy Project; React manager-overview не участвует.
Результаты нового production-прогона фиксируются в PR; исторические DEV-проверки
ниже не заменяют проверку PROD-ветки.
GET /programs/{id}/analytics-widget/, обязательная аутентификация.
Параметры role, user_id и project_id не используются для авторизации или выбора проекта.
GET не изменяет бизнес-данные. Ответ содержит только ветвь разрешённой роли:
{
"program_id": 12,
"role": "participant",
"is_competitive": true,
"participant": {
"participant_project": { "id": 5, "name": "StudyFlow", "program_link_id": 34 },
"case_provided": true,
"case_name": "Цифровой сервис",
"stage": "review",
"submission_open": true
}
}Пример иллюстрирует форму, значения не являются данными DEV. Остальные ветви:
organizer:participants,projects,submitted_solutions,participants_without_project.expert:mode(distributed/open),assigned,remaining,evaluation_ends(ISO datetime либо null).participant_projectиcase_nameмогут быть null.stage:none,not_submitted,submitted,review,evaluated,not_applicable.- Неприменимые счётчики — null: open assigned/remaining; неконкурсные submitted_solutions и персональные distributed-счётчики. Реальный срок оценивания передаётся также для open.
401 — нет входа; 403 — нет роли в этой программе; 404 — программа отсутствует; 409 — противоречивые связи команды, не выбор первого проекта. Angular не отображает raw response body и не подменяет ошибку нулями.
| Показатель | Источник и правило | Права / изменение |
|---|---|---|
| Роль | program.is_manager(user) → program.experts → PartnerProgramUserProfile |
Только текущая программа; global staff/user_type, наличие назначений и клиентские claims не дают роль |
| Проект команды | PartnerProgramProject текущей программы; Project.leader либо Exists Collaborator | Новый локальный selector; максимум две строки для обнаружения несоответствия правилу одной команды. Один проект без выбора |
| Кейс | get_program_case_field: точный name="case"; PartnerProgramFieldValue текущей связи |
Нет fallback по label, первому option, глобальному Project или другой программе |
| Участники и без проектов | _participant_metrics и participants_without_team_rows из project_analytics |
Distinct user; без проекта = нет лидерства и Collaborator на проекте программы; черновик учитывается |
| Проекты и решения | SQL aggregate над _annotated_solution_rows из project_analytics |
Единица учёта — PartnerProgramProject; отправленные — submitted-связи, не пользователи. Большая аналитика не сериализуется |
| Этап проекта | _annotated_solution_rows основной legacy-аналитики |
Неподанный → not_submitted; submitted без начала → submitted; назначение/начатая оценка → review; общая итоговая классификация → evaluated |
| Остаток эксперта | annotated_assignment_queryset, фильтр текущих program/expert, SQL aggregate |
Незавершённые назначения, включая not_ready, а не число незаполненных критериев |
| Срок | PartnerProgram.datetime_evaluation_ends |
Не срок подачи или окончания программы |
Distributed completion остаётся общим: submitted-связь, ненулевой набор критериев и заполнение всех критериев назначения; для проекта должны завершиться все назначения. Записанная допустимая оценка 0 считается заполненной. Неотправленный проект не завершён даже при существующих оценках.
В open сохранено существующее правило основной аналитики: ProjectScore по критерию программы даёт проекту evaluated. Это не новая формула виджета. Назначения и персональный остаток в open не выдумываются; frontend сохраняет переход в оценивание и однократно показывает реальный срок.
Дедлайн не участвует в определении оценённости. Баллы, личности экспертов и закрытые результаты участнику не сериализуются. Неконкурсная программа не получает искусственную обязательную сдачу.
Используются только Angular-модели Project, Collaborator, PartnerProgramProject, PartnerProgramUserProfile, Expert, ProjectExpertAssignment, Criteria, ProjectScore и существующие поля программы.
На PROD существующее поле current_project_application остаётся legacy-контрактом лидера с прежней семантикой. DEV-имя current_application не добавляется и не переименовывает PROD-контракт. Для члена команды null в этом поле не влияет на новый participant_project. Просмотр виджета не даёт права редактировать поля или отправлять проект вместо лидера.
React-модели Application, Team, Submission, SubmissionExpertAssignment, Evaluation, их serializers/services/endpoints не используются и не изменяются. Менеджерские API не открываются другим ролям.
В существующий program detail добавлен только контекстный boolean is_user_expert; он не раскрывает description/links незарегистрированному эксперту. Правила регистрации, выбора/сохранения case, сдачи, назначений, завершения и публикации сохранены. Нет миграций, зависимостей или изменений CI/Docker/workflows.
Сервис использует общие SQL-агрегации. Не сериализует большую аналитику и не загружает проекты/регистрации в браузер. Тест проверяет постоянное число SQL-запросов при росте числа проектов и отсутствие INSERT/UPDATE/DELETE.
Python 3.11, существующее Poetry-окружение. Локальные SQLite и PostgreSQL 18; production/DEV базы не использовались.
DEBUG=True python manage.py test partner_programs.tests.test_role_widget_api partner_programs.tests.test_program_detail partner_programs.tests.test_program_link_fields_api partner_programs.tests.test_manager_analytics_api partner_programs.tests.test_assignment_analytics_api project_rates.tests --noinputTargeted: 120 тестов PASS. Новые 15 тестов проверяют роли и приоритет, эксперта без регистрации/назначений, чужую программу, manager-only API, лидера/члена команды, несколько программ с разными case/status, неизменность current_application и прав сдачи, integrity 409, точное поле case, distributed/open, 0/partial/full/not_ready, черновики и командную метрику, изоляцию назначений, реальный дедлайн, bounded SQL/read-only.
Уникальность регистраций уже обеспечена схемой: тест проверяет отклонение дубликата и единственный учёт пользователя. Ограничения БД ради теста не менялись; общая аналитика сохраняет Count(distinct user).
| Команда | Фактический результат |
|---|---|
DEBUG=True python manage.py test --noinput (SQLite) |
849 тестов, OK (skipped=4), 570,439 с. После тестов exit 1: WinError 32 при удалении test_db.sqlite3 |
python manage.py test --noinput с временным settings на основе procollab.settings_ci (PostgreSQL) |
849 тестов, 1 failure: feed.tests.test_feed_api.FeedAPITests.test_feed_returns_project_news_as_news_content, ожидалось news, получено project. Teardown также встретил 21 незакрытое соединение; после завершения процесса временная БД удалена |
Тот же feed-тест отдельно на исходном ed5244bd..., PostgreSQL |
PASS. Причина сбоя полного прогона не установлена; полный suite не объявляется успешным, feed-код не менялся |
python -m flake8 всех tracked Python и отдельно новых файлов |
PASS |
python -m black --check новых файлов и urls |
PASS |
DEBUG=True python manage.py check |
0 issues |
DEBUG=True python manage.py makemigrations --check --dry-run |
No changes detected |
python -m mypy partner_programs/services/role_analytics.py partner_programs/serializers/role_analytics.py partner_programs/widget_views.py |
Не выполнен typecheck: существующий mypy.ini объединяет две строки plugins в один import (mypy_django_plugin.main\nmypy_drf_plugin.main), exit 2. Конфигурация не менялась |
git diff --check |
PASS |
Скриншоты трёх ролей/нулевых состояний и сравнение исходной геометрии находятся в парном Angular PR, docs/program-role-widget/README.md. Браузерный smoke использует реальные Angular-компоненты и локальные fixtures; живой DEV вход/сдача/оценивание в браузере не проверялись.
Сначала backend-контракт и detail-флаг, затем Angular-виджет. Изменение read-only, миграций нет. Фактическое состояние релиза и новый полный прогон PROD-ветки фиксируются отдельно в PR и отчёте развёртывания.