dumparkltd / advocacy-tracker-client

https://github.com/dumparkltd/advocacy-tracker-client/projects/1
Other
0 stars 0 forks source link

Explore possibility to make app available off-line #9

Open tmfrnz opened 2 years ago

tmfrnz commented 2 years ago

Would require a synchronisation mechanism when app comes back online, specifically also including a mechanism to resolve conflicts (currently the server application just rejects updates when a record has been updated in the meantime)

tmfrnz commented 2 years ago

Issues (and (preliminary) ideas to address them)

While there are some solutions available (see subsequent comment) that we may also consider, here is a list of issues and ideas to address them:

Cache app code

The application code is already being cached and available offline, using the offline-plugin for webpack. We could also consider to change the response strategy to "cache-first" (webpack config, see also offline-plugin options)

Cache app data

In addition, the client needs to cache the app data (retrieved from server) for future offline use and make sure it remains available when re-opening or re-loading the app while offline.

To make sure to always have the latest data available, the local cache should be updated with every remote server response (when online).

Instead of only loading data as needed for each and every component (as the client currently does, e.g. configured here), it might be good to always load all tables when loading the app.

Also consider

Sign in, log out

Authentication obviously won't work when working offline, so we will need to consider how to handle these.

A simple way could be

Check status

The app needs to periodically check the online-status in the background and inform user when status changes (also when back online).

Offline-mode (while online)

Potentially, we may want to allow users to optionally enable "offline-mode" even when online

Local API

When in "offline-mode" a local API should respond to API calls just like the server would - this way the majority of the app can abstract from the online-status.

Specifically

The current API request is handled here https://github.com/dumparkltd/advocacy-tracker-client/blob/master/app/utils/api-request.js

As the client already validates all data on "save", it might not be required to have those validation rules also checked again by the local API. Regardless, the validation rules should be reviewed in order to minimise issues when synchronising with the server (see below)

Synchronising (when coming back online)

When leaving offline-mode and coming back online, the app should check if there are any local changes that are more recent than the last load from the remote server.

To easily identify any relevant records it might be good to simply store this as a "changed_locally" flag in a separate column in the cached data.

without local changes

If there are no changes, the app can just flush the local cache and re-load all data, optionally prompting the user to confirm.

with local changes

When there are local changes, the user should be prompted to start writing those changes to the server. Here the easiest strategy would be to make those changes one-by-one, possibly grouped into multiple batches:

  1. create all new records on the server (one-by-one), which will return the new remote id - it is important to remember the local id in the meantime, possibly by storing it in an additional column in the locally cached tables
  2. create all new relationships on the server (one-by-one), making sure to use the new remote ids instead of the local ones
  3. delete all locally deleted relationships on the server (one-by-one), which should fail if any of these relationships has been updated on the server in the meantime (only applicable to some "editable" relationships, most relationships do not have column other than the respective foreign ids and thus only allow create and delete)
  4. update all locally edited records on the server (one-by-one), which will fail if the same record has been updated in the meantime (server compares "updated_at" timestamps); in this case the user should ideally be presented with both versions and have the chance to locally reconcile them, i.e. by manually bringing in the local changes to the current remote version but this may not be as important at the start [TODO: consider case when remote record is deleted in the meantime]
  5. delete all locally deleted records on the server (one-by-one), which should fail if any of these records has been updated on the server in the meantime

While this could also all happen quietly in the background, I would suggest to prompt the user in every step:

While the data is being updated on the server (one-by-one), the listed records could be visually marked according to the server response, indicating success or any errors (that could be due to failed validation on the server (we want to minimise this by reflecting those rules also on the client, see above), or outdated data (not applicable to steps 1 and 2)), and allowing the user to either update the data locally where applicable (e.g. validation issues or outdated data) and sync again or dismiss and delete the local change.

Once all local changes have been written to the server, the app can flush the local cache and re-load all data, ideally prompting the user to confirm.

tmfrnz commented 2 years ago

Other solutions and further reading