github.com/cozy/cozy-stack@v0.0.0-20240327093429-939e4a21320e/docs/sharing-design.md (about) 1 [Table of contents](README.md#table-of-contents) 2 3 # Sharing design 4 5 ## Baseline 6 7 Here we detail the baseline of the Cozy sharing design and provide some core 8 statements. 9 10 ### Data sync 11 12 - The shared data is duplicated among members: it is both on the sharer's cozy 13 (the owner), and on the recipients' cozy. This is a core difference compared 14 to a federated sharing such as the one in 15 [NextCloud](https://docs.nextcloud.com/server/latest/user_manual/files/federated_cloud_sharing.html). 16 - The [CouchDB replication 17 protocol](https://docs.couchdb.org/en/stable/replication/protocol.html) is 18 used to synchronize the documents. It means that the documents will be same 19 on the owner side and on the recipients side ("symmetric sharing"). 20 - The applications say what is shared, the cozy stack synchronizes that. The 21 stack does the low-level work and gives primitives to the applications. The 22 applications must use them in a responsible manner, and in particular, to 23 avoid transitivity issues. 24 - The applications should know how to deal with documents' conflicts, e.g. what 25 to do with a document updated by several members at the same time with 26 different content. At least, the default [CouchDB 27 behaviour](https://docs.couchdb.org/en/stable/replication/conflicts.html) to 28 handle conflicts and select winning revisions should be acceptable if the 29 applications don't do anything to detect and resolve conflicts. 30 31 ### Contacts discovery 32 33 - A sharer may not know the addresses of the recipients' cozy instances, but 34 he/she has a way to send them an URL on his/her cozy to start the process. 35 36 ### Recipient preview 37 38 - A recipient can preview a sharing before accepting it if the application 39 supports this option. Else, he/she will have only the description and rules to 40 make his/her mind about accepting or refusing the sharing. 41 42 ### Specific data type support 43 44 - For files and folders, the documents replication process (the replicator) is 45 customized to handle the specificities of the 46 [io.cozy.files](https://github.com/cozy/cozy-doctypes/blob/master/docs/io.cozy.files.md) 47 doctype. 48 - The applications must be able to work with broken 49 [relationships](https://github.com/cozy/cozy-doctypes/#relationships) between 50 documents, which can happen if one shares a document without its relationships. 51 52 ### Safety principles 53 54 - _First safety principle_: when a user B accepts a sharing from user A, the 55 documents that were on the user B's cozy before the sharing are not sent to 56 user A without an explicit action of user B (like moving a file to a shared 57 directory). 58 - _Second safety principle_: when two users, A and B, are sharing documents, a 59 change of a document on the user A's cozy can't make an exiting document of 60 user B enter in the sharing. 61 62 ## Setup of a sharing 63 64 ### Step 1: the owner creates the sharing 65 66 One person decides to share something with other people from an application on 67 her cozy. In our example, Alice wants to share a todo list with her friends, Bob 68 and Charlie, and it is done from the _Todo_ application. The application calls 69 the stack with the rules for this sharing, including the documents to target and 70 the rights granted to the recipients, to add/update/delete todos. It also 71 specifies the contacts with whom to share by providing their identifiers. 72 See the [sharing schema](#description-of-a-sharing) for a complete description 73 of the expected fields. 74 75 The stack persists an `io.cozy.sharings` document and sends 76 an email to the recipients (Bob an Charlie). 77 78 ### Step 2: a recipient accepts the sharing 79 80 A recipient, let’s say Bob, receives the email and clicks on the link. His 81 browser shows him the _Todo_ application on Alice’s Cozy so that he can preview 82 the todo list, and a modal asks him if he wants to continue the sharing 83 acceptation workflow. If he does, a form will ask him what is the address of his 84 Cozy (the form can be pre-filled if he has already accepted another sharing in 85 the past). After he has filled the form and submitted it, he is redirected on 86 his Cozy. If he is not logged in, he has to login first. Then, a page describes 87 him how the sharing will work and what technical permissions it implies. It also 88 asks him to confirm the sharing. If he accepts, his instance will send to 89 Alice’s instance the answer. 90 91 ### Step 3: the initial replication starts 92 93 Alice’s Cozy instance creates some tokens and sends them with other informations 94 such as the response of the answer request from Bob’s instance. At this moment, 95 both instances are ready to start to replicate data to the other instances. So, 96 let’s do the initial replication. 97 98 Alice’s instance starts to fill the `io.cozy.shared` database with all the 99 documents that match a rule of the sharing (except the rules with 100 `local: true`), and create triggers for the future documents to be also added in 101 this database (the exact triggers depend of the parameters of the rules). And, 102 when done, it creates a job for the replicator, and setups a trigger for future 103 changes in the `io.cozy.shared` to start a replicator job. This mechanism is 104 further explained in [the data sync](#data-sync) section. 105 106 Bob’s instance also checks if any document matches a sharing rule. In most 107 cases, it won’t. But in some very special cases (e.g. a previous revoked sharing 108 on the same documents), there are some documents that match a rule. They are 109 added to the `io.cozy.shared` database, but with a `conflict` flag. They won’t 110 be replicated unless Bob accepts to in his _Todo_ application. Triggers are also 111 added on Bob’s instance for filling the `io.cozy.shared` database, and to call 112 the replicator after that. 113 114 **Note:** there is a lock around the initial filling of the 115 `io.cozy.shared` database to avoid concurrency issues if two recipients accept 116 the sharing at the same time. 117 118 ## Data sync 119 120 As stated in the baseline, the shared data is copied among the databases of all 121 the members for a sharing. 122 Therefore, contrarily to centralized or federated sharing, where the same data 123 is accessed by all members, extra work must be done to replicate changes between 124 all members. 125 126 The replication mode is specified in a sharing rule for each document action: 127 add, update or delete. It can be: 128 129 - `none`: the changes won't be replicated between members. 130 - `push`: only the changes made by the owner will be propaged to the recipients. 131 - `sync`: the changes made by any member are propagated to the other members. 132 133 See the [sharing schema](#description-of-a-sharing) for more details and 134 examples. 135 136 The data synchronization is based on the document's revisions. Each time a 137 document is updated in database, a new revision is created with the following 138 format: `1-abc`, where `1` is a number incremented at each new change and `abc` 139 a hash of the document. 140 The revisions history of each shared document is saved in a `io.cozy.shared` 141 document. This history is used to compare revisions between sharing members and 142 propagate updates. Hence, not only the shared documents are synced, but also 143 their whole revisions history through the `io.cozy.shared` database. See the 144 [revisions syncing](#revisions-syncing) section for a complete example. 145 146 ### General workflow 147 148 In the following, we assume the a `sync` sharing for all actions between Alice, 149 Bob and Charlie. 150 151  153 154 **Step 1:** a todo item is added on Bob’s Cozy, a trigger is fired and it adds 155 the new document to the `io.cozy.shared` database 156 157 **Step 2:** a debounced trigger on the `io.cozy.shared` database is used to 158 start a replicator 159 160 **Step 3:** the replicator does the following steps 161 162 - it queries a local document of the `io.cozy.shared` database to get the last 163 sequence number of a successful replication 164 - with this sequence number, it requests the changes feed of `io.cozy.shared` 165 with a filter on the sharing id 166 - the results is a list of document doctype + id + rev that is sent to Alice’s 167 Cozy 168 - Alice’s Cozy checks which revisions are known, and send a response with the 169 list of those that are not 170 - for each not known revision, Bob’s Cozy send the document to Alice’s Cozy 171 (in bulk) 172 - and, if it’s all good, it persists the new sequence number in the local 173 document, as a start point for the next replication 174 175 **Step 4:** the changes are put in the `io.cozy.shared` database on Alice’s Cozy 176 177 **Step 5:** it starts a replicator on Alice’s Cozy 178 179 **Step 6:** the replicator send the changes to Charlie’s Cozy, all the cozy 180 instances are synchronized again! 181 182 **Note:** when a todo item is moved fron a shared todo list to a not shared todo 183 list, the document in `io.cozy.shared` for the todo item is kept, and the 184 sharing id is associated to the keyword `removed` inside it. The `remove` 185 behavior of the sharing rule is then applied. 186 187 ### Revisions syncing 188 189 Here, we detail the internals of the revisions-based syncing mechanism through 190 an example: Alice, Bob and Charlie share a Todo with the id "todo1". Note that 191 in reality this id would be an UUID, but we give it a simple name for the sake 192 of clarity. 193 194 This Todo had only one update (its creation), made by Alice that generated the 195 revision `1-a`. 196 After the initial replication, all the members have a `io.cozy.shared` document, 197 with this sole revision as history. This history is 198 actually a tree: when a CouchDB conflict occurs, a new branch is created, 199 containing the losing revision, so we can keep track of it and avoid losing any 200 data. Note the document id is in the form `<doctype>/<docid>` to easily 201 reference the shared document. Here, it is `io.cozy.todos/todo1`. 202 203 In the sequence diagram below, we illustrate the steps occuring when Alice 204 generates updates. We also illustrate how a CouchDB can occur and how it is 205 handled, by making Charlie updating the same document than Alice at the same 206 time. This update leads to a conflict between the revisions `2-a`, generated by 207 Alice, and `2-c`, generated by Charlie: a winning revision is then elected 208 by CouchDB, `2-a`, but `2-c` is saved in another branch of the revision tree. 209 Thanks to it, the conflict is propagated to other members that will be able to 210 resolve it through the Todo application (by manually erasing or merging the 211 conflicted revision for instance). 212 213 Eventually, all members converge to the same state with the same docs and the 214 same revisions histories. 215 216  217 218 ### CouchDB conflicts 219 220 A [CouchDB 221 conflict](https://docs.couchdb.org/en/stable/replication/conflicts.html) is when 222 a document has conflicting revisions, i.e. it has at least two revisions 223 branches in its revision history. Hence, these conflicts are made on the 224 database level. 225 [By 226 design](https://docs.couchdb.org/en/stable/replication/protocol.html#upload-batch-of-changed-documents), 227 CouchDB can produce conflicts in its replication protocol, as the revision 228 history is replicated and forced among nodes. 229 230 We detail [here](https://docs.cozy.io/en/cozy-stack/couchdb-quirks/#conflicts) 231 how a CouchDB conflict can be made. 232 233 In the particular case of files and folders, we implemented specific strategies 234 to avoid having to deal with conflicts at the application level: the stack is 235 able to prevent CouchDB conflicts for `io.cozy.files` documents and enforce 236 [reconciliation](#conflict-resolution) when possible. We also detail what is 237 done when [no reconciliation](#conflict-with-no-reconciliation) can be made. 238 239 ### Id transformations 240 241 Initially, we were using the CouchDB protocol revision as described above, but 242 we have introduced a transformation of the identifiers for io.cozy.files, and 243 later, we have generalized this transformation for all doctypes. It means that 244 Alice and Bob have the same shared documents, but not with the same 245 identifiers. The identifiers are transformed with a XOR, using a key exchanged 246 when the recipient accepts the sharing. 247 248 In practice, it is useful when someone is revoked from a sharing, and accepts 249 later the sharing again. It allows to avoid reusing the same identifiers for 250 documents exchanged on the first sharing and on the second sharing, which can 251 create some weird situations. For example, a cipher is shared between Alice and 252 Bob when its revision is 3-aaa. Later, when the sharing is revoked, the 253 document will be deleted on Bob's instance (the ciphers are deleted on 254 recipients when a sharing is revoked), which creates a revision 4-bbb. If Alice 255 invites Bob again, and Bob accepts, the replication will sent the document from 256 Alice's instance to Bob's instance with revision 3-aaa. CouchDB will say OK, 257 but the revision 4-bbb will still be seen as a successor of 3-aaa, and for 258 CouchDB, the document will still be deleted. Using different IDs for the first 259 and second sharing fixes this issue. 260 261 ## Files and folders 262 263 ### Why are they special? 264 265 Files are special for several reasons. First and foremost, they have a binary 266 attached to them that can be quite heavy. The stack also enforces some rules on 267 them (e.g. a file can’t be added to a deleted folder) and has some specific code 268 for the tree nature of files and folders (e.g. a permission on a folder is 269 inherited on all the files and folders inside it, even if they are several 270 levels below). Thus, the workflow explained just before is not compatible with 271 the files. 272 273 As we need to introduce some code specific to the files, we have also wanted to 274 improve the sharing of files. First, we don’t want to force the recipients to 275 put the shared folder at exactly the same place as the owner. In fact, we think 276 that putting the shared folder in a folder called `Shared with me` is more 277 friendly. We also think that a file that has been shared in the past but is no 278 longer (the sharing has been revoked) can evolve on both the owner’s cozy and on 279 the recipients’ cozy in different ways, and in such a case, it’s more logical to 280 consider them as different files. These two reasons implies, on a technical 281 level, that the identifiers for files and folders are not the same on the owner 282 and the recipients of a sharing. The replicator will translate the identifiers 283 from one system to another during the replications. Of course, it will also 284 translate the `id` in the sharing rules, and the `dir_id` to preserve the 285 relationship between a file and its parent folder. The `path` attribute will be 286 seen as a cache, and recomputed when a cozy instance receives a folder document 287 from a sharing replication. 288 289 We will continue to have a replication as close to the CouchDB replication as 290 possible. It means we synchronize a state, and not looking for the history of 291 operations like [cozy-desktop](https://github.com/cozy-labs/cozy-desktop/) does. 292 It is less accurate and can lead more often to conflicts. The cozy instances are 293 expected to be online most of the time and have a short delay for replications: 294 we think that the conflicts will happen only on rares occasions. This make 295 acceptable to take this shortcut. And, in case of conflicts, we will preserve 296 the content of the files (no data loss), even if it means duplicating the files. 297 298 ### How a sharing involving files works? 299 300 When a sharing involves a rule on the `io.cozy.files` doctype, a folder is 301 created on the recipients cozy where the files will be put. It is created inside 302 the `Shared with me` folder by default, but can be moved somewhere else after 303 that. The folder won’t be synchronized its-self later, and if the folder is 304 trashed, the sharing is automatically revoked. As it is not a reversible action, 305 a confirmation is asked before doing that. 306 307 **Note:** we will forbid the sharing of the root of the virtual file system, of 308 the trash and trashed files/folders, and of course the `Shared with me` folder. 309 310 The step 3 described above, aka the replicator, will be more complicated for 311 folders and files. First change, it will work on two phases: 1. what can be 312 synchronized without transfering the binaries first, and 2. the synchronization 313 of files with a binary attached. Second change, the replicator will acquire the 314 Virtual File System lock on the cozy instance where it will write things to 315 ensure the consistency of what it writes. Third change, before inserting a 316 folder or file in the database, the replicator checks that its parent exists, 317 and if it’s not the case, it creates it. Last change, we will avoid CouchDB 318 conflicts for files and folder by using a special conflict resolution process. 319 320 ### Sequence diagram 321 322  323 324 ### Conflict resolution 325 326 In the case of `io.cozy.files` documents, we prevent CouchDB conflicts to happen 327 by implementing specific strategies. Here, we detail the conflicts situations 328 where a resolution is possible: 329 330 1. When two cozy instances have modified the same file concurrently 331 2. Same for a folder 332 3. When two files or folders are renamed concurrently to the same name inside 333 the same directory 334 4. When a file or folder is created or updated on cozy instance while the parent 335 directory is trashed concurrently on another cozy instance. 336 337 For 1. and 2., we will reconciliate the changes except for a file with two 338 versions having a distinct binary (we rely on `size` and `checksum` to detect 339 that). In such a case, we create a copy of the file with one version, while 340 keeping the other version in the original file (the higher revision wins). 341 342 For 3., we say that the owner instance wins: the file with the name in conflict 343 on the owner instance will keep its name, and the other file with the same name 344 will be renamed. This rule helps to minimize the number of exchanges between 345 the cozy instances, which is a factor of stability to avoid more conflicts. 346 347 For 4., we restore the trashed parent, or recreate it if it the trash was 348 emptied. 349 350 ### Conflict with no reconciliation 351 352 When a file is modified concurrently on two cozy instances, and at least one 353 change involve the content, we can't reconciliate the modifications. To know 354 which version of the file is the "winner" and will keep the same identifier, and 355 which version is the "loser" and will have a new identifier, we compare the 356 revisions and the higher wins. 357 358 This conflict is particulary tricky to resolve, with a lot of subcases. In 359 particular, we try to converge to the same revisions on all the instances for 360 the "winner" file (and for the "loser" too). 361 362 We have 3 sets of attributes for files: 363 364 - `size` and `md5sum` (they change when the content has changed) 365 - `name` and `dir_id` (they change when the file is moved or renamed) 366 - `created_at`, `updated_at`, `tags`, `referenced_by`, etc. 367 368 For the first two sets, the operation on the Virtual File System will needs to 369 reach the storage (Swift), not just CouchDB. For the third set, it's easy: we 370 can do the change at the same time as another change, because these attributes 371 are only used in CouchDB. But we can't do a change on the first two sets at the 372 same time: the Virtual File System can't update the content and move/rename a 373 file in the same operation. If we needs to do both, it will generate 2 revisions 374 in CouchDB for the file. 375 376 **Note:** you can see that using CouchDB-like replication protocol means that we 377 have some replications that can look useless, just some echo to a writing. In 378 fact, it is used to acknowledge the writing and is helpful for conflict 379 resolutions. It may be conter-intuitive, but removing them will harm the 380 stability of the system, even if they do nothing most of the time. 381 382 #### Example 1 383 384  385 386 Here, Alice uploads a file on her Cozy. It creates two revisions for this file 387 (it's what the Virtual File System does). Then, she shares the directory with 388 this file to her friend Bob. When Bob accepts the sharing, the file is sent to 389 his Cozy, with the same revision (2-2aa). 390 391 Later, Bob renames the file. It creates a new revision (3-3aa). The change is 392 replicated to Alice's Cozy. And we have a replication from Alice to Bob to 393 ensure that every thing is fine. 394 395 Even later, Alice and Bob both renames the file at the same time. It creates a 396 conflict. We have a first replication (from Alice to Bob), but nothing happens 397 on B because the local revision (4-4bb) is greater than the candidate revision 398 (4-4aa) and the content is the same. 399 400 Just after that, we have a revision on the opposite direction (from Bob to 401 Alice). The candidate revision wins (4-4bb), but for files, we don't use CouchDB 402 conflict, thus it's not possible to write a new revision at the same generation 403 (4). The only option is to create a new revision (5-5bb). This revision is then 404 sent to Bob: Bob's Cozy accepts the new revision even if it has no effect on the 405 file (it was already the good name), just to resolve the conflict. 406 407 #### Example 2 408 409  410 411 Like in the last example, Alice uploads a file and share a directory to Bob with 412 this file, Bob acccepts. But then, several actions are made on the file in a 413 short lapse of time and it generates a difficult conflict: 414 415 - Alice renames the file, and then uploads a new version with cozy-desktop 416 - Bob moves the file to a sub-directory. 417 418 So, when the replication comes, we have two versions of the file with different 419 name, parent directory, and content. The winner is the higher revision (4-4aa). 420 The resolution takes 4 steps: 421 422 1. A copy of the file is created from the revision 3-3bb, with the new 423 identifier id2 = XorID(id, 3-3bb). 424 2. The new content is written on Bob's Cozy: we can't use the revisions 3-3aa 425 (same generation as 3-3bb) and 4-4aa (it will mean the conflict is fixed, but 426 it's not the case, the filenames are still different), so a new revision is 427 used (4-4cc). 428 3. The file is moved and renamed on Bob's Cozy, with a next revision (5-5bb). 429 4. The two files are sent to Alice's Cozy: 5-5bb is accepted just to resolve the 430 conflict, and id2 is uploaded as a new file. 431 432 ### Special case: out and in again 433 434 Let's look at a special case. Alice shares a folder with Bob and Charlie. It 435 contains a directory, with a few files inside it. This directory has been 436 synchronized, and Bob decides to move it somewhere else on its cozy instance 437 that is not inside the shared folder, let's say at the root. The sharing 438 synchronization will move the directory to the trash for Alice and Charlie. Bob 439 can continue to work on the files in this directory. If Charlie restores the 440 directory from the trash, it will be put again in the sharing. And we can see 441 that we have an issue: on Bob instance, we will have two copies on the files, 442 at two different locations, but technically, they should have the same 443 identifiers. It is not possible. 444 445 To avoid that, we have to change the identifier, or more precisely, delete a 446 file and recreate it with a new identifier. It means losing historical versions 447 and some other things like sharing by links. It is an operation that takes a 448 lot of resources. So, we need to be careful in how we do that. And, like usual 449 for the sharing, we need to take care of the stability and convergence of the 450 replication algorithm. 451 452 With these constraints, the approache we have chosen is to put a copy of a file 453 that was moved out of the sharing in the trash when this operation is 454 replicated. For the member of the sharing that has made the operation, the file 455 will be the same (no need to change how the VFS work), and it is only later, 456 when this change is replicated to the other members that we will put a copy of 457 the file in the trash and delete the file (this is managed by the sharing 458 layer). Thus, the other members of the sharing will have a copy of the file, 459 but not the original file (sharing by links won't work on the copy for 460 example), and the old versions of the file will be lost. We think it is an 461 acceptable tradeoff between complexity, reliability, and matching the user 462 expectations. 463 464 Still, it has an important limitation. If Alice and Bob moves a file from the 465 shared directory to somewhere else at the same time, and later, one of them is 466 moving again the file inside the shared directory, we will be in a bad 467 situation, where the replication algorithm can't synchronize the file. For the 468 moment, we prefer to advance with this limitation, but we will have to take 469 care of it later. 470 471 ## Schema 472 473 ### Description of a sharing 474 475 - An identifier (the same for all members of the sharing) 476 - A list of `members`. The first one is the owner. For each member, we have: 477 - `status`, a status that can be: 478 - `owner` for the member that has created the sharing 479 - `mail-not-sent` for a member that has been added, but its 480 invitation has not yet been sent (often, this status is used only 481 for a few seconds) 482 - `pending` for a member with an invitation sent, but who has not 483 clicked on the link 484 - `seen` for a member that has clicked on the invitation link, but 485 has not setup the Cozy to Cozy replication for the sharing 486 - `ready` for a member where the Cozy to Cozy replication has been 487 set up 488 - `revoked` for a member who is on longer in the sharing 489 - `name`, a contact name 490 - `public_name`, a public name 491 - `email`, the email address 492 - `instance`, the URL of the Cozy 493 - `read_only`, a flag to tell if the contact is restricted to read-only mode 494 - `only_in_groups`, a flag that will be false if the member has been added 495 as a single contact 496 - `groups`, a list of indexes of the groups 497 - A list of `groups`, with for each one: 498 - `id`, the identifier of the io.cozy.contacts.groups 499 - `name`, the name of the group 500 - `addedBy`, the index of the member that has added the group 501 - `read_only`, a flag to tell if the group is restricted to read-only mode 502 - `revoked`, a flag set to true when the group is revoked from the sharing 503 - Some `credentials` to authorize the transfer of data between the owner and 504 the recipients 505 - A `description` (one sentence that will help people understand what is 506 shared and why) 507 - A flag `active` that says if the sharing is currently active for at least 508 one member 509 - A flag `owner`, true for the document on the cozy of the sharer, and false 510 on the other cozy instance 511 - A flag `open_sharing`: 512 - `true` if any member of the sharing except the read-only ones can add a 513 new recipient 514 - `false` if only the owner can add a new recipient 515 - Some technical data (`created_at`, `updated_at`, `app_slug`, `preview_path`, 516 `triggers`, `credentials`) 517 - A flag `initial_sync` present only when the initial replication is still 518 running 519 - A number of files to synchronize for the initial sync, 520 `initial_number_of_files_to_sync` (if there are no files to sync or the 521 initial replication has finished, the field won't be here) 522 - A `shortcut_id` with the identifier of the shortcut file (when the 523 recipient doesn't want to synchronize the documents on their Cozy instance) 524 - A list of sharing `rules`, each rule being composed of: 525 - a `title`, that will be displayed to the recipients before they accept 526 the sharing 527 - a `doctype` (and a `mime` if the doctype is `io.cozy.files`) 528 - a `selector` (by default, it’s the `id`) and `values` (one identifier, a 529 list of identifiers, files and folders inside a folder, files that are 530 referenced by the same document, documents bound to a previous sharing 531 rule) 532 - `local`: by default `false`, but it can be `true` for documents that are 533 useful for the preview page but doesn’t need to be send to the 534 recipients (e.g. a setting document of the application) 535 - `add`: a behavior when a new document matches this rule (the document is 536 created, or it was a document that didn’t match the rule and is modified 537 and the new version matches the rule): 538 - `none`: the updates are never propagated (the default) 539 - `push`: the updates made on the owner are sent to the recipients 540 - `sync`: the updates on any member (except the read-only) are 541 propagated to the other members 542 - `update`: a behavior when a document matched by this rule is modified. 543 Can be: 544 - `none`: the updates are never propagated (the default) 545 - `push`: the updates made on the owner are sent to the recipients 546 - `sync`: the updates on any member (except the read-only) are 547 propagated to the other members 548 - `remove`: a behavior when a document no longer matches this rule (the 549 document is deleted, or it was a document that matched the rule, and is 550 modified and the new version doesn’t match the rule): 551 - `none`: the updates are never propagated (the default) 552 - `push`: the updates made on the owner are sent to the recipients 553 - `sync`: the updates on any member (except the read-only) are 554 propagated to the other members 555 - `revoke`: the sharing is revoked. 556 557 #### Example: I want to share a folder in read/write mode 558 559 - rule 1 560 - title: `folder` 561 - doctype: `io.cozy.files` 562 - values: `"ca527016-0d83-11e8-a580-3b965c80c7f7"` 563 - add: `sync` 564 - update: `sync` 565 - remove: `sync` 566 567 #### Example: I want to share a playlist where I’m the only one that can add and remove items 568 569 - rule 1 570 - title: `playlist` 571 - doctype: `io.cozy.music.playlists` 572 - values: `"99445b14-0d84-11e8-ae72-4b96fcbf0552"` 573 - update: `none` 574 - remove: `revoke` 575 - rule 2 576 - title: `items` 577 - doctype: `io.cozy.files` 578 - selector: `referenced_by` 579 - values: `"io.cozy.files/ca527016-0d83-11e8-a580-3b965c80c7f7"` 580 - add: `push` 581 - update: `none` 582 - remove: `push` 583 584 ### `io.cozy.shared` 585 586 This doctype is an internal one for the stack. It is used to track what 587 documents are shared, and to replicate changes from one Cozy to the others. 588 589 - `_id`: its identifier is the doctype and id of the referenced objet, 590 separated by a `/` (e.g. 591 `io.cozy.contacts/c1f5dae4-0d87-11e8-b91b-1f41c005768b`) 592 - `_rev`: the CouchDB default revision for this document (not very meaningful, 593 it’s here to avoid concurrency issues) 594 - `revisions`: a tree with the last known `_rev`s of the referenced object 595 - `infos`, a map of sharing ids → `{rule, removed, binary}` 596 - `rule` says which rule from the sharing must be applied for this 597 document 598 - `removed` will be true for a deleted document, a trashed file, or if the 599 document does no longer match the sharing rule 600 - `binary` is a boolean flag that is true only for files (and not even 601 folders) with `removed: false` 602 - `dissociated` is a boolean flag that can be true only for files and folders 603 when they have been removed from the sharing but can be put again (only on 604 the Cozy instance of the owner)