Files
han-app/support&knowlages/releases/#2 notifications deploy.md
T

7.9 KiB

Накатывание Notification Center v1

Выполнять на сервере из каталога:

cd /path/to/HAN_chat_specification/codebase/backend

1. Подготовить резервную точку

Создайте PITR-маркер/снимок PostgreSQL. Миграция forward-only — откатывать её нельзя.

2. Обновить код

git fetch
git checkout <утверждённый-commit-or-tag>
git status --short

Рабочее дерево должно быть чистым.

3. Добавить переменные в .env

Не перезаписывайте существующий .env. Добавьте:

NOTIFICATIONS_TOKEN_PRODUCER_TEST=<случайный-токен>

NGINX_RATE_LIMIT_NOTIFICATIONS_READ=120r/m
NGINX_RATE_LIMIT_NOTIFICATIONS_ACTION=60r/m
NGINX_RATE_LIMIT_NOTIFICATION_UPLOAD=20r/m
NGINX_RATE_LIMIT_NOTIFICATIONS_PUBLIC=60r/m

Токен можно создать так:

openssl rand -hex 32
chmod 600 .env

Проверить конфигурацию:

./scripts/validate-env .env
docker compose --env-file .env config --quiet

4. Собрать новые образы

docker compose --env-file .env build --pull \
  api-backend frontend-static nginx

5. Выполнить миграцию

PITR_MARKER_CONFIRMED=true ENV_FILE=.env \
  deployment/scripts/migrate.sh

deployment/scripts/seed.sh

Ожидаемая ревизия:

0008_notifications_v1

Проверка:

docker compose --env-file .env --profile ops run --rm \
  migrate-api alembic current

6. Обновить статический frontend

docker compose --env-file .env run --rm frontend-static

7. Перезапустить изменённые сервисы

docker compose --env-file .env up -d --force-recreate \
  api-backend \
  delivery-worker \
  safety-recovery-worker \
  cleanup-worker \
  notification-expire-worker \
  notification-draft-cleanup-worker \
  nginx

8. Проверить состояние

docker compose ps

docker compose logs --since=10m \
  api-backend \
  notification-expire-worker \
  notification-draft-cleanup-worker \
  nginx

docker compose exec -T nginx nginx -t -c /tmp/nginx.conf

Проверить API:

curl -fsS https://chat.han0107.ru/health/live
curl -fsS https://chat.han0107.ru/health/ready
curl -fsS https://chat.han0107.ru/api/v1/public/notification-types
curl -fsS https://chat.han0107.ru/api/v1/public/notifications

Внешний internal endpoint обязан возвращать 404:

curl -i https://chat.han0107.ru/internal/notifications/v1/notifications

9. Провести smoke-тест

deployment/scripts/smoke.sh

Дополнительно проверить через producer_test:

  • Create возвращает 201;
  • повтор того же тела — 200;
  • то же external_id с изменённым телом — 409;
  • Cancel — 200;
  • повторный Cancel — 200;
  • уведомление появляется у указанного user_id.

Полный эксплуатационный чек-лист находится в codebase/backend/deployment/RUNBOOK.ru.md.

Важно: при проблеме не выполнять docker compose down -v и не откатывать Alembic. После применения 0008 безопасный путь — исправляющий релиз; старый backend может не пройти readiness из-за проверки версии схемы.

Создание уведомлений

Публичные (инсерт в БД)

BEGIN;

INSERT INTO han_app.guest_notifications ( id, notification_type, notification_datetime, header, text, priority_override, date_expired, price, old_price, instruction_url, chat_message_text, lifecycle_status, closed_at, record_status, status_changed_at, status_change_reason, created_at, updated_at, updater_user_id ) VALUES -- 1. Авторизация ( '019fa3e9-8d91-7199-8199-609916d48f04', 'authorize', now(), 'Войдите в личный кабинет', 'Авторизуйтесь, чтобы видеть персональные статусы, документы и уведомления.', NULL, NULL, NULL, NULL, NULL, NULL, 'active', NULL, 'A', NULL, NULL, now(), now(), NULL ),

-- 2. Установка приложения ( '019fa3e9-8d91-722a-90df-e4824e23b354', 'install_app', now(), 'Установите приложение HAN', 'Добавьте приложение на главный экран, чтобы сервис всегда был под рукой.', NULL, NULL, NULL, NULL, 'https://www.han0107.ru/app/how-install-pwa', NULL, 'active', NULL, 'A', NULL, NULL, now(), now(), NULL ),

-- 3. Глобальная акция ( '019fa3e9-8d91-7d19-8873-eefb2a60f116', 'promo_global', now(), 'Специальное предложение', 'Узнайте подробнее об актуальной акции.', NULL, now() + interval '30 days', NULL, NULL, NULL, 'Здравствуйте! Хочу узнать подробнее об акции.', 'active', NULL, 'A', NULL, NULL, now(), now(), NULL ),

-- 4. Глобальное предложение ( '019fa3e9-8d91-7452-a13d-3d2518ea257d', 'ads_global', now(), 'Нужна помощь?', 'Расскажем об услугах и подберём подходящее решение.', NULL, now() + interval '30 days', NULL, NULL, NULL, 'Здравствуйте! Хочу получить консультацию по услугам.', 'active', NULL, 'A', NULL, NULL, now(), now(), NULL ) ON CONFLICT (id) DO UPDATE SET notification_datetime = EXCLUDED.notification_datetime, header = EXCLUDED.header, text = EXCLUDED.text, priority_override = EXCLUDED.priority_override, date_expired = EXCLUDED.date_expired, price = EXCLUDED.price, old_price = EXCLUDED.old_price, instruction_url = EXCLUDED.instruction_url, chat_message_text = EXCLUDED.chat_message_text, lifecycle_status = 'active', closed_at = NULL, record_status = 'A', status_changed_at = now(), status_change_reason = 'guest_campaign_republished', updated_at = now();

COMMIT;

Персональные

Запускать из /opt/han-chat/backend. Публичный nginx не пропускает internal API, поэтому используем контейнер в backend-сети.

read -rsp "NOTIFICATIONS_TOKEN_PRODUCER_TEST: " TOKEN echo read -rp "USER_ID клиента: " USER_ID

NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ") EXTERNAL_ID="manual-news-$(date +%s)"

docker run --rm -i
--network han-chat-backend
curlimages/curl:latest
-sS -i
-X POST
'http://api-backend:8000/internal/notifications/v1/notifications'
-H "Authorization: Bearer ${TOKEN}"
-H 'Content-Type: application/json'
--data-binary @- <<JSON { "user_id": "${USER_ID}", "notification_type": "news", "source": "producer_test", "external_id": "${EXTERNAL_ID}", "notification_datetime": "${NOW}", "header": "Тестовое уведомление", "text": "Уведомление создано через Internal API", "details": { "details_header": "Проверка Notification Center", "details_text": "Это тестовое уведомление от producer_test." } } JSON