Notifications
Tessule raises a notification when something happens that a person should know about but might otherwise miss: a usage limit is reached, an import rejects rows, a colleague mentions you in a comment, a subscription falls past due. Notifications surface in three places — a badge on the bell icon, the notification centre behind it, and (for the most serious states) a banner across the top of the app — and some kinds also send email.
If you only remember one thing: a notification explains a situation, it never enforces one. Dismissing a banner or clearing the badge changes nothing about what you or anyone else can do — the restriction a notification describes (a blocked limit, a suspended organization) is enforced by the subsystem that owns it, and it stays in force until the underlying fact changes.
Who can do what
Section titled “Who can do what”- See notifications — requires the
notifications:readaction, granted to every built-in role (Admin, Member, and Reader). - Holding
notifications:readonly lets you ask, though. Each notification kind declares who its audience is — usually the people holding the permission action that can fix the situation — and visibility is decided per notification, per person, on every read. Two admins can therefore open the same centre and see different lists, and that is by design: alerts go to whoever can act on them, never to “everyone”. - There is no separate “manage notifications” permission: nothing in the centre can be edited or deleted, only read and acknowledged.
The audience actions are ordinary actions from the
roles model — a custom role granting, say,
limits:manage also puts its holders in the audience for limit
alerts.
Conditions and events — the one distinction that explains everything
Section titled “Conditions and events — the one distinction that explains everything”Every notification is one of two kinds, and every behaviour below follows from which one it is:
- A condition is a state that is true until it isn’t — “this workspace is at its daily limit”, “this organization is past due”. Conditions never duplicate (re-detecting the same fact updates the existing entry rather than adding another) and they resolve themselves the moment the fact stops being true — when the usage window resets, the invoice is settled.
- An event is a point-in-time fact — “Tuesday’s backup failed”, “Ana mentioned you at 14:02”. Events append (three mentions are three entries) and never resolve, because a past fact cannot stop having happened. They simply age out of the list (see retention below).
Only a condition can appear as a banner: a banner is a claim about now, and only a condition can stop being true.
What generates notifications
Section titled “What generates notifications”These are the notification kinds Tessule raises today. “Who sees it” is the audience rule — the exact permission action whose holders are notified.
| Notification | Kind | Severity | Who sees it | Emailed? |
|---|---|---|---|---|
| Limit reached — a quota is exhausted and requests are being rejected | condition | critical | Workspace limit admins (limits:manage plus the action owning the affected feature); escalates to org admins (org:limits:manage) and billing (org:billing:manage) when the binding ceiling is an org policy or plan allowance |
Yes |
| Limit warning — usage passed the advisory threshold (75% by default), nothing rejected yet | condition | warning | Same as above | No — deliberately, so the 100% alert stays loud |
| Import finished with issues — a CSV import failed, or landed but rejected rows | event | warning | schema:apply holders (workspace admins); the entry names who ran the import |
Only on outright failure, not for rejected rows |
| Backup or restore failed | event | warning | Org backup admins (org:backups:manage) |
Yes |
| Domain verification lost — a verified sign-in domain’s DNS record disappeared, so its sign-in policies stopped applying | condition | critical | Org domain admins (org:domains:manage) |
Yes |
| Organization past due — the subscription fell out of good standing (trial ended, payment failed, or no payment method) | condition | critical | Org billing admins (org:billing:manage) |
Yes |
| Organization suspended — non-payment has blocked writes; data remains readable and exportable | condition | critical | Org billing admins (org:billing:manage) |
Yes |
| You were mentioned — a colleague named you in a record comment | event | info | Only the mentioned person | No |
A few deliberate absences worth knowing about:
- A clean import raises nothing. The data is simply there — a notification saying nothing went wrong is how a badge becomes wallpaper.
- Approval requests and decisions are not notification-centre items. Approvals have their own built-in emails to the approvers and requester, plus the My Approvals page — see Approvals.
- Mentions are only raised when the mentioned person can actually see the record — a mention on a record outside their visibility is suppressed, so a notification never leaks a record’s existence.
The three surfaces
Section titled “The three surfaces”Where a notification appears is derived from its severity and kind — nothing chooses its own placement:
| Condition | Event | |
|---|---|---|
| critical | banner + badge + centre | centre + badge |
| warning | badge + centre | centre + badge |
| info | centre | centre |
- The badge on the bell icon counts your unread events plus all open conditions — so acknowledging a banner drops it to the badge rather than making it vanish. It updates live (a raised notification arrives over the workspace’s realtime connection) with a slow poll as backstop.
- The notification centre (click the bell) lists everything you can see: conditions pinned first (they are claims about now), then events, newest first. Each entry shows a severity chip, the message, a relative timestamp, and — where there is somewhere useful to go — an action button deep-linking to the page where the state can be understood or fixed. Mark all read is in the header.
- The banner renders only open, unacknowledged, critical conditions —
and only one at a time (any others are noted as “+N more in notifications”).
It is always dismissible:
criticaldeliberately tops out at a banner, never a modal or a lockout.
Read vs acknowledge — two different verbs
Section titled “Read vs acknowledge — two different verbs”These are easy to conflate and the system keeps them strictly apart:
- Read is personal. Marking a notification read
(
POST /notifications/{notificationId}/read, orPOST /notifications/readfor everything at once) affects only your badge. It never changes the notification’s status for anyone else, and it does not assert the underlying fact has gone away — a still-open condition keeps its banner even after you mark it read. - Acknowledgement is shared. Dismissing a banner
(
POST /notifications/{notificationId}/acknowledge) drops it to the badge for the whole audience — one admin acknowledging means five admins don’t each dismiss the same true fact. Acknowledging does not resolve the condition and does not change what anyone can do; it only stops the app shouting about it. Events cannot be acknowledged — read state is their whole lifecycle. - Resolution is automatic. Nobody “closes” a condition by hand: it resolves when the fact it describes stops being true, whether or not anyone ever acknowledged it.
The app shell fetches the badge count and banner set in one cheap request,
GET /notifications/summary; the full list is GET /notifications (pass
status=all to include recently resolved conditions).
Kinds marked “emailed” above send a plain-text email to each person in the audience, at the address on their account. Three rules keep this channel trustworthy:
- A condition emails once. Re-detecting an already-notified condition updates the in-app entry but does not email again — no daily nagging about the same true fact.
- In-app is the record; email is a channel. Organizations have a daily cap on notification email (200/day by default across all workspaces, adjustable per plan). Past the cap the in-app notification still exists — nothing is lost, only the email.
- There are no per-user email preferences today. Which kinds email is a platform decision per kind (chosen so that only things genuinely worth an inbox entry send one); individual opt-out per kind is not currently a setting. Verify against the table above rather than assuming a toggle exists.
Browser push notifications (per device)
Section titled “Browser push notifications (per device)”Tessule is an installable web app and can show system-level notifications via your browser’s push service, using standard VAPID web push.
- Enabling: shortly after signing in you may see a one-time prompt asking
for notification (and location) permission; you can also toggle push any time
from the profile menu (your avatar, top right) — the “Push Notifications”
switch. Enabling asks the browser for permission, then registers this
browser with the server (
POST /push/subscribe). - Per device, deliberately. A push subscription belongs to one browser on
one device. Enable it on your laptop and your phone separately; disabling it
on one device (
DELETE /push/unsubscribe) leaves the others subscribed. A test or push send goes to all devices you have registered. - Testing: once subscribed, a Send Test button appears under the toggle
— it calls
POST /push/testand reports how many of your devices received it. Use it to confirm the browser-side plumbing before relying on push. - If the toggle says “Blocked”, you previously denied notification permission for the site; re-enable it from the browser’s site settings (the lock icon in the address bar), then refresh.
Retention
Section titled “Retention”Notifications are working memory, not the audit trail:
- Resolved conditions are pruned about 30 days after resolving.
- Events are pruned after about 90 days.
- Security- and billing-shaped kinds (lost domain verification, past-due, suspended) are exempt and never auto-pruned.
The authoritative record of what happened is the audit log — a pruned notification removes the reminder, never the evidence.
Q: A banner disappeared and I never dismissed it.
Either a colleague in the same audience acknowledged it (acknowledgement is
shared), or the condition resolved itself — the usage window reset, the
payment landed. Check the centre with
status=all if you want to see recently resolved entries.
Q: My colleague sees a notification I don’t. Is something broken?
No — each kind is visible only to the people holding the permission action that
can act on it. A limit alert goes to limits:manage
holders, a billing alert to org billing admins, a mention only to the person
mentioned. Your badge count is personal to what you can see.
Q: I marked everything read but the badge still shows a number. The badge counts unread events plus open conditions. An open condition keeps contributing until it resolves — that’s deliberate, because the state it describes is still true. Acknowledged conditions still count too; only resolution clears them from the badge.
Q: Can I turn off emails for a particular kind of notification? Not currently — email policy is fixed per kind (see the table). The kinds that email are chosen to be low-frequency and genuinely actionable; high-frequency kinds like mentions never email.
Q: I enabled push on my laptop but got nothing on my phone. Push subscriptions are per device. Open Tessule on the phone and enable the toggle there too.