Powiadomienia (w aplikacji i mailowe)
View on GitHubPowiadomienia (w aplikacji i mailowe)
Orbit informuje użytkowników o aktywności na dwa sposoby: powiadomieniem w aplikacji (dropdown z dzwonkiem) oraz mailem, w podziale na App\Enums\Notifications\NotificationType — per użytkownik, per kanał, niezależnie przełączalne w ustawieniach konta. Ta kategoria dokumentuje ten system: jak event domenowy staje się powiadomieniem, jak preferencje per-użytkownik bramkują dostarczanie, oraz jeden krok, o którym łatwo zapomnieć przy dodawaniu nowego rodzaju powiadomienia.
Przewodniki, w kolejności, w jakiej faktycznie będą potrzebne
-
Dodaj nowy typ powiadomieniaPowiadomienia (w aplikacji i mailowe)Dodaj nowy typ powiadomieniaPrzećwiczony przykład: powiadamianie członka, gdy zmieni się jego rola w projekcie — NotificationType::MemberRoleChanged. Dziś ProjectMemberService::update… — przećwiczony przykład dodania
MemberRoleChanged(powiadamianie członka, gdy zmieni się jego rola w projekcie) od początku do końca: przypadek enuma, wystrzelenie i obsłużenie eventu oraz — krok, o którym łatwo zapomnieć — wiersz w ustawieniach na froncie, który w ogóle sprawia, że nowy typ jest widoczny i przełączalny. -
Wyślij powiadomienie z własnego koduPowiadomienia (w aplikacji i mailowe)Wyślij powiadomienie z własnego koduPrzewodnik 1 pokrywa podłączenie eventu domenowego przez SendNotificationListener do NotificationService::notify(). Nie zawsze potrzebujesz eventu pomiędzy… — pełny kontrakt
NotificationService::notify()(odbiorca, typ, ważność wizualna, wiadomość, URL akcji, co dokładnie robi każdy kanał), na wypadek gdy chcesz wysłać istniejący typ powiadomienia bezpośrednio, bez wprowadzania nowego eventu domenowego. -
Przegląd połączenia frontend ↔ backendPowiadomienia (w aplikacji i mailowe)Przegląd połączenia frontend ↔ backendMapa całej funkcji: jak powiadomienia docierają do przeglądarki, jak stan read/unread wraca w obie strony i jak zakładka ustawień zapisuje preferencje. War… — jak powiadomienie faktycznie dociera do przeglądarki (to współdzielony prop Inertii, nie fetch), jak przebiega mark-as-read/mark-all-as-read/usuwanie oraz jak zakładka ustawień zapisuje przełącznik — przydatne jako mapa przed zagłębieniem się w którykolwiek z powyższych przewodników.
-
Dodaj dedykowany mail transakcyjnyPowiadomienia (w aplikacji i mailowe)Dodaj dedykowany mail transakcyjnyPrzewodnik 2 pokrywa ponowne użycie generycznego szablonu NotificationMail (jeden współdzielony układ tematu/treści/przycisku akcji dla każdego Notificatio… — przećwiczony przykład (
OwnershipTransferredMail) dla innego kształtu maila: takiego, który musi zostać wysłany bezwarunkowo, z własnym tematem i layoutem, całkowicie z pominięciemNotificationType/NotificationSetting— ten sam wzorzec, którego już używaProjectInvitationMail. -
Dodaj obsługę @mention do pola tekstowegoPowiadomienia (w aplikacji i mailowe)Dodaj obsługę @mention do pola tekstowegoPrzećwiczony przykład: system @mention już zbudowany dla komentarzy do zadań — wpisz @ w polu komentarza, wybierz członka projektu z pływającej listy podpo… — przećwiczony przykład: system
@mentionw komentarzach (IssueMentioned), od początku do końca, od wpisania@w zwykłym<textarea>aż po powiadomienie odbiorcy. Pokrywa wielokrotnego użytku technikę śledzenia zakresów (MentionRange/applyRangeEdit), która odróżnia dwie wzmianki po pozycji znaków zamiast po nazwie, oraz kontrolę po stronie backendu, która nie pozwala klientowi zgłosićmentioned_user_idsdla osoby, której treść komentarza nigdy faktycznie nie wymienia. -
Sprzątanie starych powiadomień i historii aktywnościPowiadomienia (w aplikacji i mailowe)Sprzątanie starych powiadomień i historii aktywnościPowiadomienia i wpisy dziennika aktywności gromadzą się w nieskończoność, jeśli nic ich nie usuwa. Orbit daje każdemu użytkownikowi dwa sposoby, oba w Usta… — harmonogram per użytkownik (codziennie / co tydzień / co miesiąc,
notifications:prune) oraz jednorazowe akcje "usuń starsze niż N dni" w Ustawienia → Powiadomienia: co jest usuwane, logika "należy do uruchomienia", cache oraz jak dodać wartość wieku, częstotliwość albo kolejny rodzaj danych.
Podłączenie eventu domenowego do pipeline'u powiadomień jest samo w sobie udokumentowane w ramach
../integrations/03-add-a-new-event-type.mdIntegracjeDodaj nowy typ eventuPrzećwiczony przykład: dodanie IssueCreated — rodzaju aktywności, który jeszcze nie istnieje. Dziś stworzenie issue odpala tylko IssueAssigned, i to tylko…
(na przykładzie IssueCreated) — przewodnik 1 nie powtarza tego mechanizmu, tylko pokrywa wszystko, co jest specyficzne dla typów powiadomień ponad nim: wiersz w ustawieniach, domyślne wartości kanałów oraz podział frontend/backend, którego tamten przewodnik nie dotyka.
Architektura w jednym akapicie
Każdy fakt wart powiadomienia to jeden przypadek NotificationType (np. IssueAssigned, ProjectInvited). Każde powiadomienie może pójść jednym lub obydwoma z dwóch NotificationChannel — InApp (domyślnie włączony) i Email (domyślnie wyłączony, zobacz NotificationChannel::enabledByDefault()) — a użytkownik może nadpisać dowolny kanał dla dowolnego typu poprzez wiersz NotificationSetting (user_id + type + channel + enabled; brak wiersza oznacza "użyj domyślnej wartości kanału"). NotificationService::notify() to jedyny lejek, przez który wszystko przechodzi: zawsze prosi NotificationMailService o (ewentualne) wysłanie maila, a następnie sprawdza preferencję odbiorcy dla powiadomień w aplikacji, zanim w ogóle zapisze wiersz Notification — pominięcie tego sprawdzenia zapisywałoby wiersze dla kanałów, które użytkownik jawnie wyłączył. Eventy domenowe nie wywołują notify() bezpośrednio; SendNotificationListener::handle() to jedyne miejsce, które zamienia fakt "to się wydarzyło" (IssueAssigned, CommentAdded, ProjectInvited, …) w "powiadom tę konkretną osobę, z tym tytułem/wiadomością" — zobacz
../integrations/03-add-a-new-event-type.mdIntegracjeDodaj nowy typ eventuPrzećwiczony przykład: dodanie IssueCreated — rodzaju aktywności, który jeszcze nie istnieje. Dziś stworzenie issue odpala tylko IssueAssigned, i to tylko…
po to, jak sam event jest tworzony i rejestrowany. Na froncie tablica defaultNotificationTypes w AccountSettingsNotificationsTab.tsx to ręcznie utrzymywane lustro przypadków NotificationType z backendu (ikona, tytuł, opis per typ) — nic nie generuje jej z enuma, więc nowy typ z backendu jest niewidoczny w Ustawieniach, dopóki nie dodasz tam też jego wiersza.
Popup z dzwonkiem nie renderuje całej skrzynki: współdzielony prop niesie tylko 20 najnowszych powiadomień oraz prawdziwą liczbę nieprzeczytanych, a starsze popup dociąga stronami z GET /notifications (kursor keyset, filtry nieprzeczytanych i ważności), z trybem zaznaczania do hurtowego oznaczania/usuwania — zobacz przewodnik 3.
