Documents: invite people to a document by email (#56) - #169
Merged
Merged
Conversation
Hosts the invite panel built for #55 over /api/documents/{id}/invites, so both domains share one control instead of duplicating the flow — the sharing model is identical and the invite payloads are byte-identical, so EmailInvite and InvitePanel are reused as-is. Service lives in a new domain partial, Services/InterlinedApiClient.DocumentInvites.cs, rather than in .Documents.cs — partial-per-domain is this repo's convention and it keeps the contended file untouched. Shapes verified live 2026-09-16 against a throwaway document, then cleaned up: GET /api/documents/{id}/invites -> 200 {"invites":[{email,role, expiresAt,accepted,createdAt,token}]} POST /api/documents/{id}/invites -> 201 {email,role,expiresAt,url} DELETE /api/documents/{id}/invites/{token} -> 200 {"revoked":true} Role and expiresAt both round-trip (probed with role "manager" and a 7-day expiry). The one real difference from the list side is the ownership envelope: documents nest the payload under "document" where lists use "data", so GetDocumentOwnerUserIdAsync reads the other key. The panel leads the Share card rather than sitting under the share links, matching the web's "Share window leads with Invite people; Make public is secondary" ordering. Hosting it costs DocumentsView.xaml one line, and the InviteTargets factory one. Closes #56 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Sep 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hosts the invite panel built in #168 over
/api/documents/{id}/invites, satisfying theacceptance criterion that documents share one invite component with the list flow rather
than duplicating it. The sharing model is identical and the invite payloads turned out
byte-identical, so
EmailInvite,InvitePanelViewModelandViews/InvitePanelare reusedunchanged — this PR adds only a service partial, a target adapter, one factory line and one
view line.
Branch / file placement
Services/InterlinedApiClient.Documents.csis in unmerged PR #139, so the service goesinto a new domain partial —
Services/InterlinedApiClient.DocumentInvites.cs.Partial-per-domain is this repo's stated convention, and
.Documents.csis not touched atall.
DocumentsViewModel.cs(do-not-touch) is untouched too, and there is no code-behindchange: the panel takes its target declaratively.
DocumentsView.xamltakes one functional line (plus a comment), inserted as the firstchild of the existing Share card's
StackPanel— no newGrid.RowDefinition, no rowrenumbering:
Placing it at the top of that card is also the product-correct ordering: per
/help/documentsthe Share window leads with "Invite people" and offers Make public /share links as the secondary option below.
Live verification (2026-09-16)
Probed with a bearer sync-token against a throwaway document I created and then
deleted — never the account's existing documents.
Both
role(probed withmanager) andexpiresAt(probed with a 7-day expiry) round-trip,even though the published OpenAPI request schema for this route lists only
email+expiresAt. The payload is identical to the list route's in every field, which is whatjustifies the shared wire type.
The one real difference is the ownership envelope:
GET /api/documents/{id}nests theresource under
"document"whereGET /api/lists/{id}uses"data", soGetDocumentOwnerUserIdAsyncreads the other key. Both payloads carryuserId(confirmedlive), which is how ownership is resolved without modifying
DocumentSummary— aModels/*file I must not touch, and one that doesn't model that field.What I deliberately did not verify
claude-probe@il-probe.invalid—.invalidis an IANA-reserved TLD that can neverresolve, so the server's fire-and-forget invite email cannot reach a person. Each invite
was revoked immediately after its shape was captured.
GET/POST /api/documents/invite/{token}). Claiming is session-cookie-only per the API docs —a bearer-token native client structurally can't do it — and it needs a second verified
account. That's the rest of epic Epic: Sharing, invites and collaboration depth #54.
notify: falseon the invite create is accepted (201) but notechoed, so I couldn't confirm it suppresses the email and did not expose a tick for
it. The web's "Email this person" tick belongs to the named-person (collaborator) flow,
where
notifyis documented — for an email invite the email is the deliverymechanism. Wiring
notifyinto the existingAddDocumentCollaboratorAsyncwould meanediting the contended
.Documents.cs, so it's left for a follow-up.Cleanup confirmed
The throwaway document
ZZ claude-probe invites 56was deleted, and a closingGET /api/documentsreturns exactly the five pre-existing documents (a-root-doc,another-root,Bespoke_Template!!!,Social Media Campaign,Untitled). The throwawaylist from #168 was deleted too —
GET /api/listsis back to justNew list.Behaviour inherited from the shared panel
Unchanged from #168, and all of it applies to documents automatically:
(
manager) collaborator cannot manage sharing. A non-owner sees a plain notice, andthe server's
404-for-non-owner (existence is never leaked) is swallowed rather thanshown as an error.
disabled with an amber Upgrade prompt. Gate is
customerStatus != "free". The inviteenever pays.
granted, so Revoke stays live while the send form is locked.
watcher/collaborator/manager;expiry Never / 7 days / 30 days; pending rows show address · role · Pending-or-Accepted ·
expiry; Copy link rebuilds the landing URL from the token (the listing returns no
url).What still needs wiring
Nothing for this issue — the card is live in the document Share panel. Remaining epic
#54 work, untouched here: the claim/resolve side (
/api/{lists|documents}/invite/{token},cookie-session-only),
GET /api/lists/shared/{token}/data, and anotifytoggle on theexisting per-person collaborator/watcher add.
Notes for review
-c Debugand-c Release(-r win-x64, 0 warnings), as doesInterlinedList.Sync.Core.Closes #56
🤖 Generated with Claude Code