Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tag Feature RFC #4

Merged
merged 23 commits into from
Jul 21, 2024
Merged
Changes from 9 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9c1dd2d
Tag Feature RFC
Neshura87 Nov 4, 2023
d8695da
Apply RFC number to PR and MD file
Neshura87 Nov 4, 2023
677e1d0
Re-Added accidentally removed template file
Neshura87 Nov 6, 2023
1a911f6
Clear Up Tag ID Language, changed examples to reflect change
Neshura87 Dec 18, 2023
f060201
Blacklist -> Blocklist renaming
Neshura87 Dec 18, 2023
d894b35
Clarify tag management role in Guide-level explanation
Neshura87 Dec 18, 2023
5a3082a
Tag amount limit added to Future possibilities
Neshura87 Dec 18, 2023
ec85436
Updating of RFC to reflect implementation of only community tags
Neshura87 Dec 18, 2023
b6afe07
Add missing ActivityPub Object Specification
Neshura87 Dec 18, 2023
2fec10f
Clarify ActivityPub Section
Neshura87 Jul 15, 2024
bcb8364
Use /tag instead of /t root for tag URLs
Neshura87 Jul 15, 2024
6824d06
Remove duplicate tag object markdown in ActivityPub section
Neshura87 Jul 15, 2024
7b85265
Adjust detailed breakdown in ActivityPub Section to reflect changed T…
Neshura87 Jul 15, 2024
7a7f442
Adjust tag object examples to reflect changed ActivityPub object stru…
Neshura87 Jul 15, 2024
57c0b22
Change wording around the new database tables
Neshura87 Jul 15, 2024
6fb66c8
Add "Global Tags" to Future Possibilities
Neshura87 Jul 15, 2024
e6f78c0
Update API Routes to reflect RFC changes
Neshura87 Jul 15, 2024
3d5c9c3
Addition to Commit #e6f78c085631f9c83c536ee58dc3524195a57b53
Neshura87 Jul 15, 2024
d582286
Remove mention of NSFW and CW tag types, Update Tag Examples & Add Ta…
Neshura87 Jul 15, 2024
ac7963f
Add API base to API routes, move tag creation to /create sub-route
Neshura87 Jul 15, 2024
31b65de
Apply suggestions from code review
Neshura87 Jul 16, 2024
740b41b
Update 0004-post-tags.md
Nutomic Jul 18, 2024
6257bc3
Various Formatting Fixes & Change reference "bigint" in flow text to …
Neshura87 Jul 20, 2024
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
324 changes: 324 additions & 0 deletions 0004-post-tags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,324 @@
- Feature Name: Post Tags
- Start Date: 2023-11-04
- RFC PR: [LemmyNet/rfcs#0004](https://github.com/LemmyNet/rfcs/pull/4)
- Lemmy Issue: [LemmyNet/lemmy#317](https://github.com/LemmyNet/lemmy/issues/317)
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved

# Summary

Ability to add descriptive tags to Posts similar to Reddit's Flair system primarily on a per-community basis.

# Motivation

Post Tags would allow for vastly improved content filtering (and to a lesser extent searching) both for Users and Admins/Moderators.

# Guide-level explanation

Tags grant you more fine grained control over the content you see on Lemmy. Certain users do not want to see certain content and tags allow you to do exactly that.

For example a lot of communities offer mixed content such as Memes, News and Discussions. Some people would like to only see News or Discussions. In such a case they could blocklist (filter out) the "Meme" tag, going forward they would not be presented with any Memes in that community.

Another use for tags is better handling of how posts are displayed. For example some people would like the content of a post to stay hidden for all users. This could be the case in a community focused on release discussions of Books, Movies, TV Shows or communities with content some users might find offensive but which is not neccesarily NSFW (for example jokes about certain topics).

In order to ensure this consistency while filtering tags can only be created by privileged users, initially that is intended to be Admins and Community moderators.

Essentially the tags serve as an easier way to message what is *inside* the post. Combining multiple tags allows for even finer control. Made a post about news in poland? Add the "News" and "Poland" tags to it and people interested exclusively in polish news can find it easily or people not interested can avoid it just as easily.
phiresky marked this conversation as resolved.
Show resolved Hide resolved

# Reference-level explanation

### Protocol:
According to https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tags a general tag object exists in the ActivityPub protocol allowing for custom implementations so long as a type is specified.
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved
To keep things simple an initial community tag object should consist of the following:
```json
{
id: number,
url: string,
name: string
}
```
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved

Entirely unmoderated tags are not an option for lemmy as the moderation workload would be too much. Additionally users being able to type out tags themselves introduces splintering in the tag contents due to typos. A better solution is a curated list of tags users can attach to their posts. The list of tags can be maintained by both admins and moderators allowing for each community to tailor tags to their specific needs.
Content for tags would be located in the respective root: `https://example.org/c/example/t/tag`
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved

The tag URL could then be utilized as a unique identifier for the tag, however doing so would restrict the ability to move the underlying tag url in the future. Instead an additional `id` field should be used. Using the object ID optional tag federation can also be achieved, allowing for communities across multiple instances to share content via tags (example: News tag shared across instances). This would also solve the issue of splintered communities across instances while not forcing it on the communities in question. For now tags will only be applicable to posts, however the general design allows for them to be attached to any kind of object later on, be that instance, community or user. The limited initial scope allows for easier modifications should any rough edges or missing features be discovered.
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved

To fill all needed use cases 3 tag flavors will be needed:

- NSFW
- Content Warning
- Generic Tag
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved

Theoretically NSFW could be implemented using a preset "Content Warning" tag but seperating out this tag allows instances to better filter it out for moderation purposes (for example if no admin/moderator is willing to moderate NSFW content).
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved
Both "NSFW" and "Content Warning" tags should blur the post body by default. Additionally the `sensitive` post flag to `true` should either of these flavors be present in the post tags to ensure correct handling on other fediverse platforms.

Example Tag Objects:

**Generic Tag:**
```json
{
"id": 1,
"url": "https://example.org/c/community/t/tag",
"name": "Generic Tag"
}
```

**NSFW Tag:**
```json
{
"flavor": "nsfw",
"id": 1,
"url": "https://example.org/c/adult_community/t/nsfw",
"name": "NSFW"
}
```

**Spoiler Tag:**
```json
{
"flavor": "cw",
"id": 1,
"url": "https://example.org/c/story_community/t/spoiler",
"name": "Spoiler"
}
```

**Remote Instance Spoiler Tag:**
```json
{
"flavor": "cw",
"id": 1,
"url": "https://example.org/c/example_community/tag@example_remote.org",
"name": "Spoiler"
}
```
Copy link
Collaborator

Choose a reason for hiding this comment

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

The "remote instance" example doesn't make sense, since the activitypub URL of the tag will stay the same regardless of which instance is looking at the post object.

The "flavor" attribute IMO doesn't make much sense and isn't really described in enough detail, it seems like instead it makes more sense to add a hierarchy: "content-warning/triggers/gore" or inherits: property to tags in the future if we want specific tags that imply generic tags.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, the remote instance example was a symptom of me not really understanding activitypub (which I think is pretty obvious by the extended fixing needed in that section so far, thank you for that a lot)

Personal style preference but I would opt for the inherits field instead of the hierarchy one, reference the parent tag URL there once and have the server resolve the tag recursively if not already known instead of shipping the entire inheritance tree with every occurrence of the tag. Especially since only the immediate parent needs to be known to sort out the correct display behaviour of a tag. Leaving the field empty (or omitting it entirely, not sure which one would be best practice) would then mean the tag is a root tag that starts a new behaviour tree (for now only display behaviour).

Including this field later should be possible but would absolutely require a way for admins and moderators to change a tag's parent from the settings (something I think is a good idea anyway).
I've moved this specific part to the Future Possibilities Section and added a bit more detail to my thoughts. I also replaced the previous example tags with the tags present in the post example, it's small change but I think it elevates the readability.

See d582286 for the changes

Copy link
Collaborator

@phiresky phiresky Jul 19, 2024

Choose a reason for hiding this comment

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

it might make sense to do what you say, but it's also a lot more complex. IMO tags shouldn't need resolution or complex whatever algorithms at all, the hierarchy should purely be a way to allow prefix-based filtering in a bit of a structured way. everything you need to know about the tag should be contained within the tag.

anyways, hierarchy is a discussion for a nother time i guess and it's good to leave it out for now


Below is an example of a News post in the news community. The post has a communtiy tag for the newspaper company that published it, as well as a content warning for Blood/Gore. In order to share this news post across instances it also is tagged with the news tag of a remote instance.
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved

Example Post json:

``` json
{
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved
"content": ". . .",
"sensitive": true,
"tag": [
{
"id": 1,
"url": "https://example.org/c/news/t/newspaper_company_1",
"name": "Newspaper Company Tag"
},
{
"flavor": "cw",
"id": 2,
"url": "https://example.org/c/viral_clips/t/blood",
"name": "Blood/Gore"
},
{
"id": 3,
"url": "https://example.org/c/tv_shows/t/news@example_remote.org",
"name": "News"
}
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved
]
}
```

### Backend:
I am not quite familiar with the Lemmy Backend so any corrections or additions for this section are appreciated.

One new tables for "community_tags" would be required. This new table would consist of the columns `url`, `name`, `flavor`, `deleted`, `ìd` and `community_id`. Additional columns for tag display style (for example background & text color) could be added later by extending this table.
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved

Additionally a table for listing the tags on posts would be needed as some Databases (at least Postgres) do not support Foreign Keys in Arrays. The table would consist of two foreign key columns: `tag_id` and `post_id` with `tag_id` being linked to the id column in the respective community tag table and `post_id` being linked to the id column of the post table.
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved

Instance Admins should have the option to delete/ban tags.
Instances with nsfw disables/blocked could/should auto reject posts with an nsfw flavor tag.

The following API routes will need to be added:

**GET /tag/list:**
Parameters:

- community_id (optional)
- auth (optional)

Returns:
List of all tags, if a community id is specified only tags of that communtiy are returned.
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved
Deleted tags should not be returned in the list unless an admin/moderator.

```json
{
"tags": [
{
"url": "https://example.org/t/tag",
"name": "Generic Tag",
"id": 1,
"community_id": 1
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved
},
{...}
]
}
```

**GET /tag:**
Parameters:

- tag_id
- auth (optional)

Returns:
Returns the information for a single tag.
Deleted tags should not be returned unless an admin/moderator.

```json
{
"tag":
{
"url": "https://example.org/t/tag",
"name": "Generic Tag",
"id": 1,
"community_id": 1
}
}
```
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved

**POST /tag:**
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved
Parameters:

- name
- flavor
- community_id (optional)
- auth
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved

Tag URL will be generated using the name and communtiy id. Specifying tag type will not be neccesarry initially as only one type exists.
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved

Returns:
Object of freshly created tag

**PUT /tag:**
Parameters:

- id
- name
- flavor
- auth

Replaces tag name and flavor with the provided info. Tag type should initially not be changeable Community Id will not be consumed as a parameter as tags should not be community transferable.
The new Tag URL will be generated using the name and communtiy id.

Returns:
Object of freshly created tag

**POST /tag/delete:**
Parameters:

- id
- deleted
- auth

Deletes the tag associated with the id. Updates `deleted` field in table. Allows for un-deleting a tag.

Returns:
Object of freshly created tag
Neshura87 marked this conversation as resolved.
Show resolved Hide resolved


Neshura87 marked this conversation as resolved.
Show resolved Hide resolved
**Additionally:**

Posts will need to be made editable by moderators, this is currently not possible but will be required to allow mods to fix missing or misused tags on posts.
Ideally the endpoint that will be opened for this should only allow the addition or removal of tags from a post and nothing else to prevent abuse.
As such I propose the use of:
`POST /post/tag` and `POST /post/tag/delete` for these roles.
Nesting these endpoints under the `/post` endpoint seems appropriate.
Shared parameters would be authentication, `post_id` and `tag_id` with an additional `delete` parameter for the delete endpoint.

Groups that should be able to add/edit the tags:
- Instance Admins of the Community
- Moderators of the Community
- Post creator

### Frontend:

**General Changes:**

Tags can be listed next to the Post title in the feed and at the end of the post in the post view.
Adding tags to a post can be implemented via a separate tag box where they can be typed in with search support.

![tags post view iamge](https://github.com/Neshura87/Lemmy-RFC/blob/main/tags_post_view.png?raw=true)

Tags in the feed should be displayed next to the post interaction elements.
![tags feed view iamge](https://github.com/Neshura87/Lemmy-RFC/blob/main/tags_feed_view.png?raw=true)



**Moderator Changes:**

Moderators need a UI Section in the community settings for adding, edditing and deleting tags. This could also implement a way to "import" a tag from another instance.
Moderators should also be able to add tags to user posts.

# Drawbacks

Adding the tag system would increase backend complexity, increased workload for alternative frontends and apps as well as add another barrier for full federation between lemmy and other services. On top of that the moderation workload would somewhat increase since posts would need to be checked for proper usage of tags as well.

# Rationale and alternatives

The proposed system aims to be a balance between the extremely limited flair feature of reddit and the often fragmented tag system of image hosting platforms, combining the best properties of both options into a theoretically ideal version of the system. Additionally the current system with a singular NSFW flag is far too inflexible to properly moderate the scope of content that falls under NSFW. Many instances have implemented a blanket NSFW ban because of this, greatly limiting what content can be posted where. Aside from that the inability to better sort content is a often discussed topic, especially story communities are desperately craving for a better option to both sort posts based on story association as well as hide/blur posts if they contain spoilers. Given the very high community demand not implementing a tag system of some sort will likely lead to a (soft-)fork of lemmy. The feature is extremely desired by many communities. An implementation of tags via UI rendering ([] brackets for tags in text would turn into a tag on a post) would be possible but ultimately far more limiting and would lead to an incosistent experience across lemmy apps/frontends as well as an inability to properly federate the tags.

# Prior art

Similar implementations can be found on Reddit as well as a great many image hosting platforms.

Reddit's Flair System is rather restrictive, a Post can only have a single custom Flair (such as "News") greatly limiting the usefullness of the feature.
Nutomic marked this conversation as resolved.
Show resolved Hide resolved

Pros:
- low moderation effort due to predefined tags
- no/little content fragmentation since typos are not possible
- no flair spam due to only 1 flair being allowed at a time

Cons:
- extreme moderation effort for 1st time setup due to inability to mix flairs
- filter lists get extremely long because all variants of a flair need to be filtered (for example "News Europe", "News America", etc. instead of just "News")
- flairs need to be created before being usable

Tag/Flair Systems on Image hosting platform generally tend to favor a more unmoderated experience, often allowing Users to type in the tags themselves.

Pros:
- enhanced user freedom when applying tags
- no delay between arising demand for tag and creation of the tag

Cons:
- greater moderation demand since tags have to be checked for inappropriate content
- very high chance for content fragmentation (typos, differences in naming things, language barriers)
- almost completely removes the ability of users to blocklist content tags (pronography would slip past a "pornography" blocklist).

# Unresolved questions

- How would tags federate/display on other Fediverse services such as Mastodon?

Choose a reason for hiding this comment

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

While it'd definitely be useful to federate tags as hashtags and such, I don't think Lemmy should restrict itself to the limitations of hashtags. Instead, consider creating an AP extension (or adopting an already existing extension if one already exists) that:

  • Allows editing of the tags themselves (renaming or otherwise)
  • Has the ability to adjust tags across instance boundaries (potentially via Accept/ Reject/ so implementations can create some sort of "tag suggestion" UI?)
  • That does not have anything to do with communities (remember: not all fediverse software need that concept!)
    • The concept of "instance-level tags" and "community-level tags" should be a concept enforced by the Lemmy backend and not ActivityPub itself

This would make it so that any other fediverse projects that want a similar level of flexibility in tags can just adopt Lemmy's extension and get interoperability "for free", even if they're built for different audiences.

Perhaps some tags could be marked as "hashtaggable", but I don't think all tags should federate as hashtags. a tag such as Spoiler does not need a hashtag. (in fact, a CW would be more appropriate!), not to mention the more hashtags you add the more Update activities you need to broadcast per tag change.

Copy link
Member

Choose a reason for hiding this comment

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

It may be worth writing an FEP about this.

Choose a reason for hiding this comment

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

I saw several discussions around content labeling, and Web Annotation Protocol is often brought up. It might be a good foundation for such FEP. No need to adopt the protocol as is, but I think their vocabulary can be useful.

- ~~Should instance wide and community tags be implemented separately or together. If separately which one should be first.~~
-> resolved, community tags will be implemented first with instance tags to follow some time later.
- There is a discussion about creation permissions for tags however that changes nothing about the fundamental functionality and can be discussed after initial experience is gathered.
- Should there be a limit on how many tags can be applied? If so, should this limit be hard coded or community configurable?
-> should be made configurable, still up for debate whether to be implemented with this RFC or later on.

# Future possibilities

Neshura87 marked this conversation as resolved.
Show resolved Hide resolved
### Filtering of user feeds based on tags

### Pre-Selected tags determined by Instance/Community/User settings:
Allows for easier handling for cases where a few tags are used very often (example: a news community could pre-select the "News" tag, thereby automatically adding it to every users post creation form)

Addition by [RocketDerp](https://github.com/RocketDerp) (Source: [GitHub Comment](https://github.com/Neshura87/Lemmy-RFC/commit/a11727bb992aa91e89354286876d7144b61b926f#commitcomment-125201367)):

Tagging of Instances, Communitites and Users using the same system.

>There are issues open on Lemmy project to have flares for users, flares for posts. I think community itself being tagged is another thing to consider and could be a means to implement a multi-community (multi-reddit) presentation system for blending communities on a post list.
>[...]
>Perhaps a scope smallint added to the proposed database table... scope 0 = all, 1 = community itself tagged, 2 = post tagged, 3 = user tagged. And community_id specific ones would have to be 2 = post.

### Migration and replacement of current "NSFW" flag in favor of "NSFW" tag:
The current flag used to mark posts NSFW can be replaced by a Instance wide default "NSFW" flag once the feature has been field tested.

### Tag Amount Limit
Unlimited Tag usage might lead to undesired situations and extra moderation effort, long term the addition of Instance or Community limits to number of tags on a Post might be useful.

### Instance wide or other tags
The basic framework should allow this system to be used in many other contexts, however due to the complexity this should be done after an initial implementation.
Areas that could use this system include:
- Instance wide post tags (for example a single instance wide NSFW tag or some such)
- User flairs
- Tags on Communities (as opposed to on Posts)