42 KiB
Backend Endpoints Competence Map Analytics
Назначение: спецификация backend-контракта для страницы
Все сервисы / Карта компетенций / Аналитическая панель.
Документ нужен как задача для backend-разработки. Цель: реализовать endpoint-ы, которые возвращают все данные аналитической панели по инновационным объединениям:
- значения фильтров;
- верхние KPI-карточки;
- состав инновационных объединений;
- аналитику по ОЭЗ;
- аналитику по технопаркам;
- аналитику по промышленным кластерам;
- рейтинги субъектов РФ;
- топ отраслей;
- временную динамику;
- численность сотрудников.
Принципы контракта
- аналитика страницы должна возвращаться одним page-level endpoint-ом;
- справочники фильтров должны возвращаться отдельным endpoint-ом;
- все значения должны возвращаться в raw-формате: number, string, boolean, null;
- проценты должны возвращаться числом
0..100, а не долей0..1; - даты должны возвращаться в ISO 8601 с timezone;
- каждый объект, который может использоваться для drilldown или ссылки, должен иметь стабильный
id; - все массивы должны возвращаться уже отсортированными;
- все KPI должны иметь стабильный
code; - все проценты должны иметь
numeratorиdenominator, если знаменатель известен; 0должен возвращаться как валидное значение, а не какnull, строка или—;nullдопустим только для реально отсутствующего или неприменимого значения;- backend должен обеспечивать консистентность KPI, таблиц и графиков внутри одного response.
Важное ограничение по числам в примерах:
- числовые значения в JSON-примерах взяты из референсных экранов и нужны для описания формы контракта;
- реальные знаменатели процентов должны быть рассчитаны по утверждённой бизнес-методике;
- если методика конкретного процента не утверждена, её нужно зафиксировать до реализации endpoint-а.
Термины и правила подсчёта
association_type
Тип инновационного объединения.
Допустимые значения:
all: все типы объединений;sez: особые экономические зоны;technoparks: технопарки;clusters: промышленные кластеры.
associations_count
Количество инновационных объединений выбранного типа после применения фильтров.
Примеры:
- для
sezэто количество ОЭЗ; - для
technoparksэто количество технопарков; - для
clustersэто количество промышленных кластеров; - для
allэто сумма объединений всех типов.
opk_organizations_count
Количество уникальных организаций ОПК после применения фильтров.
Одна организация ОПК может входить в несколько объединений. Поэтому это поле не должно считаться как простая сумма участий.
opk_memberships_count
Количество связей организация ОПК x инновационное объединение.
Это поле может быть больше opk_organizations_count.
residents_count
Количество резидентов.
Используется для ОЭЗ и технопарков, если источник данных различает резидентов и участников.
participants_count
Количество участников.
Используется для промышленных кластеров.
employees_count
Численность сотрудников.
Для показателей сотрудников нужно явно различать:
- сотрудников организаций ОПК;
- сотрудников организаций ОПК-резидентов;
- сотрудников всех резидентов;
- сотрудников участников кластера;
- сотрудников выбранного типа объединений.
Нужно реализовать
competence-map analytics filters
GET /api/v1/competence-map/analytics/filters/
Описание:
- возвращает справочники для фильтров аналитической панели;
- учитывает права пользователя;
- учитывает текущие выбранные фильтры, если они переданы в query params;
- не возвращает аналитические KPI, рейтинги и графики.
Request:
GET /api/v1/competence-map/analytics/filters/?association_type=all&federal_district_id=®ion_id=&industry_id=&integrated_structure_id=&organization_id=
Query params:
association_type:all | sez | technoparks | clusters, optional, defaultall;federal_district_id: string, optional;region_id: string, optional;industry_id: string, optional;integrated_structure_id: string, optional;organization_id: string, optional.
Response:
{
"generated_at": "2026-06-19T15:20:00+03:00",
"applied_filters": {
"association_type": "all",
"federal_district_id": null,
"region_id": null,
"industry_id": null,
"integrated_structure_id": null,
"organization_id": null
},
"association_types": [
{
"id": "all",
"label": "все",
"associations_count": 176,
"disabled": false
},
{
"id": "sez",
"label": "ОЭЗ",
"associations_count": 17,
"disabled": false
},
{
"id": "technoparks",
"label": "технопарки",
"associations_count": 35,
"disabled": false
},
{
"id": "clusters",
"label": "кластеры",
"associations_count": 124,
"disabled": false
}
],
"federal_districts": [
{
"id": "central",
"label": "Центральный федеральный округ",
"associations_count": 58,
"disabled": false
}
],
"regions": [
{
"id": "moscow-oblast",
"federal_district_id": "central",
"label": "Московская область",
"associations_count": 41,
"disabled": false
}
],
"industries": [
{
"id": "aviation",
"label": "Авиационная промышленность",
"opk_organizations_count": 180,
"disabled": false
}
],
"integrated_structures": [
{
"id": "rostec",
"label": "ГК Ростех",
"opk_organizations_count": 42,
"disabled": false
}
],
"organizations": [
{
"id": "org-001",
"label": "АО Пример",
"inn": "7700000000",
"ogrn": "1027700000000",
"association_memberships_count": 1,
"disabled": false
}
]
}
Требования к analytics/filters/
Поле generated_at
Требования:
- ISO 8601 с timezone;
- обязательное поле;
- единое время генерации для всего payload.
Блок applied_filters
Требования:
- возвращает фактически применённые фильтры;
- все отсутствующие значения возвращаются как
null; association_typeвсегда заполнен.
Массив association_types
Требования:
- содержит все доступные пользователю типы объединений;
idдолжен быть одним изall,sez,technoparks,clusters;labelобязательный;associations_countinteger>= 0;disabledboolean.
Массивы справочников
Для массивов federal_districts, regions, industries, integrated_structures, organizations:
idобязательный;labelобязательный;disabledобязательный;- count-поля должны быть integer
>= 0; - если по текущим фильтрам список пустой, возвращается пустой массив.
competence-map analytics
GET /api/v1/competence-map/analytics/
Описание:
- возвращает всю аналитику страницы для выбранного
association_type; - применяет все переданные фильтры;
- возвращает KPI, основной аналитический блок, рейтинги, топ отраслей, временную динамику и дополнительные показатели;
- не требует дополнительных аналитических endpoint-ов для отдельных виджетов.
Request:
GET /api/v1/competence-map/analytics/?association_type=all&federal_district_id=®ion_id=&industry_id=&integrated_structure_id=&organization_id=
Query params:
association_type:all | sez | technoparks | clusters, optional, defaultall;federal_district_id: string, optional;region_id: string, optional;industry_id: string, optional;integrated_structure_id: string, optional;organization_id: string, optional.
Общий response envelope:
{
"generated_at": "2026-06-19T15:20:00+03:00",
"data_actual_at": "2026-06-19T00:00:00+03:00",
"association_type": "all",
"applied_filters": {
"association_type": "all",
"federal_district_id": null,
"region_id": null,
"industry_id": null,
"integrated_structure_id": null,
"organization_id": null
},
"kpis": [],
"main_block": {},
"region_ranking": {},
"top_industries": {},
"trend_block": null,
"employee_stats": null
}
Response для association_type=all
{
"generated_at": "2026-06-19T15:20:00+03:00",
"data_actual_at": "2026-06-19T00:00:00+03:00",
"association_type": "all",
"applied_filters": {
"association_type": "all",
"federal_district_id": null,
"region_id": null,
"industry_id": null,
"integrated_structure_id": null,
"organization_id": null
},
"kpis": [
{
"code": "innovation_associations_count",
"label": "Количество инновационных объединений",
"value": 176,
"value_type": "integer",
"numerator": 176,
"denominator": null
},
{
"code": "opk_organizations_count",
"label": "Количество организаций ОПК",
"value": 605,
"value_type": "integer",
"numerator": 605,
"denominator": null
},
{
"code": "opk_organizations_in_associations_share_percent",
"label": "Составляют организации ОПК в инновационных объединениях",
"value": 20.0,
"value_type": "percent",
"numerator": 605,
"denominator": 3025
},
{
"code": "associations_with_opk_share_percent",
"label": "Процент инновационных объединений, в которых участвуют организации ОПК",
"value": 42.0,
"value_type": "percent",
"numerator": 176,
"denominator": 419
}
],
"main_block": {
"type": "all_associations_composition",
"title": "Организации ОПК в инновационных объединениях",
"total_associations_count": 176,
"segments": [
{
"association_type": "sez",
"label": "особые экономические зоны",
"associations_count": 17,
"opk_organizations_count": 64,
"opk_memberships_count": 64
},
{
"association_type": "technoparks",
"label": "технопарки",
"associations_count": 35,
"opk_organizations_count": 66,
"opk_memberships_count": 66
},
{
"association_type": "clusters",
"label": "промышленные кластеры",
"associations_count": 124,
"opk_organizations_count": 517,
"opk_memberships_count": 517
}
]
},
"region_ranking": {
"title": "Рейтинг субъектов РФ по участию организаций ОПК в инновационных объединениях",
"sort": {
"field": "total_opk_organizations_count",
"direction": "desc"
},
"rows": [
{
"rank": 1,
"region_id": "moscow-oblast",
"region_name": "Московская область",
"cluster_opk_organizations_count": 41,
"technopark_opk_organizations_count": 41,
"sez_opk_organizations_count": 63,
"total_opk_organizations_count": 145
},
{
"rank": 2,
"region_id": "moscow",
"region_name": "г. Москва",
"cluster_opk_organizations_count": 28,
"technopark_opk_organizations_count": 28,
"sez_opk_organizations_count": 32,
"total_opk_organizations_count": 88
},
{
"rank": 3,
"region_id": "chelyabinsk-oblast",
"region_name": "Челябинская область",
"cluster_opk_organizations_count": 23,
"technopark_opk_organizations_count": 23,
"sez_opk_organizations_count": 46,
"total_opk_organizations_count": 92
}
]
},
"top_industries": {
"title": "Топ отраслей по количеству организаций ОПК, участвующих в инновационных объединениях",
"mode": "stacked_by_association_type",
"association_type": null,
"max_value": 180,
"rows": [
{
"industry_id": "aviation",
"industry_name": "Авиационная промышленность",
"total_opk_organizations_count": 180,
"cluster_opk_organizations_count": 84,
"technopark_opk_organizations_count": 82,
"sez_opk_organizations_count": 14
},
{
"industry_id": "conventional-weapons",
"industry_name": "Промышленность обычных вооружений",
"total_opk_organizations_count": 124,
"cluster_opk_organizations_count": 72,
"technopark_opk_organizations_count": 38,
"sez_opk_organizations_count": 14
},
{
"industry_id": "ammunition-and-special-chemistry",
"industry_name": "Промышленность боеприпасов и спецхимии",
"total_opk_organizations_count": 110,
"cluster_opk_organizations_count": 45,
"technopark_opk_organizations_count": 55,
"sez_opk_organizations_count": 10
}
]
},
"trend_block": {
"type": "opk_participation_by_year",
"title": "Участие организаций ОПК в инновационных объединениях",
"points": [
{
"year": 2014,
"cluster_opk_organizations_count": 24,
"technopark_opk_organizations_count": 7,
"sez_opk_organizations_count": 5,
"total_opk_organizations_count": 36
},
{
"year": 2016,
"cluster_opk_organizations_count": 42,
"technopark_opk_organizations_count": 9,
"sez_opk_organizations_count": 6,
"total_opk_organizations_count": 57
},
{
"year": 2018,
"cluster_opk_organizations_count": 54,
"technopark_opk_organizations_count": 11,
"sez_opk_organizations_count": 8,
"total_opk_organizations_count": 73
},
{
"year": 2020,
"cluster_opk_organizations_count": 58,
"technopark_opk_organizations_count": 16,
"sez_opk_organizations_count": 10,
"total_opk_organizations_count": 84
},
{
"year": 2022,
"cluster_opk_organizations_count": 66,
"technopark_opk_organizations_count": 18,
"sez_opk_organizations_count": 12,
"total_opk_organizations_count": 96
},
{
"year": 2024,
"cluster_opk_organizations_count": 80,
"technopark_opk_organizations_count": 22,
"sez_opk_organizations_count": 14,
"total_opk_organizations_count": 116
}
]
},
"employee_stats": null
}
Response для association_type=sez
{
"generated_at": "2026-06-19T15:20:00+03:00",
"data_actual_at": "2026-06-19T00:00:00+03:00",
"association_type": "sez",
"applied_filters": {
"association_type": "sez",
"federal_district_id": null,
"region_id": null,
"industry_id": null,
"integrated_structure_id": null,
"organization_id": null
},
"kpis": [
{
"code": "sez_count",
"label": "Количество ОЭЗ",
"value": 17,
"value_type": "integer",
"numerator": 17,
"denominator": null
},
{
"code": "sez_with_opk_residents_share_percent",
"label": "Процент ОЭЗ, в числе резидентов которых есть организации ОПК",
"value": 32.0,
"value_type": "percent",
"numerator": 17,
"denominator": 53
},
{
"code": "opk_resident_organizations_count",
"label": "Количество организаций ОПК-резидентов ОЭЗ",
"value": 64,
"value_type": "integer",
"numerator": 64,
"denominator": null
},
{
"code": "opk_organizations_in_sez_share_percent",
"label": "Составляют организации ОПК в ОЭЗ",
"value": 15.0,
"value_type": "percent",
"numerator": 64,
"denominator": 427
}
],
"main_block": {
"type": "sez_types_and_priority_directions",
"sez_types": {
"title": "Типы ОЭЗ",
"total_sez_count": 17,
"segments": [
{
"sez_type": "industrial_production",
"label": "промышленно-производственные ОЭЗ",
"sez_count": 8,
"opk_organizations_count": 31
},
{
"sez_type": "technology_implementation",
"label": "технико-внедренческие ОЭЗ",
"sez_count": 7,
"opk_organizations_count": 27
},
{
"sez_type": "port",
"label": "портовые ОЭЗ",
"sez_count": 2,
"opk_organizations_count": 6
}
]
},
"priority_directions": {
"title": "Приоритетные направления деятельности ОЭЗ",
"sort": {
"field": "sez_count",
"direction": "desc"
},
"rows": [
{
"rank": 1,
"direction_id": "aircraft-maintenance",
"direction_name": "Обслуживание и ремонт воздушных судов",
"sez_count": 3
},
{
"rank": 2,
"direction_id": "ict",
"direction_name": "Информационно-коммуникационные технологии",
"sez_count": 4
},
{
"rank": 3,
"direction_id": "wood-processing",
"direction_name": "Лесопереработка",
"sez_count": 2
}
]
}
},
"region_ranking": {
"title": "Рейтинг субъектов РФ по участию организаций ОПК в ОЭЗ",
"sort": {
"field": "opk_organizations_count",
"direction": "desc"
},
"rows": [
{
"rank": 1,
"region_id": "moscow-oblast",
"region_name": "Московская область",
"sez_count": 41,
"opk_organizations_count": 41
},
{
"rank": 2,
"region_id": "moscow",
"region_name": "г. Москва",
"sez_count": 28,
"opk_organizations_count": 28
}
]
},
"top_industries": {
"title": "Топ отраслей по количеству организаций ОПК, участвующих в ОЭЗ",
"mode": "single_association_type",
"association_type": "sez",
"max_value": 180,
"rows": [
{
"industry_id": "aviation",
"industry_name": "Авиационная промышленность",
"opk_organizations_count": 180
},
{
"industry_id": "conventional-weapons",
"industry_name": "Промышленность обычных вооружений",
"opk_organizations_count": 124
}
]
},
"trend_block": null,
"employee_stats": {
"items": [
{
"code": "opk_resident_employees_count",
"label": "Численность сотрудников организаций ОПК-резидентов ОЭЗ",
"value": 1678,
"value_type": "integer",
"numerator": 1678,
"denominator": null
},
{
"code": "sez_employees_count",
"label": "Численность сотрудников ОЭЗ",
"value": 5235,
"value_type": "integer",
"numerator": 5235,
"denominator": null
}
]
}
}
Response для association_type=technoparks
{
"generated_at": "2026-06-19T15:20:00+03:00",
"data_actual_at": "2026-06-19T00:00:00+03:00",
"association_type": "technoparks",
"applied_filters": {
"association_type": "technoparks",
"federal_district_id": null,
"region_id": null,
"industry_id": null,
"integrated_structure_id": null,
"organization_id": null
},
"kpis": [
{
"code": "technoparks_with_opk_residents_count",
"label": "Количество технопарков, в числе резидентов которых есть организации ОПК",
"value": 35,
"value_type": "integer",
"numerator": 35,
"denominator": null
},
{
"code": "opk_organizations_in_technoparks_share_percent",
"label": "Доля организаций ОПК в технопарках",
"value": 10.0,
"value_type": "percent",
"numerator": 66,
"denominator": 660
},
{
"code": "opk_organizations_in_technoparks_count",
"label": "Количество организаций ОПК в технопарках",
"value": 66,
"value_type": "integer",
"numerator": 66,
"denominator": null
},
{
"code": "technoparks_with_opk_residents_share_percent",
"label": "Доля технопарков, в числе резидентов которых есть организации ОПК",
"value": 21.0,
"value_type": "percent",
"numerator": 35,
"denominator": 167
}
],
"main_block": {
"type": "technopark_area_distribution",
"title": "Распределение технопарков по площадям",
"total_technoparks_count": 35,
"area_segments": [
{
"area_segment": "large",
"label": "крупные",
"area_range_label": "150-200",
"technoparks_count": 12
},
{
"area_segment": "medium",
"label": "средние",
"area_range_label": "50-150",
"technoparks_count": 14
},
{
"area_segment": "small",
"label": "мелкие",
"area_range_label": "0-50",
"technoparks_count": 9
}
],
"technoparks": {
"sort": {
"field": "area_value",
"direction": "desc"
},
"rows": [
{
"rank": 1,
"technopark_id": "technopark-001",
"technopark_name": "Индустриальный технопарк Пример",
"region_id": "moscow-oblast",
"region_name": "Московская область",
"area_value": 41,
"area_unit": "ha"
},
{
"rank": 2,
"technopark_id": "technopark-002",
"technopark_name": "Технопарк Развитие",
"region_id": "moscow",
"region_name": "г. Москва",
"area_value": 28,
"area_unit": "ha"
}
]
}
},
"region_ranking": {
"title": "Рейтинг субъектов РФ по участию организаций ОПК в технопарках",
"sort": {
"field": "opk_organizations_count",
"direction": "desc"
},
"rows": [
{
"rank": 1,
"region_id": "moscow-oblast",
"region_name": "Московская область",
"technoparks_count": 41,
"opk_organizations_count": 41
},
{
"rank": 2,
"region_id": "moscow",
"region_name": "г. Москва",
"technoparks_count": 28,
"opk_organizations_count": 28
}
]
},
"top_industries": {
"title": "Топ отраслей по количеству организаций ОПК, участвующих в технопарках",
"mode": "single_association_type",
"association_type": "technoparks",
"max_value": 180,
"rows": [
{
"industry_id": "aviation",
"industry_name": "Авиационная промышленность",
"opk_organizations_count": 180
},
{
"industry_id": "conventional-weapons",
"industry_name": "Промышленность обычных вооружений",
"opk_organizations_count": 124
}
]
},
"trend_block": null,
"employee_stats": {
"items": [
{
"code": "opk_resident_employees_count",
"label": "Численность сотрудников организаций ОПК-резидентов технопарков",
"value": 1678,
"value_type": "integer",
"numerator": 1678,
"denominator": null
},
{
"code": "opk_resident_employees_share_percent",
"label": "Доля сотрудников организаций ОПК-резидентов технопарков",
"value": 35.0,
"value_type": "percent",
"numerator": 1678,
"denominator": 4794
}
]
}
}
Response для association_type=clusters
{
"generated_at": "2026-06-19T15:20:00+03:00",
"data_actual_at": "2026-06-19T00:00:00+03:00",
"association_type": "clusters",
"applied_filters": {
"association_type": "clusters",
"federal_district_id": null,
"region_id": null,
"industry_id": null,
"integrated_structure_id": null,
"organization_id": null
},
"kpis": [
{
"code": "clusters_with_opk_participants_count",
"label": "Количество кластеров, в числе участников которых есть организации ОПК",
"value": 124,
"value_type": "integer",
"numerator": 124,
"denominator": null
},
{
"code": "clusters_with_opk_participants_share_percent",
"label": "Процент кластеров, в числе участников которых есть организации ОПК",
"value": 62.0,
"value_type": "percent",
"numerator": 124,
"denominator": 200
},
{
"code": "opk_organizations_in_clusters_count",
"label": "Количество организаций ОПК, участвующих в кластерах",
"value": 517,
"value_type": "integer",
"numerator": 517,
"denominator": null
},
{
"code": "opk_organizations_in_clusters_share_percent",
"label": "Составляют организации ОПК в кластерах",
"value": 15.0,
"value_type": "percent",
"numerator": 517,
"denominator": 3447
}
],
"main_block": {
"type": "cluster_specializations",
"title": "Специализации промышленных кластеров",
"specializations": {
"sort": {
"field": "clusters_count",
"direction": "desc"
},
"rows": [
{
"rank": 1,
"specialization_id": "aircraft-maintenance",
"specialization_name": "Обслуживание и ремонт воздушных судов",
"clusters_count": 3
},
{
"rank": 2,
"specialization_id": "ict",
"specialization_name": "Информационно-коммуникационные технологии",
"clusters_count": 4
},
{
"rank": 3,
"specialization_id": "wood-processing",
"specialization_name": "Лесопереработка",
"clusters_count": 2
}
]
}
},
"region_ranking": {
"title": "Рейтинг субъектов РФ по участию организаций ОПК в кластерах",
"sort": {
"field": "opk_organizations_count",
"direction": "desc"
},
"rows": [
{
"rank": 1,
"region_id": "moscow-oblast",
"region_name": "Московская область",
"clusters_count": 41,
"opk_organizations_count": 41
},
{
"rank": 2,
"region_id": "moscow",
"region_name": "г. Москва",
"clusters_count": 28,
"opk_organizations_count": 28
}
]
},
"top_industries": {
"title": "Топ отраслей по количеству организаций ОПК, участвующих в промышленных кластерах",
"mode": "single_association_type",
"association_type": "clusters",
"max_value": 180,
"rows": [
{
"industry_id": "aviation",
"industry_name": "Авиационная промышленность",
"opk_organizations_count": 180
},
{
"industry_id": "conventional-weapons",
"industry_name": "Промышленность обычных вооружений",
"opk_organizations_count": 124
}
]
},
"trend_block": {
"type": "cluster_creation_dynamics",
"title": "Динамика создания промышленных кластеров 2020-2024 гг.",
"points": [
{
"year": 2020,
"clusters_count": 15,
"growth_percent": null
},
{
"year": 2021,
"clusters_count": 24,
"growth_percent": 60.0
},
{
"year": 2022,
"clusters_count": 47,
"growth_percent": 95.8
},
{
"year": 2023,
"clusters_count": 66,
"growth_percent": 40.4
},
{
"year": 2024,
"clusters_count": 124,
"growth_percent": 87.9
}
]
},
"employee_stats": null
}
Требования к общим полям analytics response
Поле generated_at
Требования:
- ISO 8601 с timezone;
- обязательное;
- показывает время формирования response.
Поле data_actual_at
Требования:
- ISO 8601 с timezone;
- обязательное;
- показывает дату и время актуальности аналитических данных.
Поле association_type
Требования:
- обязательное;
- должно совпадать с фактически применённым режимом;
- допустимые значения:
all,sez,technoparks,clusters.
Блок applied_filters
Требования:
- обязательный;
- содержит нормализованные значения применённых фильтров;
- отсутствующие фильтры возвращаются как
null; association_typeвсегда заполнен.
Массив kpis
Каждый объект массива - одна KPI-метрика.
Поля:
code: стабильный системный идентификатор метрики;label: человекочитаемое название метрики;value: raw numeric value;value_type:integer | percent | decimal;numerator: числитель, если применимо;denominator: знаменатель, если применимо.
Требования:
- все поля, кроме
numeratorиdenominator, обязательны; valueдолжен быть number, не string;0допустим как валидное значение;- для
value_type = percentзначение возвращается в диапазоне0..100; - для percent-метрик
numeratorиdenominatorобязательны, если знаменатель известен; - порядок массива должен соответствовать порядку карточек на странице.
Блок main_block
Полиморфный блок. Структура зависит от association_type.
Допустимые type:
all_associations_composition;sez_types_and_priority_directions;technopark_area_distribution;cluster_specializations.
Требования:
typeобязательный;titleобязательный;- структура должна соответствовать текущему
association_type; - массивы внутри блока должны быть отсортированы.
Блок region_ranking
Поля:
title;sort;rows.
Требования:
titleобязательный;sort.fieldобязательный;sort.directionдолжен бытьasc | desc;rowsможет быть пустым массивом;rankвозвращается в каждой строке;region_idобязательный;region_nameобязательный;- count-поля должны иметь однозначные имена.
Нельзя использовать неоднозначное поле:
{
"sez_count": 63
}
если значение означает количество организаций ОПК.
Нужно использовать одно из точных полей:
{
"sez_opk_organizations_count": 63
}
или:
{
"sez_opk_memberships_count": 63
}
Блок top_industries
Поля:
title;mode;association_type;max_value;rows.
Требования:
modeдолжен бытьstacked_by_association_type | single_association_type;- для
association_type = allдолжен использоватьсяmode = stacked_by_association_type; - для
association_type = sez | technoparks | clustersдолжен использоватьсяmode = single_association_type; max_valueдолжен быть number>= 0;max_valueдолжен быть больше или равен максимальному значению вrows;rowsдолжны быть отсортированы по убыванию основного значения.
Блок trend_block
Может быть null.
Допустимые type:
opk_participation_by_year;cluster_creation_dynamics.
Требования:
- если блок не применим для режима, возвращается
null; pointsдолжны быть отсортированы поyearпо возрастанию;yearinteger;growth_percentможет бытьnullдля первого года;- проценты роста возвращаются в диапазоне
0..100+, если рост больше 100% возможен.
Блок employee_stats
Может быть null.
Поля:
items.
Требования:
- если блок не применим для режима, возвращается
null; - каждый item должен иметь
code,label,value,value_type; - для percent-метрик должны быть
numeratorиdenominator, если знаменатель известен; - подписи должны соответствовать текущему
association_type.
Порядок массивов
kpis
Порядок должен соответствовать порядку карточек на странице.
main_block.segments
Для all_associations_composition порядок:
seztechnoparksclusters
region_ranking.rows
Порядок сортировки по умолчанию:
- основной показатель по убыванию;
- при равенстве -
opk_organizations_countпо убыванию; - при равенстве -
region_nameпо возрастанию (ru-RU).
top_industries.rows
Порядок сортировки:
- основной показатель по убыванию;
- при равенстве -
industry_nameпо возрастанию (ru-RU).
trend_block.points
Порядок сортировки:
yearпо возрастанию.
Проверки консистентности
Backend должен гарантировать:
association_typeв корне response совпадает сapplied_filters.association_type;kpis[*].valueсогласованы с соответствующими блоками аналитики;- сумма
main_block.segments[*].associations_countдляallравнаtotal_associations_count; top_industries.max_valueне меньше максимального значения вtop_industries.rows;rankв рейтингах не дублируется, если не используется специальная tie-ranking методика;- все
idстабильны между запросами; - все count-поля возвращаются как integer
>= 0; - все percent-поля возвращаются как number;
- пустые данные возвращаются пустыми массивами, а не отсутствующими полями.
Успешный пустой ответ
Если по фильтрам данных нет, возвращается 200 OK.
Пример:
{
"generated_at": "2026-06-19T15:20:00+03:00",
"data_actual_at": "2026-06-19T00:00:00+03:00",
"association_type": "clusters",
"applied_filters": {
"association_type": "clusters",
"federal_district_id": "unknown",
"region_id": null,
"industry_id": null,
"integrated_structure_id": null,
"organization_id": null
},
"kpis": [],
"main_block": {
"type": "cluster_specializations",
"title": "Специализации промышленных кластеров",
"specializations": {
"sort": {
"field": "clusters_count",
"direction": "desc"
},
"rows": []
}
},
"region_ranking": {
"title": "Рейтинг субъектов РФ по участию организаций ОПК в кластерах",
"sort": {
"field": "opk_organizations_count",
"direction": "desc"
},
"rows": []
},
"top_industries": {
"title": "Топ отраслей по количеству организаций ОПК, участвующих в промышленных кластерах",
"mode": "single_association_type",
"association_type": "clusters",
"max_value": 0,
"rows": []
},
"trend_block": null,
"employee_stats": null
}
Ошибка валидации query params
Для некорректного association_type:
HTTP status:
400 Bad Request
Response:
{
"error": {
"code": "invalid_association_type",
"message": "Unsupported association_type",
"details": {
"received_value": "parks",
"allowed_values": ["all", "sez", "technoparks", "clusters"]
}
}
}
Для несуществующего фильтра:
HTTP status:
400 Bad Request
Response:
{
"error": {
"code": "invalid_filter_value",
"message": "Unknown filter value",
"details": {
"field": "region_id",
"received_value": "unknown"
}
}
}
Ожидаемая схема запросов
При загрузке страницы:
GET /api/v1/competence-map/analytics/filters/
GET /api/v1/competence-map/analytics/?association_type=all
При смене типа объединения:
GET /api/v1/competence-map/analytics/filters/?association_type=clusters
GET /api/v1/competence-map/analytics/?association_type=clusters
При применении нескольких фильтров:
GET /api/v1/competence-map/analytics/filters/?association_type=technoparks&federal_district_id=central®ion_id=moscow-oblast
GET /api/v1/competence-map/analytics/?association_type=technoparks&federal_district_id=central®ion_id=moscow-oblast