You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Sharing: role management and the notify-by-email toggle #58
change content, but not rename, change public/private, or move
Admin
also rename, switch public/private, move, delete
Adding someone or changing their role sends an in-app notification and, by default, an email. An "Email this person" tick can be unticked to skip the email; delivery also depends on the recipient's own Sharing notification settings.
Only the true owner can add people, change roles or remove them — even an Admin collaborator cannot manage sharing.
Acceptance criteria
Role selector on add and on change, using the documented three levels.
An "Email this person" toggle on the add path, defaulting to on.
Sharing management is visible only to the owner; Admin collaborators see the roster read-only.
Role semantics are enforced in the app's own affordances (an Edit collaborator does not see rename/move/visibility controls).
⚠️ The role vocabulary in this issue is wrong — the API does not accept Read-only / Edit / Admin
I wrote these issues from /help/documents, which describes three permission levels as Read-only, Edit and Admin. Those are display names. The API rejects them. Verified live 2026-09-16 on a throwaway list:
role=read-only -> 400 {"error":"Invalid role. Must be watcher, collaborator, or manager"}
role=edit -> 400 {"error":"Invalid role. Must be watcher, collaborator, or manager"}
role=admin -> 400 {"error":"Invalid role. Must be watcher, collaborator, or manager"}
role=watcher -> 201 {"email":"…","role":"watcher","expiresAt":null,"url":"…/lists/invite/OG72S9Ee…"}
role=collaborator -> 201 {"email":"…","role":"collaborator","expiresAt":null,"url":"…"}
role=manager -> 201 {"email":"…","role":"manager","expiresAt":null,"url":"…"}
So the wire values are watcher / collaborator / manager, and any UI needs an explicit mapping to the documented labels:
Wire value
Help-doc label
Can
watcher
Read-only
view content only
collaborator
Edit
change content, but not rename, change public/private, or move
manager
Admin
also rename, switch visibility, move, delete
Don't send the display names, and don't show the wire values to users.
Other live findings from #55/#56 (PRs #168/#169) that affect these issues
The invite envelopes are asymmetric, which forces a read-after-write:
POST …/invites -> 201 {email, role, expiresAt, url} ← url, NO token
GET …/invites -> 200 {invites:[{email, role, expiresAt, accepted, createdAt, token}]} ← token, NO url
DELETE …/invites/{token} -> 200 {"revoked":true}
Revoke is keyed by token, which the create response doesn't return — so creating an invite must be followed by a GET to obtain a revocable handle. Copy-link rebuilds the URL from the token.
role works despite the published OpenAPI request schema omitting it — that schema lists only email + expiresAt. Another case of the spec being thinner than reality; /help/api/sharing is right and the spec is wrong.
Error shapes: invalid email → 400 "A valid email address is required"; unknown token → 404 "Invite not found or access denied" (note: not-found and not-permitted are deliberately indistinguishable).
Ownership envelopes differ between domains — lists nest the object under data, documents under document; both carry userId, which neither ListSummary nor DocumentSummary models.
customerStatus values are free / subscriber / subscriber:monthly / subscriber:annual — any non-free value grants access, so don't compare against the literal "subscriber".
An undocumented notify:false on invite create is accepted (201) but not echoed back. It was deliberately not exposed in the UI because there's no way to confirm it actually suppresses the email — which is exactly what #58's "Email this person" toggle needs. Confirming that flag is the blocker for #58's notify toggle, and it needs a mailbox you control to verify.
The claim/accept side (/api/{lists|documents}/invite/{token}) is cookie-session-only per the docs and needs a second verified account, so it is unimplemented. That's the substance of #57.
Activity
Adron commentedon Sep 16, 2026
I wrote these issues from
/help/documents, which describes three permission levels as Read-only, Edit and Admin. Those are display names. The API rejects them. Verified live 2026-09-16 on a throwaway list:So the wire values are
watcher/collaborator/manager, and any UI needs an explicit mapping to the documented labels:watchercollaboratormanagerDon't send the display names, and don't show the wire values to users.
Other live findings from #55/#56 (PRs #168/#169) that affect these issues
The invite envelopes are asymmetric, which forces a read-after-write:
Revoke is keyed by token, which the create response doesn't return — so creating an invite must be followed by a
GETto obtain a revocable handle. Copy-link rebuilds the URL from the token.roleworks despite the published OpenAPI request schema omitting it — that schema lists onlyemail+expiresAt. Another case of the spec being thinner than reality;/help/api/sharingis right and the spec is wrong.Error shapes: invalid email →
400 "A valid email address is required"; unknown token →404 "Invite not found or access denied"(note: not-found and not-permitted are deliberately indistinguishable).Ownership envelopes differ between domains — lists nest the object under
data, documents underdocument; both carryuserId, which neitherListSummarynorDocumentSummarymodels.customerStatusvalues arefree/subscriber/subscriber:monthly/subscriber:annual— any non-freevalue grants access, so don't compare against the literal"subscriber".An undocumented
notify:falseon invite create is accepted (201) but not echoed back. It was deliberately not exposed in the UI because there's no way to confirm it actually suppresses the email — which is exactly what #58's "Email this person" toggle needs. Confirming that flag is the blocker for #58's notify toggle, and it needs a mailbox you control to verify.Still unverified for #57
The claim/accept side (
/api/{lists|documents}/invite/{token}) is cookie-session-only per the docs and needs a second verified account, so it is unimplemented. That's the substance of #57.