Preferences
How VitNode decides which notifications each user receives in the notification list, as push and by email - installation policy, mandatory types, user choices and time zone.
Users choose, per notification type, whether it shows in their notification
list, whether it comes as push, and how it reaches them by email. Core builds the preferences page at /settings/notifications
from the registered types, so a new plugin's types appear there with no
migration and no UI code.
The settings page
/settings/notifications has two parts:
- Where notifications reach you - push and email for the whole account. Push asks the browser for permission on this device. The Email switch turns notification email off for every type the member can change, after a confirmation, and on again - back to exactly what they had, or to the installation defaults after a reload.
- What you get notified about - one accordion row per type, grouped by category. The bell, phone and mail icons show at a glance what is on. Open a row to flip each channel and pick the email frequency: right away, the daily digest or the weekly digest.
Every change saves instantly and says so with a toast.
Push is coming
Push choices are stored and respected by the policy today, but VitNode does not deliver push yet. Members can set them up now, so nothing changes for them when delivery lands.
How core decides
One function decides what a user receives, in this order:
- Installation policy disabled the type → nothing. Mandatory types ignore this.
- Mandatory type → always in-app. Email follows the installation default.
- The user's own choice for the type - skipped when the type is locked for members (Member can edit off in the AdminCP).
- The installation default for the type, set in the AdminCP.
- The type's own
defaults.
When the AdminCP sets the notification list to Disabled for a type, it
never lands in the list, whatever the user picked - email can still go out.
Locked types show a "Set by the admin" badge in the member's settings, and the
API refuses changes to them with 400.
The notification list, push and email are resolved separately. A user can take a type by email only, in the list only, any mix or nothing at all. Push is on by default wherever the installation allows it.
When email is available
A type can email only when all three allow it:
- the type declares
email; - an email adapter is configured;
- the type's policy in the AdminCP does not set email to Disabled.
There is no installation-wide email switch: to stop a kind of email, disable email on that type.
When any of them says no, the user sees no email choice for that type and gets
none.
Example
forum.topic_reply defaults to { inApp: true, email: "daily" }. An
administrator changed its email default to weekly.
| User | In-app | |
|---|---|---|
| Never opened preferences | yes | weekly - installation default |
Chose immediate | yes | immediate - their choice |
| Turned in-app off | no | weekly - email is independent |
| Any user, after email is Disabled | yes | none |
What users can change
PUT /api/@vitnode/core/notifications/preferences accepts a partial update:
{
"types": {
"forum.topic_reply": { "inApp": true, "push": false, "email": "weekly" }
}
}The route answers 400 for an unknown type, a change to a mandatory or locked
type, a channel the installation switched off for that type (list, push or
email), or an email mode the type cannot send. Choices are
stored per user and merged, so saving one type never resets another.
Digests
Daily digests go out at 08:00 and weekly digests on Monday at 08:00, in the member's time zone. Nobody picks the hour or the day - one predictable schedule keeps digests simple. See Email and digests.
Time zone
The time zone belongs to the account, not to notifications: it is the
timeZone column on core_users, and members change it under Region on
/settings. It takes any IANA name, like Europe/Warsaw, or null to follow
the time zone of their language, then UTC. Use this device's time zone
fills it in from the browser.
PUT /api/@vitnode/core/users/me/time-zone
Content-Type: application/json
{ "timeZone": "Europe/Warsaw" }An unknown name answers 400. A save emits
user.updated and refreshes the session,
so c.get("user")?.timeZone sees the new value on the next request.
Mandatory types and account email
A type with mandatory: true is for notices users must not miss in their inbox,
like "your account role changed". It is always delivered in-app and shows
as fixed on the preferences page. Its email follows the
installation default, as long as email is available.
Account email is not a notification
Password resets, email verification and sign-in codes stay on
c.get("email").send(). They never pass through notification preferences,
type policies or digests, so a user who turned every notification off still
receives them.
Related
Inbox and realtime
How VitNode's notification inbox tracks read state, groups events, keeps the unread count exact and pushes it live over the WebSocket - plus the REST endpoints and frontend components.
Email and digests
How VitNode sends notification email - immediate messages and daily or weekly digests in each user's time zone, with delivery records, retries, idempotency keys and send-time checks.