1
0
mirror of https://codeberg.org/fediverse/fep.git synced 2026-08-08 21:45:52 +00:00

FEP-34ec v2: simplify to activity references with Remove dismiss (#797)

Drop Notification type and notificationType property.
Collection holds activity references directly.
Dismiss via standard Remove (AP §6.11), activity stays in inbox.
Filter on as:type instead of notificationType.
Simplified JSON-LD context and TTL.

Based on SocialHub thread consensus with trwnh and stevebate.

Co-authored-by: automation <noreply@local>
Reviewed-on: https://codeberg.org/fediverse/fep/pulls/797
Co-authored-by: naturzukunft <naturzukunft@noreply.codeberg.org>
Co-committed-by: naturzukunft <naturzukunft@noreply.codeberg.org>
This commit is contained in:
naturzukunft
2026-03-20 21:25:28 +01:00
committed by silverpill
parent cc2ff6dafd
commit e4100b6bad
3 changed files with 86 additions and 169 deletions
+3 -5
View File
@@ -2,16 +2,14 @@
"_comment": [
"JSON-LD Context for FEP-34ec: Notification Collection Endpoint.",
"",
"This context defines the FEP-34ec vocabulary terms for notification",
"collections on ActivityPub actors.",
"This context defines the notifications endpoint property for",
"ActivityPub actors.",
"",
"See: https://w3id.org/fep/34ec"
],
"@context": {
"fep34ec": "https://w3id.org/fep/34ec#",
"Notification": "fep34ec:Notification",
"notifications": {"@id": "fep34ec:notifications", "@type": "@id"},
"notificationType": {"@id": "fep34ec:notificationType", "@type": "@id"}
"notifications": {"@id": "fep34ec:notifications", "@type": "@id"}
}
}
+81 -149
View File
@@ -5,24 +5,28 @@ status: DRAFT
discussionsTo: https://socialhub.activitypub.rocks/t/fep-34ec-notification-collection-endpoint/8568
dateReceived: 2026-03-15
trackingIssue: https://codeberg.org/fediverse/fep/issues/782
categories: ["Collections & Filtering", "Social Features"]
protocols: ["C2S"]
---
# FEP-34ec: Notification Collection Endpoint
## Summary
This FEP defines a standardized notification collection for ActivityPub actors. A new `notifications` property under `endpoints` ([ActivityPub] §5.7) provides an `OrderedCollection` containing `Notification` objects that inform the actor about relevant activities. Unlike the inbox, which receives raw activities, the notification collection holds server-generated notification objects. Notifications only exist within the collection — read notifications are removed. Batch removal is supported via [FEP-db70] (`RemoveAll`) with optional [FEP-34c1] filtering.
This FEP defines a standardized notification collection for ActivityPub actors. A new `notifications` property under `endpoints` ([ActivityPub] §5.7) provides an `OrderedCollection` containing references to activities that the server deems notification-worthy. Unlike the inbox, which serves as the delivery channel for all incoming activities, the notification collection is a curated subset — engagement-oriented events such as likes, mentions, and boosts. Dismissal of notifications uses the standard `Remove` activity ([ActivityPub] §7.5). Batch dismissal is supported via [FEP-db70] (`RemoveAll`) with optional [FEP-34c1] filtering.
## Motivation
ActivityPub defines an inbox as the primary collection for incoming activities. However, clients need to distinguish between content-oriented activities (home feed) and engagement-oriented events (notifications) — a separation that [SWICG #21] has long called for.
Today, every Fediverse software (Mastodon, Pleroma, GoToSocial, Misskey) implements notifications as a proprietary REST API without interoperability. There is no standardized ActivityPub endpoint for notifications and no vocabulary for notification objects.
Today, every Fediverse software (Mastodon, Pleroma, GoToSocial, Misskey) implements notifications as a proprietary REST API without interoperability. There is no standardized ActivityPub endpoint for notifications.
This FEP closes this gap by defining:
- A standardized endpoint under `endpoints.notifications`
- A new type `Notification` as a notification *about* an activity
- C2S operations for managing notifications (Remove, Add, [FEP-db70] RemoveAll)
- Integration with [FEP-34c1] for filtering and filtered batch operations
- A server-curated `OrderedCollection` of notification-worthy activities
- Dismissal via standard `Remove` ([ActivityPub] §7.5), batch dismissal via [FEP-db70]
- Optional filtering via [FEP-34c1]
No new types or vocabulary beyond the `notifications` endpoint property are introduced. The collection holds references to existing activities — the activity types themselves provide categorization.
## Specification
@@ -45,61 +49,29 @@ A conforming server MUST provide the `notifications` property under `endpoints`
}
```
The `notifications` property points to an `OrderedCollection` sorted by `published` in descending order (newest first).
The `notifications` property points to an `OrderedCollection` sorted by server receive time in descending order (newest first).
### 2. The `Notification` Type
### 2. Collection Contents
A notification is a distinct object that informs the actor about an activity. It is **not** the activity itself — a `Like` is an activity, the notification about it is a notification.
The notification collection contains references to activities that the server considers notification-worthy for the actor. These are typically engagement-oriented events:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/34ec"
],
"type": "Notification",
"object": "https://alice.example/activities/like-123",
"actor": "https://alice.example/actors/alice",
"notificationType": "as:Like",
"published": "2026-02-24T10:00:00Z"
}
```
| Activity Type | Typical Condition |
|---------------|-------------------|
| `Like` | Object is owned by the actor |
| `Announce` | Object is owned by the actor |
| `Create` | Actor is mentioned (to/cc/tag) |
| `Follow` | Actor is the follow target |
| `Update` | Object is owned by or observed by the actor |
#### Properties
This table is non-normative. Servers MAY include any activity type and SHOULD apply their own criteria for what constitutes a notification.
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `type` | String | MUST | `Notification` |
| `object` | IRI or Object | MUST | The activity being notified about |
| `actor` | IRI | MUST | The actor who triggered the activity |
| `notificationType` | IRI | MUST | An [Activity Streams 2.0 Activity Type][AS2-Vocab]. The value MUST be a subclass of `as:Activity`. |
| `published` | xsd:dateTime | MUST | Timestamp of the notification |
The `notificationType` property is defined with `@type: @id` in the [JSON-LD context](fep-34ec.jsonld), so string values like `"as:Like"` are automatically resolved to IRIs.
#### Notification Types
The value of `notificationType` MUST be an [Activity Streams 2.0 Activity Type][AS2-Vocab]. The following types are recommended as core vocabulary (SHOULD). Since `notificationType` can reference any AS2 Activity Type, the vocabulary is inherently extensible.
| notificationType | Triggering Activity | Description |
|------------------|---------------------|-------------|
| `as:Create` | `Create` addressed to the actor | New content (Note, Article, etc.) |
| `as:Like` | `Like` on an object owned by the actor | Like |
| `as:Announce` | `Announce` of an object owned by the actor | Boost/reshare |
| `as:Update` | `Update` of an object the actor is observing | Update |
The activities referenced in the notification collection also remain in the actor's inbox. The notification collection is a view, not a separate delivery mechanism.
### 3. Collection Semantics
The notification collection contains exclusively unread notifications:
- **Presence in the collection = unread** — there is no separate read/unread flag
- **Removal from the collection = read/dismissed** — the notification is deleted
- Notifications only exist within the collection — after removal, the object does not persist
- The server MUST create notifications when relevant activities arrive in the inbox
### 4. Pagination
The collection SHOULD support `OrderedCollectionPage` pagination. Since the collection only contains unread notifications, it typically remains small. Pagination becomes relevant only with larger volumes.
- **Presence in the collection = pending notification** — there is no separate read/unread flag
- **Removal from the collection = dismissed** — the activity itself is not deleted, only the reference in the notification collection is removed
- The server MUST add activities to the notification collection when relevant activities arrive in the inbox
```json
{
@@ -110,33 +82,46 @@ The collection SHOULD support `OrderedCollectionPage` pagination. Since the coll
"type": "OrderedCollection",
"id": "https://example.com/actors/bob/notifications",
"totalItems": 3,
"orderedItems": [
"https://alice.example/activities/like-123",
"https://carol.example/activities/create-456",
"https://dave.example/activities/announce-789"
]
}
```
Servers MAY inline the full activity objects instead of providing only IRIs. When inlining, the standard Activity Streams representation is used — no wrapper type is needed:
```json
{
"type": "OrderedCollection",
"id": "https://example.com/actors/bob/notifications",
"totalItems": 2,
"orderedItems": [
{
"type": "Notification",
"object": "https://alice.example/activities/like-123",
"type": "Like",
"id": "https://alice.example/activities/like-123",
"actor": "https://alice.example/actors/alice",
"notificationType": "as:Like",
"object": "https://example.com/posts/post-1",
"published": "2026-02-24T10:00:00Z"
},
{
"type": "Notification",
"object": "https://carol.example/activities/create-456",
"type": "Create",
"id": "https://carol.example/activities/create-456",
"actor": "https://carol.example/actors/carol",
"notificationType": "as:Create",
"object": {
"type": "Note",
"content": "Hey @bob, check this out!"
},
"published": "2026-02-24T09:30:00Z"
},
{
"type": "Notification",
"object": "https://dave.example/activities/announce-789",
"actor": "https://dave.example/actors/dave",
"notificationType": "as:Announce",
"published": "2026-02-24T09:00:00Z"
}
]
}
```
For larger volumes, the server SHOULD switch to pagination:
### 4. Pagination
The collection SHOULD support `OrderedCollectionPage` pagination. Since the collection only contains pending notifications, it typically remains small. Pagination becomes relevant only with larger volumes.
```json
{
@@ -149,57 +134,27 @@ For larger volumes, the server SHOULD switch to pagination:
### 5. C2S Operations
#### 5.1 Remove a Single Notification (Remove)
#### 5.1 Dismiss a Single Notification (Remove)
A client removes a single notification using the AS2 `Remove` activity:
A client dismisses a notification by posting a `Remove` activity to the actor's outbox, as defined in [ActivityPub] §6.11:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/34ec"
],
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Remove",
"actor": "https://example.com/actors/bob",
"object": {
"type": "Notification",
"object": "https://alice.example/activities/like-123"
},
"object": "https://alice.example/activities/like-123",
"target": "https://example.com/actors/bob/notifications"
}
```
The server MUST remove the notification from the collection and delete the notification object.
The server MUST remove the activity reference from the notification collection. The activity itself MUST NOT be deleted from the inbox.
#### 5.2 Mark as Unread (Add)
#### 5.2 Batch Dismiss (RemoveAll)
A client can mark a previously removed notification as unread by adding a new notification to the collection:
Batch dismissal is supported via [FEP-db70] (`RemoveAll`). An optional [FEP-34c1] filter can be provided to dismiss only matching notifications.
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/34ec"
],
"type": "Add",
"actor": "https://example.com/actors/bob",
"object": {
"type": "Notification",
"object": "https://alice.example/activities/like-123",
"actor": "https://alice.example/actors/alice",
"notificationType": "as:Like"
},
"target": "https://example.com/actors/bob/notifications"
}
```
The server creates a new notification and adds it to the collection. Since the original notification was deleted upon removal, this is a new object — not a restoration.
#### 5.3 Batch Remove (RemoveAll)
Batch removal of notifications is supported via [FEP-db70] (`RemoveAll`). An optional [FEP-34c1] filter can be provided to remove only matching notifications.
**Remove all notifications ("mark all as read"):**
**Dismiss all notifications ("mark all as read"):**
```json
{
@@ -213,14 +168,13 @@ Batch removal of notifications is supported via [FEP-db70] (`RemoveAll`). An opt
}
```
**Remove all notifications of a specific type (with FEP-34c1 filter):**
**Dismiss all notifications of a specific type (with FEP-34c1 filter):**
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/db70",
"https://w3id.org/fep/34ec",
"https://w3id.org/fep/34c1",
"https://w3id.org/tree"
],
@@ -232,15 +186,15 @@ Batch removal of notifications is supported via [FEP-db70] (`RemoveAll`). An opt
"relation": [
{
"type": "EqualToRelation",
"path": { "@id": "notificationType" },
"value": "as:Create"
"path": { "@id": "as:type" },
"value": { "@id": "as:Like" }
}
]
}
}
```
**Remove all notifications older than a given date:**
**Dismiss all notifications older than a given date:**
```json
{
@@ -260,11 +214,11 @@ Batch removal of notifications is supported via [FEP-db70] (`RemoveAll`). An opt
}
```
The server MUST remove and delete all notifications matching the filter. Without a filter, the server MUST remove all notifications.
The server MUST remove all activity references matching the filter from the notification collection. Without a filter, the server MUST remove all activity references.
### 6. Collection Filtering (Read)
Conforming servers SHOULD support [FEP-34c1] filtering for the notification collection. Servers MUST accept `notificationType` as an additional allowed `tree:path`.
Conforming servers SHOULD support [FEP-34c1] filtering for the notification collection. The activity `type` SHOULD be accepted as a `tree:path` for filtering.
The server signals filter support via `tree:search` in the collection:
@@ -286,14 +240,13 @@ The server signals filter support via `tree:search` in the collection:
}
```
A client that wants to retrieve only Create notifications sends a POST to the filter endpoint:
A client retrieving only Like notifications sends a POST to the filter endpoint:
**Request:** `POST https://example.com/actors/bob/notifications/filter`
```json
{
"@context": [
"https://w3id.org/fep/34ec",
"https://w3id.org/fep/34c1",
"https://w3id.org/tree"
],
@@ -301,8 +254,8 @@ A client that wants to retrieve only Create notifications sends a POST to the fi
"relation": [
{
"type": "EqualToRelation",
"path": { "@id": "notificationType" },
"value": "as:Create"
"path": { "@id": "as:type" },
"value": { "@id": "as:Like" }
}
],
"pageSize": 20
@@ -313,63 +266,44 @@ A client that wants to retrieve only Create notifications sends a POST to the fi
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/34ec"
],
"@context": "https://www.w3.org/ns/activitystreams",
"type": "OrderedCollectionPage",
"partOf": "https://example.com/actors/bob/notifications",
"totalItems": 5,
"orderedItems": [
{
"type": "Notification",
"object": "https://carol.example/activities/create-456",
"actor": "https://carol.example/actors/carol",
"notificationType": "as:Create",
"published": "2026-02-24T09:30:00Z"
"type": "Like",
"id": "https://alice.example/activities/like-123",
"actor": "https://alice.example/actors/alice",
"object": "https://example.com/posts/post-1",
"published": "2026-02-24T10:00:00Z"
}
]
}
```
### 7. Server Behavior
#### 7.1 Notification Generation
When the server receives an activity in the actor's inbox, it MUST check whether the activity triggers a notification:
| Incoming Activity | Condition | notificationType |
|-------------------|-----------|-----------------|
| `Create` | Addressed to the actor (to/cc) | `as:Create` |
| `Like` | Object is owned by the actor | `as:Like` |
| `Announce` | Object is owned by the actor | `as:Announce` |
| `Update` | Object is being observed by the actor | `as:Update` |
Servers MAY generate notifications for additional activity types.
#### 7.2 Authorization
### 7. Authorization
The notification collection MUST only be accessible to the authenticated actor. Unauthenticated requests MUST be rejected with `401 Unauthorized`.
## Security Considerations
- The notification collection contains potentially sensitive information (who interacts with whom). Access MUST be strictly limited to the owner.
- Servers SHOULD implement rate limiting for C2S operations, especially for `Add` and `RemoveAll`.
- Servers SHOULD implement rate limiting for C2S operations, especially for `RemoveAll`.
## Conformance
A conforming server MUST:
- Provide `notifications` under `endpoints` in the actor object
- Generate `Notification` objects in the collection
- Process `Remove` activities targeting the notification collection
- Delete removed notifications (not retain them)
- Populate the notification collection with references to notification-worthy activities
- Process `Remove` activities targeting the notification collection by removing the reference
- NOT delete the underlying activity from the inbox when removing from the notification collection
A conforming server SHOULD:
- Support `OrderedCollectionPage` pagination for larger volumes
- Support [FEP-34c1] filtering for the notification collection
- Accept `notificationType` as a `tree:path` in filters
- Support `Add` activities for "mark as unread"
- Support [FEP-db70] `RemoveAll` for batch removal
- Accept activity `type` as a `tree:path` in filters
- Support [FEP-db70] `RemoveAll` for batch dismissal
## Implementations
@@ -383,7 +317,6 @@ A conforming server SHOULD:
- naturzukunft, [FEP-34c1: Collection Filtering using TREE Hypermedia], 2025
- naturzukunft, [FEP-db70: RemoveAll Collection Activity], 2026
- [SWICG #21: Separation of home feed vs. notifications][SWICG #21]
- [SWICG #60: Server-local metadata under endpoints][SWICG #60]
- Sarven Capadisli, Amy Guy, [Linked Data Notifications], 2017
- [TREE Hypermedia Vocabulary][TREE]
@@ -394,7 +327,6 @@ A conforming server SHOULD:
[FEP-34ec]: https://codeberg.org/fediverse/fep/src/branch/main/fep/34ec/fep-34ec.md
[FEP-db70]: https://codeberg.org/fediverse/fep/src/branch/main/fep/db70/fep-db70.md
[SWICG #21]: https://github.com/swicg/activitypub-api/issues/21
[SWICG #60]: https://github.com/swicg/activitypub-api/issues/60
[Linked Data Notifications]: https://www.w3.org/TR/ldn/
[TREE]: https://treecg.github.io/specification/
+2 -15
View File
@@ -2,7 +2,7 @@
#
# RDFS/OWL ontology for the FEP-34ec vocabulary terms.
# This is a reference artefact — NOT loaded at runtime.
# It documents the classes and properties defined by FEP-34ec.
# It documents the property defined by FEP-34ec.
#
# See: https://w3id.org/fep/34ec
@@ -16,14 +16,7 @@
<https://w3id.org/fep/34ec#>
a owl:Ontology ;
rdfs:label "FEP-34ec Notification Collection Vocabulary" ;
rdfs:comment "Defines notification types and operations for ActivityPub notification collections." .
# ── Classes ──────────────────────────────────────────────────────────
fep34ec:Notification
a rdfs:Class ;
rdfs:label "Notification" ;
rdfs:comment "A notification informing an actor about a relevant activity. Not the activity itself." .
rdfs:comment "Defines the notifications endpoint property for ActivityPub actors." .
# ── Properties ───────────────────────────────────────────────────────
@@ -32,9 +25,3 @@ fep34ec:notifications
rdfs:label "notifications" ;
rdfs:comment "The notification collection endpoint for an actor. Used under endpoints in the actor object." ;
rdfs:range as:OrderedCollection .
fep34ec:notificationType
a owl:ObjectProperty ;
rdfs:label "notificationType" ;
rdfs:comment "The type of activity this notification is about. The value MUST be a subclass of as:Activity." ;
rdfs:domain fep34ec:Notification .