Files
2022_oknardia/MANAGEMENT_RUNBOOK.md

34 KiB
Raw Blame History

MANAGEMENT_RUNBOOK.md

Единый runbook по management-командам проекта.

Документ отвечает на 3 вопроса:

  • что запускать;
  • когда запускать;
  • как безопасно откатываться/повторять запуск.

Каталог команд

  1. generate_sitemaps — оффлайн генерация sitemap-файлов.
  2. regenerate_seria_prerender — оффлайн пересборка pre-render шаблонов для catalog_seria_info.
  3. populate_seo_fields — автозаполнение SEO-полей блога из существующих данных.
  4. make_rating — пересчёт рейтингов профилей и стеклопакетов методом Манна-Уитни.

Общие правила запуска

  • Запускать команды из корня репозитория.
  • Для локального/CI запуска использовать poetry.
  • Не запускать тяжелые операции через HTTP-эндпоинты /service/*.
  • Перезапуск веб-сервера (gunicorn/uWSGI) делать отдельным шагом оркестрации, а не из кода Django.

Базовый шаблон запуска:

cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py <command> [args]

1) Команда generate_sitemaps

Назначение:

  • пересобрать sitemap.xml и chunk-файлы в MEDIA_ROOT/_serv_sitemap.

Базовый запуск:

cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py generate_sitemaps

Запуск с параметрами:

cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py generate_sitemaps \
  --compare-min-depth 2 \
  --compare-max-depth 4 \
  --max-items 40000 \
  --max-file-size 5242880 \
  --max-files-qty 998

Когда запускать:

  • после деплоя;
  • по расписанию (cron/systemd timer);
  • после крупных изменений данных каталога/блога.

Важные замечания

Чтобы sitemap.xml отдавал прокси-nginx напрямую из файловой системы, нужно, чтобы он физически лежал в MEDIA_ROOT/_serv_sitemap/sitemap.xml.

Допустимо, что файл доступен по двум URL (корневой и media), но в robots.txt должен быть указан один канонический вариант sitemap.xml

NGINX snippet (alias для корневого sitemap)

# Корневой sitemap.xml (для привычного для поисковиков URL)
location = /sitemap.xml {
    alias /<путь-к-каталогку-с-докер-приложением>/media/_serv_sitemap/sitemap.xml;
    default_type application/xml;
    add_header Cache-Control "public, max-age=300";
}

2) Команда regenerate_seria_prerender

Назначение:

  • пересобрать pre-render шаблоны для страниц серий (catalog_seria_info) в каталоге seria_info/prepared/.

Проверка без записи файлов:

cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py regenerate_seria_prerender --dry-run

Пересборка только отсутствующих файлов:

cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py regenerate_seria_prerender

Принудительная пересборка всех root-серий:

cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py regenerate_seria_prerender --force

Выборочная пересборка:

cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py regenerate_seria_prerender --seria-id 843 --seria-id 2100 --force

Когда запускать:

  • после обновления логики catalog_seria_info;
  • после массового обновления данных серий/окон/квартир;
  • после очистки seria_info/prepared/.

3) Команда populate_seo_fields

Назначение:

  • автозаполнить SEO-поля (sSlug, sMetaDescription, sMetaKeywords) для всех существующих записей блога.

Используется:

  • при первом развертывании новой версии с автогенерацией SEO-полей;
  • при восстановлении из бэкапа где SEO-поля пусты;
  • при изменении логики автогенерации (с флагом --force).

Базовый запуск

Заполнить только пустые SEO-поля (стандартный вариант):

cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py populate_seo_fields

Параметры запуска

--dry-run — только показать что будет сделано (без сохранения в БД):

poetry run python oknardia/manage.py populate_seo_fields --dry-run

--force — переполнить ВСЕ SEO-поля, даже уже заполненные:

poetry run python oknardia/manage.py populate_seo_fields --force

--clean — очистить все SEO-поля перед заполнением (для переделки):

poetry run python oknardia/manage.py populate_seo_fields --clean

Комбинация флагов — сухой прогон переполнения всех полей:

poetry run python oknardia/manage.py populate_seo_fields --dry-run --force

Что заполняется

Поле Источник Результат
sSlug sPostHeader URL-безопасный слаг (max 200 символов)
sMetaDescription sPostContent Первые 160 символов (исключая теги <cut>)
sMetaKeywords sPostHeader Заголовок + префикс "oknardia, окнардия, блог, публикация" (max 256 символов)

Пример результата:

sPostHeader = "Профиль Brusbox Super Aero"

sSlug = "profil-brusbox-super-aero"
sMetaDescription = "brusbox-super-aero-pyatikamernaya-profil-sistema..."
sMetaKeywords = "oknardia, окнардия, блог, публикация, Профиль Brusbox Super Aero"

Когда запускать

  • После первого развертывания — заполнить SEO-поля всех 29 существующих постов одной командой.
  • Один раз — команда идемпотентна (при повторном запуске не будет ничего менять, т.к. пустые поля остатся).
  • При изменении логики — использовать --clean --force для полной переделки всех SEO-полей.

Пример полного сценария

cd /Users/e-serg/PRJ/2022-oknardia

# Шаг 1: Проверить что будет заполнено
poetry run python oknardia/manage.py populate_seo_fields --dry-run

# Шаг 2: Если результат устраивает — запустить реально
poetry run python oknardia/manage.py populate_seo_fields

# Шаг 3: Проверить что заполнилось
poetry run python oknardia/manage.py shell -c "
from oknardia.models import BlogPosts
posts = BlogPosts.objects.all()
print(f'Пусто sSlug: {posts.filter(sSlug=\"\").count()}')
print(f'Пусто sMetaDescription: {posts.filter(sMetaDescription=\"\").count()}')
print(f'Пусто sMetaKeywords: {posts.filter(sMetaKeywords=\"\").count()}')
"

Возвращаемая информация

======================================================================
ИТОГОВЫЙ ОТЧЕТ
======================================================================

✓ sSlug заполнено:              28 раз
✓ sMetaDescription заполнено:  28 раз
✓ sMetaKeywords заполнено:     28 раз
✓ Записей обновлено в БД:      28
✗ Ошибок при обработке:        0

✅ Обновлено 28 записей успешно!

Откат и безопасность

  • Безопасна для повторного запуска — пустые поля не изменяются при повторной работе.
  • Откат через SQL — если нужно очистить, используй: UPDATE oknardia_blogposts SET sSlug='', sMetaDescription='', sMetaKeywords='';
  • Всегда используй --dry-run перед первым запуском для проверки.

4) Команда make_rating

Назначение:

  • пересчитать рейтинги оконных профилей, стеклопакетов и наборов услуг используя адаптированный метод Манна-Уитни (Mann-Whitney U Step Rank).
  • сохранить результаты в поля fProfileRating, fGlazingRating, fSetRating (0.0 … 5.0 звёзд).
  • заполнить JSON-состав рейтинга (детальный разбор по каждому параметру) в поля sProfileDescription, sGlazingDescription, sSetDescription.
  • алгоритм рассчитывает три этапа ранжирования: профили → стеклопакеты → наборы (которые зависят от профилей и стеклопакетов).

Базовый запуск

Пересчитать рейтинги всех профилей и стеклопакетов (стандартный режим):

cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py make_rating

Параметры запуска

--verbosity 0 — минимум информации (только ошибки): --verbosity 1 — стандартная информация (по умолчанию): --verbosity 3 — очень подробный вывод (для отладки, для каждого профиля/стеклопакета таблица):

Пример использования с параметром --verbosity:

poetry run python oknardia/manage.py make_rating --verbosity 3 | head -500

АЛГОРИТМ: Метод Манна-Уитни (Mann-Whitney U Step Rank)

Команда использует адаптированный вариант критерия Манна-Уитни для ранжирования параметров качества оконных предложений и комопнентов (профилей, стеклопакетов, наборов услуг) на основе их технических характеристик и популярности у поставщиков.

Как это работает:

  1. Сортировка объектов по одному параметру (например, по теплопередаче):

    • Профиль A: 0.60 Ro → ранг = 0.0
    • Профиль B: 0.60 Ro → ранг = 0.0 (то же значение, ранг не меняется)
    • Профиль C: 0.80 Ro → ранг = 1.0 (новое значение, добавляем вес параметра)
    • Профиль D: 0.95 Ro → ранг = 2.0 (ещё новое значение)
  2. Направление ранжирования определяется флагом revers:

    • revers=FalseБОЛЬШЕ = ЛУЧШЕ (например, теплопередача, звукоизоляция)
    • revers=TrueМЕНЬШЕ = ЛУЧШЕ (например, высота в проёме для прочности)
  3. Нормализация рангов к диапазону 0.0 … 1.0:

    • Профиль A: 0.0 / 2.0 = 0.0
    • Профиль B: 0.0 / 2.0 = 0.0
    • Профиль C: 1.0 / 2.0 = 0.5
    • Профиль D: 2.0 / 2.0 = 1.0
  4. Суммирование рангов по всем параметрам:

    • TmpRating = Σ(ранг_параметра × вес_параметра)
  5. Преобразование в звёзды (0.0 … 5.0):

    • ТmpRating нормализуется к 0..1
    • Умножается на 5.0 для получения финального рейтинга

Пример итогового рейтинга профиля:

Профиль "Brusbox Super Aero" 
  Теплопередача: 0.60 Ro (ранг 0.9, вес 1.0)
  Звукоизоляция: 33 дБ (ранг 0.8, вес 1.0)
  Высота в проёме: 112 мм (ранг 0.6, вес 0.3)
  Количество камер: 6 шт (ранг 0.7, вес 0.1)
  
  Итого: (0.9×1.0 + 0.8×1.0 + 0.6×0.3 + 0.7×0.1) / 2.3 ≈ 3.8 звёзд ⭐⭐⭐⭐

ПРОФИЛИ: какие параметры учитываются

Параметр Поле БД ЛУЧШЕ Вес Описание
1 Звукоизоляция fProfileSoundproofing БОЛЬШЕ дБ 1.0 Сопротивление шуму (дБ)
2 Теплопередача fProfileHeatTransf БОЛЬШЕ Ro 1.0 Сопротивление теплопередаче (м²×°C/Вт)
3 Высота в проёме iProfileHeight МЕНЬШЕ мм 0.3 Видимая высота в световом проёме (экономия)
4 Высота фальца iProfileRabbet БОЛЬШЕ мм 0.2 Глубина фальца для герметизации
5 Толщина стеклопакета iProfileGlazingThickness БОЛЬШЕ мм 0.2 Максимальная толщина стеклопакета
6 Толщина профиля iProfileThickness БОЛЬШЕ мм 0.2 Монтажная (боковая) ширина профиля
7 Контуры уплотнения fProfileSeals БОЛЬШЕ контуров 1.2 Количество контуров уплотнения
8 Количество камер iProfileCameras БОЛЬШЕ шт 0.1 Число камер в профиле (из рамки + створки)
9 Популярность NumOffer БОЛЬШЕ предложений 0.1 Используется ли профиль в коммерческих предложениях

Примеры интерпретации:

  • Профиль с рейтингом 5.0 : отличная теплопередача + звукоизоляция + много камер + многоконтурные уплотнения.
  • Профиль с рейтингом 2.0 : среднее качество, слабые характеристики.
  • Профиль с рейтингом 0.5 : слабые характеристики или производить не предоставил данных и их нет в отрытых источниках.

СТЕКЛОПАКЕТЫ: какие параметры учитываются

Параметр Поле БД ЛУЧШЕ Вес Описание
1 Звукоизоляция fGlazingSoundproofing БОЛЬШЕ дБ 1.0 Звукоизоляционный коэффициент (дБ)
2 Теплопередача fGlazingHeatTransfer БОЛЬШЕ Ro 1.0 Сопротивление теплопередаче (м²×°C/Вт)
3 Светопропускание fGlazingLightTransmission БОЛЬШЕ % 0.25 Коэффициент пропускания видимого света (%), отражение света снаружи
4 Солнцепропускание fGlazingPassingSun МЕНЬШЕ % 0.15 Коэффициент солнечного излучения (SHGC) — В России меньше = лучше для охлаждения летом
5 Толщина iGlazingThickness БОЛЬШЕ мм 0.1 Общая толщина стеклопакета
6 Количество камер iGlazingCamerasN БОЛЬШЕ шт 0.1 Число воздушных/аргоновых камер

Особенности стеклопакетов:

  • Светопропускание = как много естественного света проходит в помещение (больше = лучше)
  • Солнцепропускание = как много солнечного тепла/излучения проходит (в России: меньше = лучше, потому что внутри есть отражающее напыление)
  • Двухкамерный (с аргоном) почти всегда лучше однокамерного
  • Трёхкамерные = премиум для холодного климата

Примеры интерпретации:

  • 5.0 : трёхкамерный с хорошей теплопередачей, звукоизоляцией (обычно с аргоном и напылением).
  • 3.0 : двухкамерный, среднее качество
  • 1.0 : однокамерный старого образца или с плохими характеристиками

НАБОРЫ: какие параметры учитываются

Параметр Поле БД ЛУЧШЕ Вес Описание
1 Актуальность dModify МЕНЬШЕ (свежее) 0.3 Дата последнего обновления (timestamp)
2 Доставка bSetDelivery ДА (1) 0.8 Включена ли доставка в стоимость
3 Монтаж/демонтаж bSetUninstallInstall ДА (1) 1.0 Включены ли услуги монтажа и демонтажа
4 Подоконник sSetSill ДА (1) 0.5 Включен ли подоконник
5 Водоотлив sSetPanes ДА (1) 0.8 Включен ли водоотлив/козырёк
6 Откос sSetSlope ДА (1) 0.5 Включены ли откосы
7 Климат-контроль sSetClimateControl ДА (1) 0.3 Включено ли управление микроклиматом
8 Число предложений NumOffer БОЛЬШЕ 0.2 Популярность набора (кол-во активных предложений)
9 Гибкость скидок iDiscountVariantsCount БОЛЬШЕ вариантов 0.5 Кол-во вариантов скидок из формулы офиса
10 Размер скидок fDiscountMax БОЛЬШЕ % 1.0 Максимальная скидка из всех вариантов

ВАЖНО: Итоговый рейтинг набора состоит из трёх компонентов:

  • Рейтинг параметров услуг (Актуальность, Доставка, Монтаж, Подоконник и т.д.)
  • Рейтинг входящего стеклопакета (ранжируется отдельно)
  • Рейтинг входящего профиля (ранжируется отдельно)

Формула итогового рейтинга набора (fSetRating):

k1 = нормализованный TmpRating (услуги) * вес услуг
k2 = нормализованный рейтинг стеклопакета * RARING_WEIGHT_GLAZING_IN_SET (обычно 1.5)
k3 = нормализованный рейтинг профиля * RARING_WEIGHT_PVC_PROFILE_IN_SET (обычно 1.5)

fSetRating = k1 + k2 + k3  (итого от 0.0 до 5.0 звёзд)

Примеры интерпретации:

  • 5.0 : набор с премиум компонентами (хороший профиль и стеклопакет) + полный пакет услуг (доставка, монтаж, подоконник, откос, климат-контроль) + значительные скидки.
  • 3.5 : хороший профиль/стеклопакет + базовые услуги (доставка, монтаж) + скромные скидки.
  • 2.0 : эконом компоненты или слабые услуги (нет доставки, нет откосов).
  • 1.0 : минимальный пакет или устаревшие предложения (давно не обновлялись).

Когда запускать

  • После первого развертывания — заполнить рейтинги всех профилей, стеклопакетов и наборов.

  • После изменения каталога (добавление нового профиля/стеклопакета/набора).

  • После уточнения характеристик (например, поставщик предоставил новые данные).

    poetry run python oknardia/manage.py make_rating
    
  • По расписанию (например, ежемесячно, чтобы пересчитать популярность):

    30 2 * * 1 cd /home/user/app-path/2022-oknardia && poetry run python oknardia/manage.py make_rating >> /var/log/oknardia-rating.log 2>&1
    
  • После обновления весов в settings.py (константы RANK_PVCP_*, RANK_GLAZ_*).

Откат и безопасность

  • Безопасна для повторного запуска — пересчитывает все рейтинги заново.
  • Всегда обновляет только рейтинги — другие данные в таблицах не меняются.
  • Откат через SQL — если нужно установить нулевые значения (перед запуском рекомендуется бэкап базы):
    -- Очистить рейтинги профилей
    UPDATE oknardia_pvcprofiles SET fProfileRating = 0.0, sProfileDescription = '{}';
    
    -- Очистить рейтинги стеклопакетов
    UPDATE oknardia_glazing SET fGlazingRating = 0.0, sGlazingDescription = '{}';
    
    -- Очистить рейтинги наборов
    UPDATE oknardia_setkit SET fSetRating = 0.0, sSetDescription = '{}';
    

Примеры из реальных данных

Пример вывода --verbosity 1:

=== НАЧАЛИ ПЕРЕСЧЁТ РЕЙТИНГОВ ===

========================================
[ЭТАП 1]: Пересчёт рейтингов ПРОФИЛЕЙ...
========================================
  ✓ Обнулены рейтинги у 94 профилей
  ✓ Найдено 94 профилей для ранжирования
  ✓ Сохранено 94 профилей с финальными рейтингами

=============================================
[ЭТАП 2]: Пересчёт рейтингов СТЕКЛОПАКЕТОВ...
=============================================
  ✓ Обнулены рейтинги у 97 стеклопакетов
  ✓ Найдено 97 стеклопакетов для ранжирования
  ✓ Сохранено 97 стеклопакетов с финальными рейтингами

================================================
[ЭТАП 3]: Пересчёт рейтингов НАБОРОВ (SetKit)...
================================================
  ✓ Обнулены рейтинги у 27 наборов
  ✓ Найдено 27 наборов для ранжирования
  ✓ Сохранено 27 наборов с финальными рейтингами

[OK!] ПЕРЕСЧЁТ РЕЙТИНГОВ ЗАВЕРШЁН УСПЕШНО!
   • Обновлено профилей: 94
   • Обновлено стеклопакетов: 97
   • Обновлено наборов: 27

Пример вывода --verbosity 3 (наиболее подробный):

=== НАЧАЛИ ПЕРЕСЧЁТ РЕЙТИНГОВ ===

========================================
[ЭТАП 1]: Пересчёт рейтингов ПРОФИЛЕЙ...
========================================

  ✓ Обнулены рейтинги у 94 профилей
  ✓ Найдено 94 профилей для ранжирования
  ...
  ...
  ====================================================================================================
  ПРОФИЛЬ: politech W80 (ID: 78)
  ====================================================================================================
  Характеристика                 Значение        Ранг (0..1)     Вклад          
  ----------------------------------------------------------------------------------------------------
  Высота в проёме                120 мм          0.368 *              
  Популярность                   0 предл.        0.000                
  Теплопередача                  0.91 Ro         0.657 ***            
  Толщина профиля                80 мм           0.588 **             
  Толщина стеклопакета           42 мм           0.409 **             
  Уплотнители                    3 контуров      1.000 *****          
  Фальц                          14 мм           0.150                
  Число камер                    12 шт           0.714 ***            
  Шумоизоляция                   44.00 дБ        0.909 ****           
  ----------------------------------------------------------------------------------------------------
  ИТОГО: Рейтинг = 4.94/5.0 ****
  ...
  ...
  ✓ Сохранено 94 профилей с финальными рейтингами

=============================================
[ЭТАП 2]: Пересчёт рейтингов СТЕКЛОПАКЕТОВ...
=============================================

  ✓ Обнулены рейтинги у 97 стеклопакетов
  ✓ Найдено 97 стеклопакетов для ранжирования
  ...
  ...
  ====================================================================================================
  СТЕКЛОПАКЕТ: Однокамерный 5-4, 25 мм (И+аргон) (ID: 60) | Марка:СПО 5М1-Ar16-И4
  ====================================================================================================
  Характеристика                      Значение             Ранг (0..1)     Вклад          
  ----------------------------------------------------------------------------------------------------
  Камеры                              —                    0.000                
  Светопропускание                    74.00%               0.824 ****           
  Солнцепропускание                   58.00%               0.450 **             
  Теплопередача                       0.91 Ro              0.936 ****           
  Толщина                             25 мм                0.400 **             
  Шумоизоляция                        —                    0.429 **             
  ----------------------------------------------------------------------------------------------------
  ИТОГО: Рейтинг = 4.87/5.0 ****
  ...    
  ...    
  ✓ Сохранено 97 стеклопакетов с финальными рейтингами
  
================================================
[ЭТАП 3]: Пересчёт рейтингов НАБОРОВ (SetKit)...
================================================
  ✓ Обнулены рейтинги у 27 наборов
  ✓ Найдено 27 наборов для ранжирования
  ...  
  ...  
  ========================================================================================================================
  НАБОР: Элит (ID: 3)
  ========================================================================================================================
  Параметр                            Значение             Ранг (0..1)     Вклад          
  ------------------------------------------------------------------------------------------------------------------------
  Актуальность                        свежий               0.375 *              
  Водоотлив                           ✓ Да                 1.000 *****          
  Гибкость скидок                     0 вариантов          0.500 **             
  Доставка                            ✓ Да                 1.000 *****          
  Климат-контроль                     ✓ Да                 1.000 *****          
  Монтаж                              ✓ Да                 1.000 *****          
  Откос                               ✓ Да                 1.000 *****          
  Подоконник                          ✓ Да                 1.000 *****          
  Размер скидок                       0.0%                 0.500 **             
  Число предложений                   46 шт                0.250 *              
  ------------------------------------------------------------------------------------------------------------------------
  ИТОГО: Рейтинг = 4.16/5.0 ****
  ...  
  ...  

[OK!] ПЕРЕСЧЁТ РЕЙТИНГОВ ЗАВЕРШЁН УСПЕШНО!
   • Обновлено профилей: 94
   • Обновлено стеклопакетов: 97

Оркестрация и reload веб-сервера

Важно:

  • reload веб-сервера не встроен в management-команды;
  • это отдельная операция окружения.

Пример для systemd + gunicorn:

sudo systemctl reload gunicorn

Рекомендуемый batch-сценарий:

cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py regenerate_seria_prerender --force
poetry run python oknardia/manage.py generate_sitemaps
sudo systemctl reload gunicorn

Cron/systemd timer (пример)

Пример cron (раз в сутки в 03:20):

20 3 * * * cd /Users/e-serg/PRJ/2022-oknardia && poetry run python oknardia/manage.py regenerate_seria_prerender --force && poetry run python oknardia/manage.py generate_sitemaps >> /var/log/oknardia-maintenance.log 2>&1

Если нужен reload после batch, добавляй отдельной строкой/шагом оркестратора.

Диагностика

Быстрая проверка конфигурации:

cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py check

Типовые причины проблем:

  • нет прав записи в директории templates/seria_info/prepared или MEDIA_ROOT/_serv_sitemap;
  • устаревшее виртуальное окружение / неустановленные зависимости;
  • запуск не из того каталога.

План миграции /service/* -> management commands

Текущее направление:

  • все тяжелые и административные операции переносить из HTTP в management-команды;
  • /service/* оставлять только как thin UI/мониторинг или убрать полностью.

См. также:

  • SETUP.md
  • README.md