Notifications and email¶
Vistilla has two ways of telling people things:
- In-app notifications: the activity bell. Always on.
- Email: only for messages someone is waiting for, sent immediately.
In-app notifications¶
Rows in notifications are written when the event happens. For comments,
replies and mentions they are part of the same transaction as the comment.
resolved and watched notices are written separately; a failed watched
notice is only logged and never fails the view.
| Kind | Written by | Sent to |
|---|---|---|
comment |
a new comment (also from guests on a share link) | the video's owner, unless they wrote it |
reply |
a reply | the parent comment's author |
thread |
a reply | everyone else who has replied in the same thread ("also replied") |
mention |
an @mention | the person mentioned; only team or workspace members are accepted |
resolved |
resolving a comment | the comment's author; one per comment (resolving again replaces it), and taken back if the comment is reopened before it was read |
reaction |
an emoji reaction on a comment (members; body = the emoji) | the comment's author, unless they reacted themselves; one unread notice per person per comment, replaced on a new emoji and removed when the reaction is taken back |
video_reaction |
an emoji reaction on a video (members; body = the emoji) | the video's owner, unless they reacted themselves; one unread notice per person per video, replaced on a new emoji and removed when the reaction is taken back |
member_joined |
accepting an invitation | whoever sent it |
watched |
a viewer passing 3 seconds, or finishing | the video's owner, once per viewer (watched_notices) |
For one comment, each person gets at most one notification: a mention, else a reply to them, else a reply in a thread they are in, else a comment on their video. Nobody is told about their own actions.
The bell¶
The bell shows how many unread notices there are, counting only those whose video and comment still exist: a notice about a deleted comment, or a video in the bin, is neither counted nor listed (and comes back if the video is restored). A notice is read when:
- it is clicked in the list (website and app);
- Mark all read is pressed;
- the video it is about is opened: opening a video marks every notice about
its comments read, as they are on the screen.
watchednotices stay, since who watched is not on that page.
The count is asked for again when the page or app comes back into view, and every minute while it is in view.
GET /api/notificationslists them, with the actor's name or the guest's name and the comment text.POST /api/notifications/readmarks them read.
Email¶
Email is sent immediately, while the person waits, by
delivery::send_now. It is used for:
| Subject | |
|---|---|
| Sign-up code | 123456 is your Vistilla code |
| Team invitation | {inviter} invited you to {workspace} on Vistilla |
| Video shared by email | {name} shared "{title}" with you |
| Password reset | Reset your Vistilla password |
If sending fails, the person is told on the spot. For example, the sign-up page says the code could not be emailed.
The design (mail.rs)¶
Every email is a Mail { heading, lines, quote, action, code, note },
rendered twice:
- HTML: a single white card with rounded corners on a soft teal
background, everything centred:
- the Vistilla logo over the card, drawn with table cells and colour to
match
web/assets/logo.svg(the dark screen with its pale play mark, a border triangle rather than a character a phone would turn into an emoji, and the line of time with its orange knob, on the pale teal tile) rather than as a picture: mail clients hold pictures from an unknown sender back, Gmail among them, and this always shows; - a heading and a short line;
- either one pill-shaped teal button (the bare link is in the plain text twin) or a large code;
- the small print below the card, and the site's address (Vistilla · …), so the reader knows which instance wrote to them.
- the Vistilla logo over the card, drawn with table cells and colour to
match
The invitation is kept to the essentials: Join {workspace}, who invited them to which team, Accept invitation, and when it expires.
It is built from tables and inline styles, which is what email clients reliably support. - Plain text: the same words, for clients that show no HTML.
Mail transports¶
The first one configured wins:
- SMTP (
VISTILLA_SMTP_HOST): through lettre, with STARTTLS by default. - Brevo (
VISTILLA_BREVO_API_KEY): Brevo's HTTPS email API, for hosts that block SMTP ports. -
Webhook relay (
VISTILLA_MAIL_WEBHOOK_URL):- Vistilla
POSTs{to, subject, text, html, name, secret}as JSON; - the relay must answer
{"ok": true}.
scripts/mail-relay.gsis such a relay as a Google Apps Script, which sends from a Gmail account withMailApp.sendEmail(about 100 emails a day on a free account). The hosted instance uses this, and its emails come from vistilla.sylergy@gmail.com. - Vistilla
With no transport configured, nothing is emailed:
- sign-up codes are written to the server log instead;
- a password reset tells the person to ask the operator. The operator can
run
vistilla-api passwd.