Skip to content
Merged
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions 172.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
NIP-172
=======

Moderated Communities (Reddit Style)
------------------------------------

`draft` `optional` `author:vitorpamplona` `author:arthurfranca`

The goal of this NIP is to create moderator-approved public communities around a topic. It defines the replaceable event `kind:34550` to define the community and the current list of moderators/administrators. Users that want to post into the community, simply tag any Nostr event with the community's `a` tag (See [NIP-33](33.md)). Moderators issue an approval event `kind:4550` that links the community with the new post.

# Community Definition

`Kind:34550` SHOULD include any field that helps define the community and the set of moderators.

```js
{
"id": "<32-bytes lowercase hex-encoded SHA-256 of the the serialized event data>",
"pubkey": "<32-bytes lowercase hex-encoded public key of the event creator>",
"created_at": "<Unix timestamp in seconds>",
"kind": 34550,
"tags": [
["d", "<Community name>"],
["description", "<Community description>"],
["image", "<Community image url>", "<Width>x<Height>"],

//.. other tags relevant to defining the community

// moderators
["p", "<32-bytes hex of a pubkey1>", "<optional recommended relay URL>", "moderator"],
["p", "<32-bytes hex of a pubkey2>", "<optional recommended relay URL>", "moderator"],
["p", "<32-bytes hex of a pubkey3>", "<optional recommended relay URL>", "moderator"],

// relays used by the community
["relay", "<relay hosting author kind 0>", "author"],
["relay", "<relay where to post requests to and fetch approvals from>"],
["relay", "<relay where to post requests to and fetch approvals from>"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, Can we add an 'optional' tag suggestion like this 👇

//optional information while forking a community from an existing one
["forksource", "34550:<source community event author pubkey>:<d-identifier of the source community>", "<Optional relay url of source community>"]

This would provide a clean mechanism for

  1. Any client to show unmoderated feeds for 'forked communities' based on the user preferences [This is not possible without this additional information]. Client can simply follow the 'forksource' tag and show the events from old community, before the timestamp of forking.
  2. Ability to see how many people have forked my community. This creates a very similar feeling of joy when someone creates a fork of my open-source repo. This provides motivation for moderators to create a quality community.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how do you know the time stamp of the forking since the created at event will change every time the community has a new moderator?

Copy link
Contributor

@vivganes vivganes Jul 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh my bad! Good point.

How about adding this suggestion instead:

["forksource", "34550:<source community event author pubkey>:<d-identifier of the source community>", "<Optional relay url of source community>","<optional timestamp of the fork>"]

This can be considered similar to creating a new git branch from a specific commit

]
}
```

# New Post Request

Any Nostr event can be a post request. Clients MUST add the community's `a` tag to the new post event in order to be presented for the moderator's approval.

```js
{
"id": "<32-bytes lowercase hex-encoded SHA-256 of the the serialized event data>",
"pubkey": "<32-bytes lowercase hex-encoded public key of the event creator>",
"created_at": "<Unix timestamp in seconds>",
"kind": 1,
"tags": [
["a", "34550:<Community event author pubkey>:<d-identifier of the community>", "<Optional relay url>"],
],
"content": "<My content>"
}
```

Community management clients MAY filter all mentions to a given `kind:34550` event and request moderators to approve each submission. Moderators MAY delete his/her approval of a post at any time using event deletions (See [NIP-09](09.md)).

# Post Approval by moderators

The post-approval event MUST include `a` tags of the communities the moderator is posting into (one or more), the `e` tag of the post and `p` tag of the author of the post (for approval notificaitons). The event SHOULD also include the stringified `post request` event inside the `.content` ([NIP-18-style](18.md)) and a `k` tag with the original post's event kind to allow filtering of approved posts by kind.

```js
{
"id": "<32-bytes lowercase hex-encoded SHA-256 of the the serialized event data>",
"pubkey": "<32-bytes lowercase hex-encoded public key of the event creator>",
"created_at": "<Unix timestamp in seconds>",
"kind": "4550",
"tags": [
["a", "34550:<Community event author pubkey>:<d-identifier of the community>", "<Optional relay url>"],
["e", "<Post Request ID>", "<Optional relay url>"],
["p", "<Post Request Author ID>", "<Optional relay url>"],
["k", "<New Post Request kind>"],
],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
],
["!", "<Community event author pubkey>"],
],

This would use #539 to make the community owner able to delete post approvals created by others (moderators).

Currently the owner can only delete its own approvals or remove moderators (which deletes all approvals from said moderator).

"content": "<New Post Request JSON>"
}
```

It's recommended that multiple moderators approve posts to avoid deleting them from the community when a moderator is removed from the owner's list. In case the full list of moderators must be rotated, the new moderator set must sign new approvals for posts in the past or the community will restart. The owner can also periodically copy and re-sign of each moderator's approval events to make sure posts don't dissapear with moderators.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about making the moderator list append only and give each moderator a expiration date? Then you can remove somebody starting last week without affecting all his approvals. As these approvals are even bigger than whatever they are approving, duplicating them should not be overly encouraged.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it works because the expired moderator can post in the past. I don't think that should be allowed once a moderator is kicked out.


Replaceable events can be submitted for approval in two ways: (i) by their `e` tag if moderators want to approve each individual change to the repleceable event or (ii) by the `a` tag if the moderator trusts the original post author to not modify the event beyond community rules.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a third interesting option here to approve by both the a and e tag. This gives the benefit of ii but would also allow the client and moderation tools to easily flag replaceable events that have changed since approval without losing the connection to the community immediately. An alternative wording that could describe this:

Suggested change
Replaceable events can be submitted for approval in two ways: (i) by their `e` tag if moderators want to approve each individual change to the repleceable event or (ii) by the `a` tag if the moderator trusts the original post author to not modify the event beyond community rules.
Post-approval for replaceable events MAY include an `a` tag in place of or in addition to the `e` tag to ensure that the event remains connected to a moderated community after being edited. Clients SHOULD indicate that replaceable events with an approval on the `a` tag, but a conflicting `e` tag have been edited after approval.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, but we might need to spell that out as a third (preferred?) option

Copy link

@armstrys armstrys Jul 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. Something like this?

Suggested change
Replaceable events can be submitted for approval in two ways: (i) by their `e` tag if moderators want to approve each individual change to the repleceable event or (ii) by the `a` tag if the moderator trusts the original post author to not modify the event beyond community rules.
Post-approval for replaceable events can be submitted in three ways (i) by their `e` tag if moderators want to approve each individual change to the replaceable event, (ii) by the `a` tag if the moderator trusts the original post author to not modify the event beyond community rules, or (iii) preferably with both the `a` and `e` tag so that clients can indicate if a post has been edited since approval.

Reasoning for changing that first line was that I had some confusion initially reading the spec whether it was the original post or the moderator approval post that these rules applied to. It is of course obvious once you understand the spec.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just committed a change as well. See if you like it

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vitorpamplona your latest changes LGTM!


Clients SHOULD evaluate any non-`34550:*` `a` tag as posts to be included in all `34550:*` `a` tags.

# Displaying

Community clients SHOULD display posts that have been approved by at least 1 moderator or by the community owner.

The following filter displays the approved posts.

```js
{
"authors": ["<Author pubkey>", "<Moderator1 pubkey>", "<Moderator2 pubkey>", "<Moderator3 pubkey>", ...],
"kinds": [4550],
"#a": ["34550:<Community event author pubkey>:<d-identifier of the community>"],
}
```

Clients MAY hide approvals by blocked moderators at the user's request.