You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# PowerSync + Supabase Flutter Local-Only to Online Mode Demo: Todo List App
1
+
# PowerSync + Supabase Flutter Todo List App: Local-Only to Sync Mode Demo
2
2
3
-
This demo app is an extension of the [Supabase Todo List App](../supabase-todolist/README.md)that demonstrates how to use the PowerSync SDK for Flutter in a local-only way without sync capabilities. It allows the user to use the app offline without having to sign in. After signing in data that was kept locally is synced up. For a step-by-step guide, see [here](https://docs.powersync.com/integration-guides/supabase).
3
+
This demo app is an extension of the [Supabase Todo List App](../supabase-todolist/README.md)and demonstrates using the PowerSync Flutter client SDK to persist data locally without syncing, for users to use the app without having to register or sign in. It then demonstrates syncing this data to Supabase once the user registers at a later stage.
4
4
5
-
# Running the app with local-only
5
+
The recommended flow through this demo is:
6
+
1. Run the app in local-only mode and create data. Notice how data persists even when closing and reopening the app.
7
+
2. Enable user registration and sign in to the app.
8
+
3. Notice how previously created data now seamlessly syncs with Supabase.
9
+
10
+
For an overview of the mechanics behind this, see [the explanation further below](#how-this-works).
11
+
12
+
# Run the app in local-only mode
6
13
7
-
Note that if Supabase and PowerSync credentials have not been been configured, a user will not be able to login or sign up. There is a hardcoded check in `main.dart` for this.
8
14
Ensure you have [melos](https://melos.invertase.dev/~melos-latest/getting-started) installed.
9
15
10
16
1.`cd demos/local-only-todolist`
11
17
2.`melos prepare`
12
18
3.`flutter run`
13
19
14
-
# Setting up sync functionality
20
+
Create some data and notice how the data persists after a refresh or reopening the app.
21
+
22
+
It is expected that users cannot register or sign in at this stage. This is because Supabase and PowerSync credentials have not been been configured yet -- there is a hardcoded check in `main.dart` for this. We'll get to this next.
23
+
24
+
# Enable user registration and sign in
15
25
16
-
Insert your Supabase and PowerSync project credentials into `lib/app_config.dart` (See instructions below).
17
-
A user should now be able to login or sign up, which enables the sync functionality.
26
+
Create Supabase and PowerSync projects, and add their credentials to `lib/app_config.dart` to enable user registration and sign in.
18
27
19
-
# Set up Supabase Project
28
+
## Set up your Supabase project
29
+
30
+
Detailed instructions for integrating PowerSync with Supabase can be found in [the integration guide](https://docs.powersync.com/integration-guides/supabase). Below are the main steps required to get this demo running.
20
31
21
32
Create a new Supabase project, and paste an run the contents of [database.sql](./database.sql) in the Supabase SQL editor.
22
33
@@ -27,7 +38,7 @@ It does the following:
27
38
3. Enable row level security, allowing users to only view and edit their own data.
28
39
4. Create a trigger to populate some sample data when an user registers.
29
40
30
-
#Set up PowerSync Instance
41
+
## Configure your PowerSync Instance
31
42
32
43
Create a new PowerSync instance, connecting to the database of the Supabase project.
33
44
@@ -43,35 +54,55 @@ bucket_definitions:
43
54
- select * from todos where list_id = bucket.list_id
44
55
```
45
56
46
-
# Configure the app
57
+
## Configure the app
58
+
59
+
Insert the credentials of your Supabase and PowerSync projects into `lib/app_config.dart`.
60
+
61
+
## Sign in to the app
62
+
63
+
Reload the app and sign up or sign in. Once successfully signed in, existing and new data should seamlessly sync with Supabase.
64
+
65
+
66
+
# How this works
67
+
68
+
This app uses [local-only](https://pub.dev/documentation/powersync/latest/powersync/Table/Table.localOnly.html) tables to persist data until the user has registered or signed in. Local-only tables do not log updates in an upload queue, avoiding any overhead or growth in database size.
69
+
70
+
Once the user registers, the data is moved over to synced tables, at which point the data would be placed in the upload queue and will start syncing.
71
+
72
+
## Naive implementation
47
73
48
-
Insert the credentials of your new Supabase and PowerSync projects into `lib/app_config.dart`
74
+
A barebones way to achieve the above is to store and query data from local-only tables before registration, copy this data to each corresponding synced table after registration and then store and query from the synced tables. This would look as follows:
49
75
50
-
# Explanation
76
+

77
+
78
+
The downside to this approach is that app queries would need to continuously differentiate between the two tables based on whether the user signed in or not.
79
+
80
+
## Recommended implementation
81
+
82
+
To keep app queries consistent between the two states, we utilize the [viewName](https://pub.dev/documentation/powersync/latest/powersync/Table/viewName.html) property, which allows overriding the default name of the view that is used in queries.
83
+
84
+
This looks as follows in the local-only state:
85
+
86
+

87
+
88
+
The local-only tables (`local_lists` and `local_todos`) have their view names overriden to `listsAlias` and `todosAlias`, and these names are used in queries (e.g. `PowerSync.getAll("SELECT * FROM listsAlias");`). The `lists` and `todos` tables are not used in this state, but will become relevant in the next step.
89
+
90
+
When the user registers / signs in:
91
+
92
+

93
+
94
+
The _synced_ tables (`lists` and `todos`) now have their view names overriden to `listsAlias` and `todosAlias`. Note that `updateSchema` must be run to update the view name. See the [schema](./lib/models/schema.dart) for details about this. The app query `PowerSync.getAll("SELECT * FROM listsAlias")` now reads data from the `lists` table.
95
+
96
+
Finally, copy data from the local-only tables to the synced tables, and delete data from the local-only tables to reduce database size:
97
+
98
+

51
99
52
-
The demo implements local-only and synced modes by using two sets of schema definitions, which can be viewed [here](./lib/models/schema.dart).
53
100
54
-
The first set doesn't record changes in an upload queue, this is achieved by using the localOnly table definition.
55
-
When the user registers and sync must start, copy the data in the first schema over to a second set of regular / synced schema
56
101
57
102
At this point, being signed in no longer determines which schema should be used, as the user's session expiring and explicitly signing out trigger different behaviors. If the session expires, the user can continue interacting with their data. However, if the user explicitly logs out, all data is cleared, effectively resetting the app. To manage this, an additional local storage mechanism is used to track which schema is currently in use, as seen [here](./lib/models/sync_mode.dart). Note that any other local storage solution would work as long as it's not using the PowerSync database (chicken and egg problem).
58
103
59
-
## Flow chart
60
-
61
-
```mermaid
62
-
graph TD
63
-
K[Start] --> A[App is empty and local-only]
64
-
A --> B[User creates todos that are stored local-only]
65
-
A --> C[User can login/register]
66
-
B -->
67
-
C --> D[Local-only data gets synced to PowerSync service]
68
-
D --> E[User creates todos that will get synced]
69
-
D --> F
70
-
E --> F[User can logout explicitly]
71
-
F --> A
72
-
```
73
104
74
-
## Limitations
105
+
# Limitations
75
106
76
-
`updateSchema`cannot be called inside a transaction, and it's recommended to perform the schema update when the database isn't connected.
77
-
Additionally, the current implementation of the PowerSync SDK's `watch` method may not correctly track tables that are altered by `updateSchema`. Note that `refreshSchema` can be executed after updating the schema to resolve this (the demo uses it in `switchToSyncedSchema` which can be viewed [here](./lib/models/schema.dart)).
107
+
- `updateSchema`cannot be called inside a transaction, and it's recommended to perform the schema update when the database isn't connected.
108
+
- Additionally, the current implementation of the PowerSync SDK's `watch` method may not correctly track tables that are altered by `updateSchema`. Note that `refreshSchema` can be executed after updating the schema to resolve this (the demo uses it in `switchToSyncedSchema` which can be viewed [here](./lib/models/schema.dart)).
0 commit comments