admin-panel/test_notifications.py):
delete-builtin → reject, залоченный маршрут
(CHECK (enabled OR NOT locked)), in_app не выключить.
Здесь — слой диспетчера и доставки: идемпотентность,
расщепление FK, две модели адресации.
ondelete расщеплён намеренно
Аудит доставки переживает удаление канала
(channel_id → SET NULL, строка цела), но
уходит за уведомлением и пользователем (CASCADE). Легко
перепутать — держим отдельным тестом с явным противопоставлением.
@pytest.mark.integration — весь слой доставки идёт
против реальной БД
user_id = NULL) идемпотентен без пользователя — UNIQUE(notification, channel) держит одну строкуchannel_id), не конфликтuser_id), уникальность per-userdeliveries.channel_id = NULL, строка-аудит цела, факт доставки сохранёнnotification_channels: его notification_routes уходят каскадом (channel_id → CASCADE, маршрут — конфиг), а deliveries.channel_id → NULL (SET NULL, аудит цел); тот же родитель, разный ondelete у двух детей → Каналы и маршрутыnotifications → его строки доставки уходят каскадомusers → его личные строки доставки уходят каскадомondelete у трёх FK одной таблицыowner / admin, status=active), веер вычисляется запросом, не колонкойagent / account адресованы одному пользователю; FK → users, ON DELETE CASCADEinfo / warning / critical — вне словаря → отказ БД; ортогонален event_typesync · security · budget · system · discovery · agent · account; чужое значение → отказ БДusers → его строки настроек уходят каскадомagent · account: email opt-in false), НЕ глобальный «оба включены»true, личные falsequeued / sent / failed / read; чужое значение → отказ БДread допустим лишь для in_app-доставки; email / webhook в read не переходятstate двигает updated_at строго вперёд (новое > прежнего)failed сопровождается заполненным errorsent проставляет sent_at; read проставляет read_atread; после пометки уменьшаетсяread → read_at; идемпотентно (повтор — no-op); только для in_app404 (не раскрываем существование); аноним → 401
Слой доставки целиком интеграционный — CHECK, FK и триггеры проверяются
против реального PostgreSQL. Конфиг-матрица (каналы, маршруты, дедуп,
засев builtin) живёт в
admin-panel/tests.html и здесь не дублируется.
tests/notifications/каталог модуля
conftest.pytestcontainers PG, фабрики уведомление / канал / доставкаintegration/против реальной БД
delivery-idempotency · delivery-fkключ идемпотентности, расщепление ondeleteaddressing · prefs · delivery-stateдве модели адресации, личное сужение, машина состояния