feat: Центр уведомлений DC v3 (замена Novu) [C28-22…27] — код-комплит, 6/6 эпиков #60
Reference in New Issue
Block a user
Delete Branch "feat/notification-center-dc-v3"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Зонтичный PR трека notifications (C28-22…C28-27): вырезан централизованный Novu, в контроллер каждого кооператива поставлен собственный лёгкий Центр уведомлений (почта / in-app / веб-пуш) с журналом доставок и переотправкой. Каждый кооператив доставляет сам своим подписчикам напрямую (federation-инвариант:
coopnameобязателен). Источник требований — ARCH-6fe-arch-tsentr-uvedomleniy-dc-v3.Нейминг: единый порт
NotificationPort(без Novu/Center в идентификаторах).Статус: все 6 эпиков КОД-КОМПЛИТ ✅
Весь код написан и закоммичен. Ветка смержена с актуальным
dev— конфликт (@coopenomics/notifications/package.json: version+description) устранён.NotificationPort.notify, типы входа, channel-порты, роутерNotificationService, схема БД (notification_outbox+notification_deliveries), идемпотентность (sha256 + ON CONFLICT DO NOTHING).notification_inbox); шаблонизатор из каталога; нет кредов → канал тихоdisabled, наружу не стучится.@Interval-поллинг по индексу(status, scheduledAt), claim-and-send, retry с backoff[5s, 30s, 2m, 10m, 1h], реклейм зависшихSENDING, enum-статусы.triggerWorkflowв 15 сервисах переключены наnotify();@OnEvent/cron-подписки сохранены; cross-plugin порт chatcoop мигрирован.@novu/api+infrastructure/novu/*+ config + sync-сервис вырезаны (grep -ri novuпоcontroller/src= 0);subscriber_hashHMAC переведён наSERVER_SECRET; пакет@coopenomics/notificationsрепурпослен (только каталог типов + шаблоны, sync удалён); desktop@novu/jsснят.getNotifications/getNotification/resendNotification(роли chairman/member, guard поcoopname), инбокс пайщика (колокол на нативном доменномNotificationCenter+ поллингunreadCount), страница «Журнал уведомлений» по канону mono-desktop.Осталось — операторская приёмка (runtime, в CI/фоне недоступно)
Эти шаги требуют запуска на остановленном/живом контроллере, поэтому не закрываются автоматически (отсюда красный typecheck в CI: без кодогена FE/SDK не компилируются — это ожидаемо):
pnpm generate-schema+pnpm generate-client(controller) +pnpm build(sdk) — backend-резолверы эпика 6 поменяли GraphQL-схему; локально нельзя (вешает контейнер), нужно на остановленном controller или в CI.NOVU_*env →grep ERROR(DI-граф tsc не ловит).После кодогена typecheck станет зелёным.
🤖 Generated with Claude Code
EmailChannelAdapter (nodemailer, SMTP из config.email; disabled при пустом SMTP_HOST, наружу не стучится — NFR11). WebPushChannelAdapter: контроллер доставляет сам своим подписчикам напрямую через WebPushService на endpoint'ы из web_push_subscriptions по username (фикс пушей — точки доставки, не ключи); 410 → деактивация подписки. Шаблоны рендерятся из каталога @coopenomics/ notifications (controlValues.subject/body), mustache-интерполяция {{payload.x}} без liquidjs (лишняя зависимость для MVP). Порты EMAIL_CHANNEL_PORT/ WEB_PUSH_CHANNEL_PORT в NotificationCenterModule. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>feat: Центр уведомлений DC v3 (замена Novu) [C28-22…27]to feat: Центр уведомлений DC v3 (замена Novu) [C28-22…27] — код-комплит, 6/6 эпиковПолучатель без активной push-подписки (не дал разрешения / нет PWA / 410) давал {delivered:false,error} → worker ретраил 5× → терминальный FAILED: ложные «Ошибка» в журнале и warn в логах для всех, у кого push не настроен (в dev SW не регистрируется без ENABLE_PWA_DEV → у всех). Ввёл исход skipped в ChannelDeliveryResult: канал неприменим к получателю. Адаптер web-push возвращает skipped при 0 подписок / отсутствии username. Worker гасит такую строку в canceled — без ретраев, без записи попытки в журнал, без error-лога (debug); причину кладёт в lastError → тултип «Отменено» на столе председателя. Гейт на слое отправки (состояние подписки авторитетно в момент доставки), роутер outbox остаётся чистым. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>