groups: admin-managed groups, sharing a note with one, and membership in the feed

/api/groups (admin) creates, renames and deletes groups and adds or removes
members. The member directory lists every group, and a share may name a
group_id instead of a user_id; a note's shares answer with `member` or `group`.

A note shared with a group reaches whoever is in it now, so membership is what
the feed follows: joining grants each of the group's notes to the new member's
devices, and leaving (or the group being deleted) revokes them unless a direct
share or another group still reaches that person. recipients() never counts the
note's own owner, who may sit in a group it is shared with.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 18:25:16 -04:00
co-authored by Claude Opus 5.5
parent 2e2714a50b
commit 5f3cfe8bb7
6 changed files with 358 additions and 34 deletions
+4 -2
View File
@@ -221,8 +221,10 @@ labels are personal, and a recipient files nothing under the owner's tags.
Granting or changing a share moves the note to a new revision (without touching
`updated_at`, so last-write-wins is unaffected), which is how it passes a
recipient's cursor. Ending a share — or the owner purging the note — adds the note
to the recipient's `revoked` list:
recipient's cursor. Joining a group a note is shared with does the same for the
new member (#5177). Ending a share — or the owner purging the note, the person
leaving the group, or the admin deleting it — adds the note to the `revoked` list of
each person who can no longer see it:
```json
{ "notes": [ ... ], "labels": [ ... ], "revoked": ["<note id>", ...],