Перейти к основному содержимому

PUT /api/admin/notifications/templates/{templateId} — Изменить/опубликовать шаблон

Назначение

Администратор платформы редактирует шаблон уведомления (NotificationTemplateEntity) — тело каналов, плейсхолдеры, имя/описание — и меняет его статус (Draft ↔ Active, то есть публикацию и снятие с публикации) с проверкой инвариантов (INV-TPL-1..3). Owning-контекст — notifications, feature group templates.

Metadata

ПолеЗначение
Сервис/контекстnotifications
API areaadmin
Feature grouptemplates
Статусdraft
Документdocs/06-services/notifications/api/admin/update-template.md

Актор и доступ

ПроверкаЗначение
Actor typeOperator(Admin)
Auth policy / Permissionsnotifications.templates.manage
Scope (RBAC)платформа
Tenant isolationне tenanted (платформенный каталог)
Auditupdate (Version ++)

HTTP-контракт

ПолеЗначение
MethodPUT
Route/api/admin/notifications/templates/{templateId}
Success status200
Idempotency headerне применяется
Correlationсквозной trace через заголовок traceparent

Входные данные / параметры запроса

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
TemplateIdrouteGuidДасуществует
Namebodystring?Нет1..128
Descriptionbodystring?Нет<=512
DefaultUrgencybodyNotificationUrgency?Нетenum
PlaceholdersbodyIReadOnlyList<NotificationPlaceholder>?Нетдопустимые для Kind
ChannelBodiesbodyIReadOnlyList<ChannelBodyInput>?Нетуникальны по Channel; плейсхолдеры ⊆ Placeholders
TargetStatusbodyTemplateStatus?НетDraft/Active (переход); архив — archive-template.md
ExpectedVersionbodylong?Нетoptimistic concurrency

Kind/Locale/Code иммутабельны (для смены — новый шаблон). ChannelBodyInput — см. create-template.md.

Модель ответа TemplateModel

Та же модель, что в create-template.md (после применения; Status актуальный).

Алгоритм

  1. Контекст и доступ. Операцию выполняет администратор платформы; требуется право notifications.templates.manage. Нет права → FORBIDDEN.
  2. Проверка входа и предусловий. Шаблон с TemplateId существует; иначе — NTF_TEMPLATE_NOT_FOUND. Если задан ExpectedVersion и он не совпадает с текущей версией — NTF_TEMPLATE_CONFLICT. Kind/Locale/Code менять нельзя (попытка → VALIDATION_FAILED). Плейсхолдеры тела входят в Placeholders (INV-TPL-2, иначе → NTF_TEMPLATE_UNKNOWN_PLACEHOLDER). Прочие нарушения формата/каналов → VALIDATION_FAILED.
  3. Правила и переходы. Применить изменения имени/описания/плейсхолдеров/тела каналов. При переходе в Active (публикация) действуют инварианты: должен быть хотя бы один включённый канал с телом (INV-TPL-3, иначе → NTF_TEMPLATE_NO_CHANNEL_BODY); на пару (Kind, Locale) допустим лишь один Active-шаблон (INV-TPL-1); системный шаблон здесь не архивируется (INV-TPL-4 — только через archive-template.md).
  4. Согласованность. Изменения шаблона и его тел каналов сохраняются в одном согласованном изменении; правка не должна затирать чужую (при конфликте версий — NTF_TEMPLATE_CONFLICT); кэш резолва шаблонов инвалидируется (сигнал TemplateChanged). Уже отправленные уведомления хранят собственный RenderedBody и не меняются.
  5. Результат. Возвращается карточка шаблона с актуальным Status.

Диаграмма

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
FORBIDDEN403нет notifications.templates.manage«Недостаточно прав»no retry
NTF_TEMPLATE_NOT_FOUND404TemplateId не найден«Шаблон не найден»no retry
VALIDATION_FAILED400попытка сменить Kind/Locale; тело/каналы вне ограничений«Проверьте шаблон»no retry
NTF_TEMPLATE_UNKNOWN_PLACEHOLDER400плейсхолдер вне Placeholders«Недопустимый плейсхолдер»no retry
NTF_TEMPLATE_NO_CHANNEL_BODY422Active без включённого канала с телом (INV-TPL-3)«Нужно тело хотя бы одного канала»no retry
NTF_TEMPLATE_CONFLICT409ExpectedVersion не совпадает с текущей версией«Повторите сохранение»retry (перечитать)

Переходы статуса и их следствия

Переход TargetStatusУсловиеСледствие для доставки
Draft → Active (публикация)≥ 1 включённый канал с телом (INV-TPL-3); единственность (Kind, Locale) по Code (INV-TPL-1)шаблон начинает резолвиться при enqueue/консюмерами для Kind/Locale
Active → Draft (снятие с публикации)шаблон перестаёт резолвиться; если действующего шаблона для Kind/Locale больше нет — enqueue/консюмеры получают NTF_TEMPLATE_NOT_RESOLVED (422/DLQ)
правка без смены статусаплейсхолдеры/каналы валидны (INV-TPL-2)новые уведомления рендерятся обновлённым телом; уже отправленные — неизменны (снапшот RenderedBody)
в Archivedтолько через archive-template.mdздесь недоступно

Пред- и постусловия

  • Предусловие. Актор имеет notifications.templates.manage; шаблон существует; при указании ExpectedVersion он совпадает с текущей версией; Kind/Locale/Code не изменяются.
  • Постусловие (успех). Применены правки имени/описания/плейсхолдеров/тел каналов; при переходе — новый Status; Version увеличена; кэш резолва инвалидирован. In-flight уведомления не затронуты.

Совместимость и наблюдаемость

  • Kind/Locale иммутабельны. Logs: template-updated/template-published (Code, TargetStatus); metrics: notifications_templates_updated_total.

Acceptance criteria

  • Given Draft-шаблон с ≥ 1 включённым каналом, when публикация (TargetStatus = Active), then 200, Status = Active; шаблон резолвится при enqueue соответствующего Kind.
  • Given Draft без включённого канала с телом, when публикация, then 422 NTF_TEMPLATE_NO_CHANNEL_BODY (INV-TPL-3), статус не изменён.
  • Given Active-шаблон, when снятие с публикации (TargetStatus = Draft) и это был единственный действующий шаблон (Kind, Locale), then 200; последующий enqueue этого KindNTF_TEMPLATE_NOT_RESOLVED.
  • Given попытка сменить Kind/Locale, when обновление, then 400 VALIDATION_FAILED.
  • Given плейсхолдер тела вне Placeholders, when обновление, then 400 NTF_TEMPLATE_UNKNOWN_PLACEHOLDER.
  • Given две конкурентные правки, when вторая приходит с устаревшим ExpectedVersion, then 409 NTF_TEMPLATE_CONFLICT; проигравший перечитывает актуальную версию и повторяет.
  • Given уже отправленные уведомления по старому телу, when шаблон отредактирован, then их RenderedBody не меняется.

Обратные ссылки

Автоссылки: где используется этот документ.

Связанные документы