github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/docs/move-design.md (about) 1 [Table of contents](README.md#table-of-contents) 2 3 # Move design 4 5 > "You will stay because you can leave" - Cozy. 6 7 We have made this important promise to our users, and moving a Cozy to a new 8 hoster/address is a big part of it. That's why we have tried hard to make it 9 smooth and robust. It means that we had to manage some complex special cases. 10 This document is here to keep a trace of them. 11 12 But, first, let's define what moving a Cozy means. When you have an instance, 13 the "source", and another instance, the "target", the user can move their usage 14 from the source to the target. The data is exported from the source instance, 15 and imported on the target instance. But there is more than that. For example, 16 the Cozy to Cozy sharings ([documentation](./sharing-design.md)) will be 17 updated to work the target instance instead of the source instance. 18 19 20 ## Workflows 21 22 Technically, a new component called [Cozy-Move](https://github.com/cozy/cozy-move) 23 was created. It is a web application in Elixir/Phoenix that can be seen as a 24 wizard to help users select from which instance and to which instance they want 25 to move. It is possible to send a mail with a link to cozy-move, and put this 26 link in a FAQ, and users can start the process from this link. But, if a user 27 wants to initiate a move by them-self, they will start from the settings of 28 their Cozy. The two workflows are available. 29 30 ### Starting from settings 31 32 ![Starting from settings](./diagrams/from-settings.png) 33 34 ### Starting from cozy-move 35 36 ![Starting from cozy-move](./diagrams/from-cozy-move.png) 37 38 ### Notes 39 40 For security, we need an interaction of the user with both instances (even if 41 the user is already logged). There is a confirmation mail sent by the source 42 Cozy, that counts as a interaction. For the target Cozy, a click on a page 43 served by the stack could have been enough, but asking the password was easier 44 to explain to the user and improve the sense of security as perceived by the 45 user, so that was what we did. And we had to take care of that to allow or 46 forbid swapping instances on Cozy-Move. 47 48 The token exchanges are inspired by OAuth 2.0, but don't follow OAuth 2.0 as it 49 would have made the user experience really awkwards with lots of redirections 50 and meaningless screens. The confirmation mail is really important, as it is 51 a safeguard if the worflows are not as robust as we think they are. 52 53 54 ## Source instance 55 56 Exporting the data from a Cozy was a feature already implemented in the stack. 57 The user can ask an export of their Cozy: the stack will send a mail with a 58 link, and after following the link, the user can download the data as a zip. If 59 the VFS ([Virtual File System](./files.md#virtual-file-system)) takes a lot of 60 space, the zip will be split in several parts. 61 62 When an export if part of a move, the instance is blocked to avoid any change 63 that could increase the risk of inconsistencies during the move. 64 65 And, if the move is successful, the OAuth clients are revoked to encourage the 66 user to reconnect them on the target. Also, the source instance will be 67 destroyed 30 days later. It gives time to the user to check that every thing is 68 OK on their new instance, and can be used to alert other users that want to see 69 a page shared by link of the new address of the sharing. 70 71 ### Zip vs Tar 72 73 The export produces a zip file (or several files if it is too large). But the 74 stack first makes a tar file while preparing the export. At first, it looks 75 strange, but we though that a zip will be more friendly for users, and a tar is 76 more adapted to our constraints. A tar can be read sequentially while a zip 77 needs random access, and it was easier to stream a tar from Swift and converts 78 it to zip, than trying to add entries to a zip file (and we didn't want to copy 79 the whole files from the VFS in the zip in Swift as it takes too much space). 80 81 82 ## Target instance 83 84 Importing a zip can also be done before moving: the user can go in the settings 85 of their Cozy, gives the URL of the zip, and let the Cozy imports it. The Cozy 86 is reset before the import: the data is erased! 87 88 We would like to offer a way to merge the existing data and the data to import, 89 but it looks really complex and we think that it is more useful to use our time 90 on other features. 91 92 At the end of the import, a mail is sent to the user to tell them that they can 93 use again their Cozy (the instance is blocked during the reset+import). 94 95 96 ## Special doctypes 97 98 ### Apps 99 100 The home, settings, and store applications are always installed on the target Cozy. 101 And we also try to install all the webapps and konnectors from the source, but 102 it can fail as they might not be available (e.g. the 2 Cozys don't have the 103 same apps registry). In that case, the user will be alerted in the mail sent at the 104 end of the import. 105 106 For the permissions, we recreate them from the manifest and don't try to import them 107 from the source instance. 108 109 ### Email address 110 111 The email address on the target instance is kept. We don't import the email 112 address the user had on their source instance. The stack also keep other 113 settings that are tied to the cloudery (UUID, ToS, context). 114 115 We also update the myself document with the kept email address. 116 117 ### Files 118 119 The directories, files, and versions are imported. The thumbnails are not 120 exported/imported, but rebuilt on the target instance. 121 122 If the quota of the target is too small for the files from the source, we alert 123 the user before the move. 124 125 ### Konnectors 126 127 See the apps section. For konnectors that have a on_delete_accounts hook, we have 128 to use some tricks: 129 130 - we delete the accounts on the target instance for the reset while the 131 instance is blocked, but the konnectors can still make requests to the stack 132 for those executions (allowed via a flag in redis) 133 - the accounts from the source instance are not imported on the target, as they 134 will be useless soon (when they will be deleted by the source). 135 136 ### Sessions 137 138 They are not imported. 139 140 ### Sharings 141 142 For the shared by links, we import the permission document. But the link given 143 to other users will still go on the old instance. While this instance is not 144 deleted, it will show a page that gives the new link. 145 146 For the Cozy to Cozy sharings, the stack has a mechanism for updating them so 147 that the other instances will now synchronize with the target. It is a bit 148 complicated as we have to make it work if several members of a sharing has 149 moving at the same time, and as the JWT tokens are tied to an instance and have 150 to be renewed (access token & refresh token). 151 152 ### Triggers 153 154 We import the triggers for the sharings and konnectors. For the apps 155 (services), they are recreated when installed. The trigger for the 156 thumbnails is also recreated when the instance is reset (not imported). 157 158 Note: the triggers are imported at the end to avoid creating many jobs when 159 importing the shared files. 160 161 ### Vault 162 163 The bitwarden vault is encrypted with a key not available on the servers (on 164 purpose). It makes difficult to move it automatically, but the stack can detect 165 if the vault has been used, and in that case, show instructions to export and 166 import the passwords.