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  ![Alice has shared a todo-list with Bob and Charlie, and Bob has added an item
   152  to this todo-list](diagrams/sharing.png)
   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  ![Revisions sync between Alice, Bob and Charlie](diagrams/sharing-revisions.png)
   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  ![Replicator and upload](diagrams/replicator.png)
   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  ![File is renamed on both instance](diagrams/files-conflict-1.png)
   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  ![A difficult conflict](diagrams/files-conflict-2.png)
   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)