Notification requirements
Table of Contents
1. Summary
Nothing in ORE Studio tells a person that something happened. A role request waits until an administrator happens to open the queue, a failed tenant setup is found on the home page, and a forgotten password has no recovery because nothing can send a mail. These are requirements for one notification subsystem that any activity in the system can use, written before anything is built.
A notification is a short, durable message to a person or to everyone who holds a permission, about one thing that happened, with a link to where it is dealt with. A component raises it from an activity it owns; the subsystem works out who receives it, keeps it until it is read, and delivers it through the channels each person has. The first users are the approval requests, built at the same time, but nothing in the subsystem knows about approvals.
2. Detail
2.1. What raises a notification
Any component, from any activity it owns. The subsystem has no list of activities: a component states the kind, the subject, the audience and the words, and the subsystem does the rest. Examples it must serve from the start:
| Activity | Who is told | What |
|---|---|---|
| A role is asked for | Holders of the permission that decides it | A request waits, with a link to it |
| A request is decided | The person who asked | Given or refused, with the reason |
| A role is given or taken away | The person | Their access changed |
| A tenant setup fails | System administrators | Which tenant, which step, the error |
| A tenant is removed | Its administrators | It is closed, and when access ends |
| An account is locked by failed sign-ins | The tenant's administrators | Who, and from where |
| A trade waits for operational authorisation | Holders of the authorising permission | The queue has work |
| A report run finishes or fails | The person who ran it | Where the output is |
| A password recovery is asked for | The account's own address | A single-use link |
2.2. Requirements
- Generic. A notification names a kind, a subject and an audience. No activity is built into the subsystem, and a new kind needs no change to it.
- Audience by person or by permission. A notification goes to named accounts or to every account that holds a permission in the tenant, resolved when it is raised, so a new administrator is not told about yesterday's requests.
- Tenant-scoped. A notification belongs to one tenant and row-level security scopes it; a system notification belongs to the system tenant.
- Durable and personal. Each recipient has their own copy, kept until they read or clear it, and a person reads only their own.
- Read state. A person sees what is unread, marks one or all as read, and clears what they no longer need. The count of unread ones is cheap to read, because it sits on every screen.
- A link to the thing. Every notification links to where it is dealt with: the request, the tenant, the account. A notification never asks a person to act inside it.
- Channels. In the application first: a bell in the header with a list, and live arrival through the server-sent event channel the screens already use. Mail second, for what a person must see without signing in, which a password recovery needs by definition. A channel is a delivery of the same notification, not a different message.
- Preferences. A person chooses, per kind, whether mail is sent as well; the in-application copy is always kept. A kind may be marked as one that cannot be turned off, such as a password recovery.
- Words in the person's language. A notification carries a kind and its values, not a finished sentence, so the screen renders it in the reader's language, as every other screen does.
- No secrets and no data beyond the subject. A notification names what happened and links to it. It carries no password, token or trade economics, because mail leaves the system; a recovery link is single-use and short-lived.
- Grouping. Many notifications of one kind about one subject collapse to one with a count, so a bulk import does not bury a person.
- Retention. Read notifications are removed after a period, as a setting.
- Audit. Whether a notification was raised, delivered and read is recorded, so "were they told?" has an answer.
- Raising never blocks the activity. A failed delivery does not fail what raised it; it is retried and recorded.
2.3. The schema
The model follows data-oriented design: keyed tables, foreign keys, and no column that holds a document. Nothing is stored as JSON.
| Table | Key | What it holds |
|---|---|---|
ores_inbox_notification_kinds_tbl |
PK code |
Each kind: its description, its message key for the screen, whether a person may turn its mail off |
ores_inbox_notifications_tbl |
PK id; FK tenant_id, kind_code, raised_by |
One thing that happened: when, by whom, and the link target as a route and an id |
ores_inbox_notification_arguments_tbl |
PK (notification_id, name); FK to the notifications |
The values the message names, one row each: the role, the tenant, the step |
ores_inbox_notification_recipients_tbl |
PK (notification_id, account_id); FKs to the notifications and the accounts |
Who receives it, and when they read or cleared it |
ores_inbox_notification_channels_tbl |
PK code |
The ways a person is reached: in_app, mail |
ores_inbox_notification_deliveries_tbl |
PK id; FKs (notification_id, account_id) to the recipients, channel_code to the channels |
One attempt to reach one recipient through one channel: when, and its outcome, an enum of pending, delivered and failed (with the reason); a recipient has many |
ores_inbox_notification_preferences_tbl |
PK (account_id, kind_code, channel_code); FKs to the accounts, the kinds and the channels |
Whether a channel is used for a kind, per person |
A permission audience is resolved into recipient rows when the notification is
raised; audience_permission_code, a foreign key to the permissions, records on
the notification which permission it was raised to.
2.4. How it relates to the approval requests
The two are built together because each is the other's first proof. A request waiting is the notification's first kind, and a decision is its second; the request's change events are what the subsystem listens to. Neither depends on the other's internals: the approval record raises notifications as any component would, and the subsystem would serve a failed tenant setup the same way.
2.5. What exists today
- A server-sent event channel from the browser backend to the screen, carrying entity change events; a notification's live arrival can use it.
- Change events published by every generated entity; a notification can be raised from them, but they are not notifications: they carry no audience and no words.
- No mail: there is no SMTP client, no mail service and no template pipeline (the password recovery capture).
2.6. Decisions
- One component. The notifications live in
ores.inbox, beside the approval requests, and know nothing of them. - In the application first. The first build has the bell, the list, read state and live arrival. Mail, with its transport and credentials, follows, first for password recovery.
- Open: whether a permission audience is resolved when raised (proposed) or when read, and the retention period.
3. See also
- Approval requests — the first activity built on it.
- The tree cannot send an email — the recovery need that makes mail a requirement.
- Workflow waiting and deadlines — the event channels a notification can travel.