Appearance
Subscriptions & Watchers
Concept layer — frozen. The Subscriptions & Watchers generic. Nothing here is written by a normal playbook run; a project's own feature analysis is the live document and takes every edit. This layer names no project and links to none — the dependency runs one way, from an application to its concept.
Business Context
A notification system that only reaches the people a rule already knows about serves the people the system chose, not the people who care. The colleague covering a holiday, the manager who owns the outcome but no step of it, the specialist consulted once and now invested — each is interested in an object nobody wrote a rule for, and each currently learns what happened by asking somebody.
A subscription is that person declaring the interest themselves.
Business-Level Definition
A subscription is a durable, revocable statement that an actor wants to hear about a particular object. It carries no opinion about what happens to the object and no delivery mechanism of its own: it is one input to the question who should be told, answered when something happens.
Two properties make it worth building rather than assuming:
- It is declared, not derived. A rule that infers interest from behaviour is a guess that cannot be corrected; a subscription is a decision the interested person owns and can withdraw.
- It outlives the reason it was made. Whoever subscribed stays subscribed after the assignment moves, the approval closes, or the conversation ends — which is the point, and also the source of most of the noise complaints this feature will attract.
Requirements Definition
- An actor can express interest in an object, and withdraw it, at any time.
- Interest can also arise automatically from participation, be created for the person by someone else, and be pre-declared for a class of objects rather than one at a time — all without destroying the withdrawal above.
- Interest widens who is told about an event; it never changes what the event is, and never grants sight of anything the subscriber could not already see.
Technical Context
User Stories / Use Cases
- As someone with a stake in an object, I subscribe to it and stop having to ask what happened.
- As someone who subscribed and has heard enough, I withdraw and it stays withdrawn.
- As someone responsible for a class of objects, I declare up front that a set of people should hear about every object of that class.
- As someone looking at an object, I can see who else is listening.
UI/UX Design
One toggle on the object, showing current state rather than an instruction, and a list of the current subscribers. The toggle is the whole surface; everything expensive about this concept sits behind it.
Where subscribers are pre-declared for a class of objects, that is a configuration surface belonging to whatever administers the class, not to the object.
Internationalization & Localization
No text of its own beyond the toggle and list labels, which follow the project's translation approach. The messages a subscription causes to be sent are the notification feature's text, not this one's.
Functional Requirements
A subscription is a recipient rule, not an event type
- Subscribing widens the recipient set of events that already exist. It does not introduce a parallel "something changed" event, and the subscriber receives the same named event, rendered the same way, as anyone else entitled to it.
- The consequence runs the other way too, and is the hidden cost of this concept: a subscriber can only be told about things the system already raises as events. Where the event set is thinner than the recorded history, subscribing delivers less than the interface promises — so adopting this concept usually means curating the event set first. Where the events are derived from recorded history, an entry type that is written for several reasons (a manual edit that is also a rename, a decline, a reclassification) needs the reason carried in the entry and filtered on, or the derived event says less than its name and fires more often than the event it replaced.
Provenance is part of the record
- Every subscription records how it came to exist — declared by the subscriber, created for them by someone else, inherited from a class default, or raised automatically by participation.
- Provenance is a kind — declared, class default, participation, usually one value per participation trigger, because each trigger is a decision that can be revisited — plus, where a person other than the subscriber acted, who. Whether "added by a colleague" is its own kind or an attribute on a declared subscription is the project's call; modelled as a peer value alone, it loses the actor, and "who put me on this?" must be answerable either way.
- Without it, an explicit withdrawal is silently undone the next time the automatic rule fires, and the person who unsubscribed concludes the control does not work. Provenance is what lets a withdrawal outrank a later automatic subscribe.
- A withdrawal outranks every automatic source. Whether it also outranks another person's explicit action — a colleague re-adding someone who removed themselves — is a project decision, stated in the state table and not left to the first implementation of the add endpoint, because it is the case a colleague hits first.
- Withdrawal is therefore recorded, not deleted, wherever an automatic rule could recreate it.
Automatic interest is a convenience, not a definition
- Participation — being made responsible for the object, commenting on it, being drawn into a decision about it — may create a subscription on the participant's behalf. It is the difference between a feature people use and one they never discover.
- It is also how a subscriber list becomes a list of everyone who ever touched the object. Each automatic trigger is a decision, taken once, written down, and revisited when volume complaints arrive.
Pre-declared defaults: materialise or resolve
- Defaults attached to a class of objects can be materialised into subscriptions when an object is created, or resolved from the class at the moment of notification. The choice is not a detail:
- Materialised fixes the audience at creation. Existing objects are unaffected by a later change to the default, which is predictable and auditable, and means a correction to the default never reaches the objects that need it.
- Resolved applies the current default everywhere, retroactively. A correction takes effect at once, and so does a mistake — and nobody can withdraw from a subscription that has no record.
- Materialising is the safer default precisely because it produces records that behave like every other subscription, withdrawal included.
- The same choice recurs for a subscriber that is a set of people. Expanded when the subscription is created, the audience is fixed — a later joiner is not a subscriber — and every member has a row to withdraw. Expanded at delivery, the audience follows membership, the outbound count is unbounded, and there is no row for a member to withdraw. The first is the one that behaves like every other subscription; a project choosing the second owns the fan-out risk below.
One notification per recipient per occurrence
- Recipients from every source — the rules the event already had, the subscribers, the participants — are gathered into one set, deduplicated, and only then delivered against. A person who qualifies three ways is told once.
- Deduplication is per occurrence, not per event type: two genuinely distinct changes produce two notifications even where a reader would call both "an update".
- An occurrence is one user or system action, not one persisted change. Where one action raises several named events — a confirmation that is also an edit and a state change — the project decides whether the subscriber sees all of them or one, and a correlation identifier shared by the events of one action is what makes the second answer possible at all.
Subscription is not authorization
- Entitlement to see the object is evaluated at delivery, not at subscribe time. A subscription created while someone had access, on an object whose access has since been withdrawn, must produce nothing.
- The failure mode is asymmetric: a message whose title alone discloses the object is a disclosure the access control was supposed to prevent, and it arrives by mail, outside the system that would have refused the request.
Volume is a first-class requirement
- The concept's success condition is that people stay subscribed. Every notification a subscriber did not want is an argument for withdrawing from all of them, and the withdrawal is not selective.
Non-Functional Requirements
- Resolving the recipient set is on the path of every notifiable change, so it is a read of a small, well-indexed set — never a scan of history, and never a call out to the subscribers' own systems.
- Subscriber lists are small by nature; where one is not, that is a signal about the automatic rules rather than a scaling problem to engineer around.
Performance Considerations
The hot read is who subscribes to this object — a lookup on the object identity, satisfied by one index. The second read, what does this object's class declare, is configuration and cacheable wherever defaults are resolved rather than materialised.
Transactional Operations
Subscribing and withdrawing are single-row operations, and repeating either is not an error: the same declaration twice leaves one record, which matters because the toggle will be double-clicked and the automatic rules will fire more than once for the same participation.
Where defaults are materialised at object creation, they belong to the same transaction that creates the object — a half-created object with no audience is worse than one with too large an audience.
Processes & Related Systems / Components
This concept sits between whatever raises events about an object and whatever delivers messages to people. It owns neither, which is what keeps it small.
Related concepts: Audit Log (the recorded history a subscriber's expectations will be measured against; a legitimate source of named events when the mapping is a curated allow-list of entry types, and the wrong trigger when every entry, or every entry of a broad type, becomes a notification — see the event-set requirement above), Permission Model (the entitlement re-checked at delivery), Users & Groups (a subscriber that is a set of people rather than a person), Multi-Organizations / tenant scoping (a subscription never crosses a tenant boundary).
Diagrams & Models
Resolving the audience for one change:
sequenceDiagram
autonumber
participant S as Something changes
participant R as Recipient resolution
participant U as Subscriptions
participant D as Delivery
S->>R: A named event about an object
R->>R: The event's own recipient rules
R->>U: Who subscribes to this object
U-->>R: Subscribers, with provenance
opt Defaults are resolved rather than materialised
R->>R: Add the class defaults in force now
end
R->>R: Union, then deduplicate per recipient
R->>R: Drop the actor who caused the change
loop each remaining recipient
R->>R: Re-check entitlement to see the object
alt Not entitled
R->>R: Drop silently
else Entitled
R->>D: One notification for this occurrence
end
end
The order is the content: entitlement is re-checked after the audience is assembled, and the actor is removed before anyone is told that they did something.
API Analysis (API-A)
Deliberately not specified here. The surface is small — declare, withdraw, list, and administer the class defaults — and every interesting decision in it (whether withdrawal is a delete or a state, whether one actor may subscribe another, whether the list is public to everyone who can see the object) is one this concept refers to the project. Each application documents its own.
Domain Model & Data Attribute Table
One record per (subscriber, object, provenance-bearing state). Its identity is the subscriber and the object; everything else — how it arose, whether it is currently in force — is attribute.
Where objects of more than one kind can be subscribed to, the object reference is a kind plus an identifier rather than a foreign key per kind. This is the shape that lets a second kind be adopted without a second table, and it is worth adopting at the first kind even when only one is planned, because the alternative is a migration disguised as a feature request.
The class defaults are a second, separate record: a set of subscribers declared against a class of objects, not against any object.
Data
Nothing to seed. Subscriptions describe choices people have made; a seeded subscription describes a choice nobody made.
Class defaults may reasonably be seeded, and are configuration rather than data belonging to this concept.
Logging & Monitoring
.info— a subscription created or withdrawn, with the actor, the subject, the object, and the provenance. The provenance is the field that answers "why am I getting these", which is the most common question this feature generates..warn— a subscriber dropped at delivery because entitlement no longer holds. Rare and individually harmless; a rising count means access is being revoked without the subscriptions being reconsidered..debug— an automatic trigger suppressed by a withdrawn subscription. It is the only evidence that the withdrawal-outranks-automatic rule fired, and the line that answers "why did commenting not re-subscribe me" without a database query.
Worth watching: the size distribution of subscriber lists, and the withdrawal rate. A withdrawal rate that climbs after an event is added to the notified set is that event failing its case.
Backward Compatibility and Migration
Adding a subscription source — a new automatic trigger, a new class default — silently enlarges every affected audience. It is a behaviour change for people who chose nothing, and it is the change most likely to be shipped without being recognised as one.
Removing a subscribable kind of object leaves records pointing at nothing. Where the object reference is a kind plus an identifier, nothing enforces that for you, which is the price of the shape that made the second kind cheap. The same shape means nothing removes a subscription when a single object goes: the project owes a rule — cascade with the object's own deletion, or a sweep over subscriptions whose object no longer exists — or the hot read grows with the graveyard.
Legal Context
- A subscriber list is a record of who is interested in what, and in some settings that is itself sensitive — who is watching a case, a complaint, or a personnel matter. Whether the list is visible to everyone who can see the object is a decision with a legal dimension, not only a product one.
- Messages leave the system. Where delivery includes a channel outside the product's boundary, the subscription is what determined the destination, and any obligation about where an object's content may travel is discharged — or breached — here.
Cybersecurity Considerations
The re-check at delivery is the control, and it is easy to build in the wrong place. Checking entitlement when someone subscribes is the intuitive design and it protects nothing: access changes after the subscription exists, and the subscription is long-lived by design. The check belongs on every delivery.
Who may subscribe someone else is the second decision. Allowing it makes the feature genuinely useful — bringing a colleague in is the ordinary case — and it also means one actor can direct another's notifications, including into a channel outside the product. Where that is allowed, the class defaults are the more sensitive surface, because they act on every future object at once rather than on one. The usual answer — anyone who can read the object may subscribe anyone else who can read it — has an asymmetry worth stating: a caller who cannot see the object gets the same not-found as any other read, while a subject who cannot see it is a refusal, not a silent skip.
A message's own text is a disclosure channel. Titles and summaries assembled from the object travel to whatever address the delivery mechanism holds; whatever redaction the object's own interface applies has to apply here too, or the notification is a way to read what the interface would refuse to show.
Risk Assessment
Business Risks
- Noise defeats the feature. Subscribers who are told too much withdraw entirely, and the audience for genuinely important events shrinks to the people rules already reached. The mitigation is curating the notified event set, not adding finer controls people will not open.
- A promise the event set cannot keep. An interface offering to tell someone about an object implies everything that happens to it. Where only a subset raises events, the subscriber is quietly under-informed and trusts the silence.
Technical Risks
- The withdrawal that will not stay withdrawn. An automatic rule recreating a subscription somebody removed is the defect this concept most reliably produces, it is invisible in testing that does not replay the triggering participation, and it destroys trust in the control.
- Retroactive defaults. Resolving class defaults at notification time means a configuration edit changes the audience of every existing object at once, with no record on any of them and nothing to withdraw from.
- Fan-out through a subscriber that is a set of people. Where a group subscriber expands at delivery, the expansion is where a small list becomes a large one; the count nobody bounded is the outbound message count. Where it expands at creation, the risk is the opposite and quieter: the person who joined the group afterwards hears nothing.
- Residual, deliberately not mitigated: nothing detects an audience that is too small. A subscription that was never created, or was dropped by an entitlement check that is wrong, produces silence — and silence is indistinguishable from nothing having happened.
Auditing, Reporting & Measurement
Subscribing and withdrawing are user decisions about who sees information, so they belong in the durable trail rather than in logs alone — particularly where one actor may act for another, where the trail is the only record of who enlarged the audience.
What is worth measuring is whether the feature is working as an information channel rather than as a volume source: how many objects have a subscriber who is not otherwise involved, and the withdrawal rate per notified event.
Known instances
None recorded in this copy. Add this project's instance here as it adopts the concept — one line naming the feature that implements it. This is the only place a concept may name a project, and the template ships it empty so a fork inherits no other project's entries.