Skip to content

Commit 2debbe1

Browse files
committed
New tutorial for Dexie Cloud
1 parent f5e877e commit 2debbe1

1 file changed

Lines changed: 340 additions & 0 deletions

File tree

docs/Tutorial/Dexie-Cloud.md

Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
---
2+
layout: docs-dexie-cloud
3+
title: 'Get started with Dexie Cloud'
4+
---
5+
6+
## 1. Bootstrapping
7+
8+
No matter if you create a brand new app or adjust an existing one, this tutorial will guide you through the steps.
9+
10+
You can use whatever framework you prefer but in this tutorial we'll be showing some sample components in React, so if you start on an empty paper, I'd recommend using vite to bootstrap a react app:
11+
12+
```bash
13+
npm create vite@latest my-app -- --template react-ts
14+
```
15+
16+
Make sure to have dexie-related dependencies installed:
17+
18+
```bash
19+
npm install dexie
20+
npm install dexie-cloud-addon
21+
npm install dexie-react-hooks # If using react
22+
```
23+
24+
## 2. Declare a `db`
25+
26+
Unless you already use Dexie (in which case you could just adjust it), create a new module `db.ts` where you declare the database.
27+
28+
_If migrating from vanilla Dexie.js to Dexie Cloud, make sure to remove any auto-incrementing keys (such as `++id` - replace with `@id` or just `id`) as primary keys has to be globally unique strings in Dexie Cloud._
29+
30+
```ts
31+
// db.ts
32+
import { Dexie } from 'dexie';
33+
import dexieCloud from 'dexie-cloud-addon';
34+
35+
export const db = new Dexie('mydb', { addons: [dexieCloud] });
36+
37+
db.version(1).stores({
38+
items: 'itemId',
39+
animals: `
40+
@animalId,
41+
name,
42+
age,
43+
[name+age]`
44+
});
45+
```
46+
47+
In this example we use the property `itemId` as primary key for `items` and `animalId` for `animals`.
48+
49+
Notice the `@` in `@animalId`. This makes it auto-generated and is totally optional but can be handy since it makes it easier to add new objects to the table.
50+
51+
Note that `animals` also declares some secondary indices `name`, `age` and a [compound](/docs/Compound-Index) index of the combination of these. These indices are just to examplify. For this tutorial, we only need the 'name' index. _A rule of thumb here is to only declare secondary index if needed in a where- or orderBy expression. And don't worry - you can add or remove indices later_
52+
53+
## 3. Make it Typing-Friendly
54+
55+
```ts
56+
// Item.ts
57+
export interface Item {
58+
itemId: string;
59+
name: string;
60+
description: string;
61+
}
62+
```
63+
64+
```ts
65+
// Animal.ts
66+
export interface Animal {
67+
animalId: string;
68+
name: string;
69+
age: number;
70+
}
71+
```
72+
73+
Then adjust the `db.ts` module we've already created so that it looks something like this:
74+
75+
```ts
76+
// db.ts
77+
import dexieCloud, { type DexieCloudTable } from 'dexie-cloud-addon';
78+
import type { Item } from './Item.ts';
79+
import type { Animal } from './Animal.ts';
80+
81+
export const db = new Dexie('mydb', { addons: [dexieCloud] }) as Dexie & {
82+
items: DexieCloudTable<Item, 'itemId'>;
83+
animals: DexieCloudTable<Animal, 'animalId'>;
84+
};
85+
86+
db.version(1).stores({
87+
items: 'itemId',
88+
animals: `
89+
@animalId,
90+
name,
91+
age,
92+
[name+age]`
93+
});
94+
```
95+
96+
_We're actually just casting our Dexie to force the typings to reflect the `items` and `animals` tables that we are declaring in db.version(1).stores(...)._
97+
98+
\_There's also the option to declare the entities as classes instead of interfaces. See [TodoList.ts](https://github.com/dexie/Dexie.js/blob/928684175024b9a00269de1a65845a1f43ec8d74/samples/dexie-cloud-todo-app/src/db/TodoList.ts), [TodoDB.ts](https://github.com/dexie/Dexie.js/blob/3fe0876df83485e6552ee823a84aabac37cfa606/samples/dexie-cloud-todo-app/src/db/TodoDB.ts) and [db.ts](https://github.com/dexie/Dexie.js/blob/d58ddee379bec306a8ba4689d20f940c700449a4/samples/dexie-cloud-todo-app/src/db/db.ts) in the dexie-cloud-todo-list example. If you find that way more appealing, that's also ok.
99+
100+
## 4. Start Playing with it
101+
102+
Create some components that renders and manipulates the database. In this example, we use React + Typescript that demonstrate basic CRUD with a Dexie Cloud `animals` table.
103+
104+
```tsx
105+
// components/App.tsx
106+
import React from 'react';
107+
import CreateAnimal from './CreateAnimal';
108+
import AnimalList from './AnimalList';
109+
110+
export default function App() {
111+
return (
112+
<>
113+
<style>
114+
div.animal { display: 'flex', align-items: 'center', gap: 8 }
115+
div.create-form { display: 'flex', gap: 8, margin-bottom: 12 }
116+
</style>
117+
<div>
118+
<h1>Animals</h1>
119+
<CreateAnimal />
120+
<AnimalList />
121+
</div>
122+
</>
123+
);
124+
}
125+
```
126+
127+
_App: top-level component that renders `CreateAnimal` and `AnimalList`._
128+
129+
---
130+
131+
```tsx
132+
// components/AnimalList.tsx
133+
import React from 'react';
134+
import { useLiveQuery } from 'dexie-react-hooks';
135+
import { db } from '../db';
136+
import AnimalView from './AnimalView';
137+
import type { Animal } from '../Animal';
138+
139+
export default function AnimalList() {
140+
const animals = useLiveQuery(() => db.animals.orderBy('name').toArray(), []);
141+
142+
if (!animals) return <div>Loading…</div>;
143+
144+
return (
145+
<ul>
146+
{animals.map((a: Animal) => (
147+
<li key={a.animalId}>
148+
<AnimalView animal={a} />
149+
</li>
150+
))}
151+
</ul>
152+
);
153+
}
154+
```
155+
156+
_AnimalList: lists animals using `useLiveQuery` (live updates) and renders `AnimalView` for each._
157+
158+
---
159+
160+
```tsx
161+
// components/AnimalView.tsx
162+
import React from 'react';
163+
import { db } from '../db';
164+
import type { Animal } from '../Animal';
165+
166+
export default function AnimalView({ animal }: { animal: Animal }) {
167+
const onDelete = async () => {
168+
await db.animals.delete(animal.animalId);
169+
};
170+
171+
return (
172+
<div className="animal">
173+
<div>
174+
<strong>{animal.name}</strong> — {animal.age} yrs
175+
</div>
176+
<button aria-label="Delete" onClick={onDelete} title="Delete">
177+
🗑️
178+
</button>
179+
</div>
180+
);
181+
}
182+
```
183+
184+
_AnimalView: shows `name` and `age` and a delete button that removes the item from the table._
185+
186+
---
187+
188+
```tsx
189+
// components/CreateAnimal.tsx
190+
import React, { useState } from 'react';
191+
import { db } from '../db';
192+
193+
export default function CreateAnimal() {
194+
const [name, setName] = useState('');
195+
const [age, setAge] = useState<number | ''>('');
196+
197+
const onSubmit = async (e: React.FormEvent) => {
198+
e.preventDefault();
199+
if (!name || age === '') return;
200+
await db.animals.add({ name, age: Number(age) });
201+
setName('');
202+
setAge('');
203+
};
204+
205+
return (
206+
<form onSubmit={onSubmit} className="create-form">
207+
<input
208+
value={name}
209+
onChange={(e) => setName(e.target.value)}
210+
placeholder="Name"
211+
/>
212+
<input
213+
type="number"
214+
value={age}
215+
onChange={(e) => setAge(e.target.value ? Number(e.target.value) : '')}
216+
placeholder="Age"
217+
/>
218+
<button type="submit">Add</button>
219+
</form>
220+
);
221+
}
222+
```
223+
224+
_CreateAnimal: small form that adds a new animal to `db.animals` (the table uses an auto-generated `@animalId`)._
225+
226+
---
227+
228+
Start the app and browse to it. Add and delete animals - see the app work with a local database only.
229+
230+
## 5. Make it Sync
231+
232+
Still, we haven't connected Dexie Cloud in the picture. Everything is happening locally so far. Yes, we've prepared the code but we haven't yet connected it to a cloud database.
233+
234+
1. Create a database in the cloud
235+
236+
```bash
237+
npx dexie-cloud create
238+
```
239+
240+
This will produde two local files: `dexie-cloud.json` and `dexie-cloud.key`. Make sure
241+
to .gitignore them:
242+
243+
```bash
244+
echo "dexie-cloud.json" >> .gitignore
245+
echo "dexie-cloud.key" >> .gitignore
246+
```
247+
248+
2. White-list application URL (such as http://localhost:3000)
249+
250+
```bash
251+
npx dexie-cloud whitelist http://localhost:3000 # assuming port 3000
252+
253+
# ...Dont forget (at a later stage) to also white-list public URLs:
254+
npx dexie-cloud whitelist https://mygreatapp02240s.azurewebsites.net
255+
```
256+
257+
3. Pick the `dbUrl` from your local `dexie-cloud.json` file and configure the database in `db.ts`
258+
259+
```ts
260+
// db.ts
261+
...
262+
db.cloud.configure({
263+
databaseUrl: "<dbUrl>",
264+
})
265+
```
266+
267+
4. Add a Login button to your App.tsx:
268+
269+
```tsx
270+
<button onClick={() => db.cloud.login()}>Login</button>
271+
```
272+
273+
5. Now, launch the app and navigate a browser to it
274+
275+
## 6. Learn about Access Control and Sharing (optional)
276+
277+
By default, all data being created will remain private to the end user, even though
278+
kept in sync with the cloud. Learn more how you can create realms, roles, members and
279+
permissions to invite a group of users to a commonly shared realm of data.
280+
281+
See [Access Control in Dexie Cloud](/cloud/docs/access-control)
282+
283+
## 7. Use Dexie Cloud Manager (optional)
284+
285+
Login to [Dexie Cloud Manager](https://manager.dexie.cloud/) to manage:
286+
287+
- end-users seats
288+
- end-user evaluation policy
289+
- SMTP settings
290+
- Free / paid subscription
291+
292+
## 8. Use `dexie-cloud` CLI
293+
294+
The CLI can be used to switch between databases, export, import, authorize colleguaes. See all commands in the [CLI docs](/cloud/docs/cli).
295+
296+
## 8. Customize Authentication (optional)
297+
298+
Choose between:
299+
300+
1. [Keep the default authentication but customize the GUI](/cloud/docs/authentication#customizing-login-gui)
301+
2. [Replace authentication in its whole with a custom solution](</cloud/docs/db.cloud.configure()#example-integrate-custom-authentication>)
302+
303+
## 9. Customize Email Templates
304+
305+
Email templates for outgoing emails can be [customized](/cloud/docs/custom-emails) using the [npx dexie-cloud templates](/cloud/docs/cli#templates-pull) command.
306+
307+
---
308+
309+
## 10. FAQ
310+
311+
### What happens when clicking login button?
312+
313+
The default authentication dialog (which is [customizable](/cloud/docs/authentication#customizing-login-gui)) will ask for an email address for one-time password (OTP) authentication and prompt for the OTP. If this was the first time of login, your user will be registered in the database - otherwise it acts as a normal login. Once logged in / registered - the local database will be in sync with your account on your dexie-cloud database.
314+
315+
1. You get prompted for email
316+
2. You get prompted for OTP
317+
3. You enter OTP
318+
4. You get logged in
319+
5. All local data is uploaded to cloud and cloud data is downloaded
320+
6. Now the local and remote databases are connected in real time.
321+
322+
The login flow typically happens once per end user and device. It's a part of the setup process for your application. Users can logout but if not, their device will be persistently logged in for as long as the local database lives.
323+
324+
### Can I force a login + initial sync before any data is accessed?
325+
326+
Yes, a [requireAuth](</cloud/docs/db.cloud.configure()#requireauth>) property can be passed to db.cloud.configure(). This will block an query until a user is logged in and has completed an initial sync flow. It's also possible to force a login as a specified email or userId and even to provide an OTP token this way (for example read from the query if the a magic link was sent).
327+
328+
### Is it possible to Logout?
329+
330+
Yes, but local first apps are normally intended to have long or even eternal login sessions. A logout from a local first app is similar to erasing the local database.
331+
332+
A logout button can be added that calls `db.cloud.logout()` when clicked.
333+
334+
### What is `dexie-cloud.key` good for?
335+
336+
This file is needed when you use the CLI (`npx dexie-cloud`) to whitelist, export, import etc. It's not needed for web applications as it is authorized using the `npx dexie-cloud whitelist` command instead. The clientId and clientSecret is also needed when using the the [REST API](/cloud/docs/rest-api).
337+
338+
### Why should `dexie-cloud.json` and `dexie-cloud.key` be .gitignored?
339+
340+
Keys shall never be committed to git (`dexie-cloud.key`). `dexie-cloud.json` does not contain any sensitive data but is still not tied to your code base - some other person might want to run the app on another database.

0 commit comments

Comments
 (0)