food-market/src/food-market.domain/Platform/PlatformSettings.cs
nns 560d52e8cd
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
feat(notifications): Web Push (VAPID) — браузерный push о минусах
Канал Web Push для центра уведомлений (item 5). Ключи VAPID генерируются один раз
и хранятся в platform_settings (без ручной настройки секретов); публичный отдаётся
фронту. Таблица web_push_subscriptions (Phase42) + /api/web-push/{public-key,
subscribe,unsubscribe}. Отправка через web-push-csharp из фонового джоба минусов
(best-effort, протухшие подписки чистятся). SW: обработчики push/notificationclick
(am-v3→am-v4), клик открывает нужный путь. Кнопка «Вкл. push» в колокольчике.
Работает в т.ч. в iOS Safari для PWA на домашнем экране.

Тесты: integration — публичный ключ стабилен, подписка идемпотентна, 400/unsubscribe
(4/4 группы); unit 299/299.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-09 03:49:32 +05:00

46 lines
2.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using foodmarket.Domain.Common;
namespace foodmarket.Domain.Platform;
/// <summary>Платформенные настройки (singleton, single-row). Хранят SMTP-креды
/// для отправки писем (forgot-password, инвайты, нотификации). Не tenant-scoped —
/// общий конфиг для всей платформы, видны и меняются только Супер-администратором.
///
/// SmtpPassword хранится зашифрованным через DataProtection API
/// (`IDataProtectionProvider.CreateProtector("foodmarket.smtp")`); снаружи
/// (контроллер) — никогда не возвращается в открытом виде, только has-password флаг.</summary>
public class PlatformSettings : Entity
{
/// <summary>SMTP-сервер для отправки исходящей почты (НЕ IMAP — IMAP это
/// для чтения входящей).</summary>
public string? SmtpHost { get; set; }
public int? SmtpPort { get; set; }
/// <summary>Implicit TLS (SMTPS, обычно порт 465). Взаимоисключающий
/// со SmtpStartTls (587).</summary>
public bool SmtpUseSsl { get; set; }
/// <summary>STARTTLS upgrade (обычно порт 587). По дефолту true в большинстве
/// современных провайдеров (Gmail/Yandex/Mailgun).</summary>
public bool SmtpStartTls { get; set; } = true;
public string? SmtpUsername { get; set; }
/// <summary>Зашифрованный SmtpPassword (base64 через DataProtection).
/// Никогда не отдаётся в API-ответах. Установка только через PUT с
/// явно переданным new-password полем.</summary>
public string? SmtpPasswordEncrypted { get; set; }
public string? FromEmail { get; set; }
public string? FromName { get; set; }
// ── Web Push (VAPID) ──────────────────────────────────────────────────────
// Пара ключей VAPID генерируется один раз при первом обращении и хранится
// здесь (стабильна между рестартами). Публичный ключ отдаётся фронту для
// подписки; приватный — только серверу (в API-ответах не возвращается).
public string? WebPushVapidPublicKey { get; set; }
public string? WebPushVapidPrivateKey { get; set; }
/// <summary>VAPID subject — mailto:/URL контакта оператора push (по умолчанию mailto:).</summary>
public string? WebPushVapidSubject { get; set; }
}