The Join activity is not part of ActivityPub. Only Follow is.
This is extension territory. There is no specified way within Activity Streams 2.0 or special collection within ActivityPub to signal members of a group. You should not use followers unless you are dealing with Follow activities.
(The following is theoretical conjecture:)
If you wanted to pursue this further, the “weakest” way of signaling group members is to use vcard:hasMember from the VCard Ontology that is recommended by AS2 (and its prefix is part of the AS2 context document). I say “weakest” because this is literally just a JSON array and comes with none of the advantages of a collection:
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Group",
"vcard:hasMember": [
{"id": "https://social.example/users/1"},
{"id": "https://social.example/users/2"},
// ...
{"id": "https://social.example/users/100"},
]
}
Probably the “better” way is to write a FEP for a members collection and how it would work. This is pretty open-ended for now, so you would need to pretty concisely bound behavior in such a way as to be useful. For example, by defining the following provisions:
- The
memberscollection indicates that the actor acceptsJoin/Leaveactivities? - Some property like
manuallyAcceptsJoinsto indicate that theAccept Joinwill not be automatically received ~immediately? This mirrors themanuallyApprovesFollowersextension property in popular usage with current implementations in the fediverse. - Heavy consideration needs to be given to the privileges granted by being a member vs being a follower, or being both! Or being followed by the group, etc etc.
- More consideration needs to be given ahead-of-time to how to remove a member from a group, and who can do so. Something like deciding “the
attributedToactor (or some other further extensionmoderator?) can issue aRemoveactivity targeting the group’smemberscollection, or otherwise send aReject Joinat any future point, or [other potential scenarios]”.
This is an open issue for Follow activities too, and the guidance is basically like so:
- The sender of the Follow activity SHOULD include an id, just like any other non-transient activity.
- The receiver of a Follow activity SHOULD include the id received, either directly, or by embedding a (possibly partial) representation of the Follow activity they just received (within
object). - The receiver of an
Accept FolloworReject Followmay not receive an inner id on their Follow object from certain implementations, so they will have to keep track of an internal follow-request state machine and match against pending follow requests.