Conversation
46e5b10 to
9f82cef
Compare
013d0bc to
23db50c
Compare
5b58ac1 to
f8f522b
Compare
|
|
||
| Recipient suggestions in Drive have three problems: | ||
|
|
||
| 1. They do not scale. The share modal [loads every contact and group](https://github.com/cozy/cozy-libs/blob/319c4890af0fbee641e25a2cb7c1bd2501b57024/packages/cozy-sharing/src/components/ShareRecipientsInput.jsx#L37) of the instance each time it opens, then [filters them in the browser](https://github.com/cozy/cozy-libs/blob/319c4890af0fbee641e25a2cb7c1bd2501b57024/packages/cozy-sharing/src/components/ShareAutosuggest.jsx#L43). In an organization of thousands of members, that is thousands of documents downloaded before the user types anything. |
There was a problem hiding this comment.
but it lods them from local DB, if we want to support offline mode(I'm not sure that it's relevant for sharing) we still needs to keep this cache
|
|
||
| - It knows which user is searching. Results depend on who asks (their personal contacts, the members of their organization), and the service token identifies the stack, not the user, so the stack names the user in a header. | ||
| - It accepts a service token, configured per context. | ||
| - Each result carries a display name and the emails. |
There was a problem hiding this comment.
i don't think we will need that, we will invite/search by email or display name, and inviting by phone can arrive later
There was a problem hiding this comment.
when we will do this match contact->user and vice versa, email is just one of the identifiers
| ## What changes for the clients | ||
|
|
||
| - cozy-sharing stops loading every contact and group, and calls `GET /contacts/suggest` as the user types (debounced, 3 characters minimum). | ||
| - cozy-sharing sends people as `{email}` and stops creating contacts before sharing. |
There was a problem hiding this comment.
Why by email if we don't have an email? Do we create contact now from UI before sharing? It's not a stack who creating contact?
There was a problem hiding this comment.
The stack shares with the email sends the contact collected event, and the contact comes back from Sabre through the contacts service. and we do this because sabre is our source of truth and we want to make sure this contact is available to everyone else in every app and not just stack
There was a problem hiding this comment.
mmm, it depends, I don't remeber how contact is used during sharing(probably we need instance URL for autoacceptance flow, key exchange, and etc), and we already storing or can store in the member, but if we have to have a contacts for this, it's ok to store contact reacotd at first, and then update in with info from conact service.
Especially that we wil have standalone mode, and to have external http call in the middle of "transaction" ...
So I think then during the sharing we should create contact all (but we use it for autoacceptance) or call contact sercive only after sharing was created
f8f522b to
aa9e13c
Compare
41da840 to
b2bf2ad
Compare
b2bf2ad to
a99b9d9
Compare
Status
Proposed
Date
2026-09-14
Context
Recipient suggestions in Drive have three problems:
The common contacts ADR already syncs contacts to every app through the
twake:contacts:commonexchange. ADR 058 adds a new contacts service with a search API shared by every app. This ADR describes how the stack uses that API. Where members and contacts are stored is covered by the storage ADR.Decision
GET /contacts/suggestroute, called by the share modal as the user types.The search API
The search is proposed in twake-calendar-side-service#1061:
POST /contacts/api/contacts/search?limit=&offset=with aqueryand a list of address books. It searches each address book in Sabre, merges the results and returns one vCard per contact, with its CardDAV path in_links.self.href.What the stack needs from it:
dupand has an email", and the service applies it before cutting to the top N. If the stack filters instead, the list comes up short: 30 results with 20 of them without an email leave 10 suggestions, and the next matches are never fetched./metricsendpoint #1061 takes Sabre address book ids and user ids in the body, and the stack knows neither./metricsendpoint #1061 does. From the vCard the stack only reads the name and the emails.Each context configures the full URL of the search endpoint and the OIDC client of the stack:
A context without
contacts_serviceis in standalone mode.The stack stores the CardDAV path of every contact it receives (storage ADR). It looks each result up by that path, on the org instance first, then on the user's instance. Where it is found gives its kind: a member on the org instance, a personal contact on the user's instance.
A contact the stack created at share time has no path until Sabre sends it back. When the path matches nothing, the stack tries the email with the
contacts-by-emailview.A contact can have no email, and someone without one cannot be invited. With the filter the contacts service never returns them, and the standalone search applies the same rule. The share modal already hides them today, it only lists contacts with an email or a cozy URL.
The route
GET /contacts/suggest?q=<text>&limit=<n>on the user's instance, withGETonio.cozy.contacts.qneeds at least 3 characters andlimitdefaults to 20.{ "data": [ { "type": "io.cozy.contacts", "id": "6f2a", "attributes": { "fullname": "Jean Dupont", "email": [{ "address": "jean.dupont@org.tld", "primary": true }], "cozy": [{ "url": "https://jdupont.org.tld", "primary": true }] }, "meta": { "kind": "member" } } ] }io.cozy.contactsfield names, so cozy-sharing can render them as today.meta.kindismemberorcontact, depending on where the document was found.idorkind, with the name and email from the contacts service. The client shares it by email.Standalone mode
Without a contacts service, the stack runs a case-insensitive
$regexMango query on names and emails, on the org instance and the user's instance.No existing index helps:
contacts-by-emailis an exact lookup,by-groupsandby-meanswer other reads, and a$regexcannot use an index anyway. So it stays a scan, which is fine on a standalone instance with few contacts.What changes for the clients
GET /contacts/suggestas the user types (debounced, 3 characters minimum).{email}. Today, when the typed email matches nothing, it creates the contact itself so the recipient has a document to point at. It stops, and the stack does it instead: it creates the contact, shares, publishes the address ontwake:contacts:collected, then updates that document when Sabre sends it back (storage ADR). Nothing waits on the contacts service.What to do when things fail
idand are shared by email.Consequences
Open questions
/metricsendpoint #1061 request? @chibenwainternalEmail)? @chibenwalimit, and what latency should the stack expect per keystroke?