## Introduction

[IDX](https://idx.xyz/?ref=blog.ceramic.network) is a protocol for building applications with user-centric, interoperable data. In [a previous post](https://blog.ceramic.network/idx-a-devkit-for-open-identity/), we described what IDX is and the benefits of building applications in this way. This tutorial will walk through the creation of a simple note-taking web app using **decentralized technologies** for authentication and data storage, allowing users to have **complete ownership** over their contents.

In this tutorial, we will use the following technologies:

- [React](https://github.com/facebook/create-react-app?ref=blog.ceramic.network): a popular framework for building web applications
- [IDX](https://github.com/ceramicstudio/js-idx?ref=blog.ceramic.network): a JavaScript/TypeScript framework for user-centric data management
- [Ceramic](/content/?ref=blog.ceramic.network): a decentralized network for storing mutable, verifiable data
- [DIDs](https://github.com/3box/identity-wallet-js?ref=blog.ceramic.network): a W3C standard for decentralized identifiers

The finished product ✨

## Environment setup

To get started using IDX, we'll first need to install the IDX CLI using `npm`. You'll also need to have `node` installed.

```bash

```

## Project setup

### Initial dependencies

We'll use Create React App with the TypeScript template to setup our project:

```bash

```

Then we'll add the first dependencies:

```bash

```

Let's also edit the `package.json` file to add the following `scripts`:

```json

```

Finally, as the `uint8arrays` package does not provide TypeScript definitions, let's add them to the `src/react-app-env.d.ts` file:

```javascript

```

### Local Ceramic node

Let's start a local Ceramic node using the script defined, and keep it running for all the steps of this tutorial:

```bash

```

We'll also need to bootstrap the local node with the IDX documents, using the IDX CLI previously installed:

```bash

```

### Data model

By using Ceramic and IDX, we can create a data model for our application that is **user-centric** (instead of application-siloed),  **globally available** from any client on the Ceramic network, and **publicly** **discoverable and shareable** across _any_ application(s) that a user interacts with. This is all made possible thanks to public **schemas,** data **definitions,** and the user's **IDX document**. Thus, by storing your application's user data in the IDX framework, it becomes truly user-centric and portable across app domains and contexts.

- A **schema** is a [JSON-schema](https://json-schema.org/?ref=blog.ceramic.network) document created by a developer which can be used to validate the contents of other documents simply by including the unique identifier (StreamID) of the schema.
- A **definition** is a document created by a developer which provides metadata about the data that they want to store with the user. The StreamID of the definition acts as a unique key within the user's IDX document, and is used to identify a **reference** (the actual contents) associated to a specified **schema**.
- An **IDX document** is a document owned by a user which maintains an index of all of their data in a single place. It is a key-value store that stores mappings from _definitions_ to _references_.

For this notes management app, we'll use two types of documents and therefore two schemas:

- `Note`: this document will store the contents of a single note
- `NotesList`: the entry-point document to index the list of notes with metadata

We will need to create and publish these schemas to the local Ceramic node, along with a definition which allows us to interact with the notes list using IDX. This will allow our app and others to access the notes via the following path:

```
User DID —> IDX index —> notes definition —> notes list —> note 1
                                                        -> note 2
                                                        -> ...
```

Let's create a `bootstrap.js` script that will create and publish the schemas and definition to our Ceramic node as TileDocuments, and store the Ceramic stream ID (StreamID) of the definition to a JSON file that will be used by the app:

```javascript

```

### Interacting with our data model

Before moving forwards with implementing our app, let's first check we can interact with our data model using the IDX CLI.

First, we'll need to create a local DID that will be used by the CLI:

```bash

```

The `local` alias can be used to reference the DID in the following commands, rather than having to provide the full DID string.

Now we can create a note with some text using the `Note` schema URL added to `src/config.json`. In my case this URL is `ceramic://kjzl6cwe1jw14atxo8ax0mrknm7xfh8pxqy24hbdrxi9nagtwoa3la5s4hf32qr` but it will be different when using another seed, so don't forget to change it in the example below:

```bash

```

Successfully running this command will display the stream ID of the created note, that we can then add to the list of notes using the `notes` definition key added to `src/config.json`:

```bash

```

Make sure to replace the definition key (`kjzl6cwe1jw14almqh93rmt1mpv8h6zvyeyhh7jzlqp95kgv38c0jb5yuo8mo7w` in my case) and the created note URL (`ceramic://kjzl6cwe1jw147xhyjemd6r38812gzhhexw9mj3gz2vvkimotu5xktssik2cbzp` in the code above) with the values created in your environment.

We can now check the created note and notes list can be loaded:

```bash

```

## Application dependencies and IDX setup

Our app is going to use the following additional dependencies:

- [IDX](https://github.com/ceramicstudio/idx-web?ref=blog.ceramic.network), to interact with the list of notes
- [Material UI](https://github.com/mui-org/material-ui?ref=blog.ceramic.network) for UI components and icons
- A [random bytes generator](https://www.stablelib.com/modules/_random_random_.html?ref=blog.ceramic.network), to generate a seed

```bash

```

Then, let's create an `idx.ts` file in the `src` folder, implementing the logic to authenticate using a provided seed and load notes with IDX:

```ts

```

## Application state and actions

In this section, we'll implement the core logic of our app based on a **state**, **synchronous actions** mutating the state, and **high-level handlers** performing one or more actions.

First, let's create a `state.ts` file in the `src` folder with the following initial contents:

```ts

```

Here we are importing types and dependencies from React (the `useCallback` and `useReducer` hooks) and defining the valid shapes the application `State` can have.

Next we'll define an `Action` type that includes all the possible synchronous actions that can be performed to mutate the `State`:

```ts

```

To handle the state transitions, we'll use a reducer function, as presented in [React's documentation](https://reactjs.org/docs/hooks-reference.html?ref=blog.ceramic.network#usereducer):

```ts

```

Finally, let's create a React hook wrapping this logic in high-level handlers:

```ts

```

## Application UI

Now that our application logic is implemented, we can add the user interface, based on Material UI components.

For simplicity in this tutorial all the components are implemented in a single file, but more complex apps would gain from having the interface split into different modules.

Let's change the generated `App.tsx` file in the `src` folder, first to import the dependencies we'll use:

```ts

```

Next, let's create the styles we will use:

```ts

```

Now we'll create our first component: `NotesList`. This component displays the list of notes in a side menu, and a button to open a draft note.

This component will get the `State` and needed actions injected:

```ts

```

Another component we will need is `AuthenticateScreen`, that will display the authenticated ID or seed prompt as needed:

```ts

```

Next, let's add the `DraftScreen`, allowing users to create and save a new note:

```ts

```

We will use another component, `NoteScreen`, for displaying an existing note as the logic is a bit different from a draft, notably that we have to first load the document from Ceramic before being able to display the note contents:

```ts

```

Finally, we can use all these components in the top-level `App` component exported by this module:

```ts

```

## That's it!

You should now be able to start the app using the `npm start` command that will compile and start a local server.

The application logic and UI in this tutorial is intentionally kept simple for demonstration purposes, but could be greatly improved for a real app.

The full code for this tutorial is [available on GitHub](https://github.com/ceramicstudio/idx-demo-app?ref=blog.ceramic.network) if you want to use it as a basis for your own experiments.

## Moving to production

Using a local Ceramic node is an easy way to get started developing an app, but what about production use cases?

We are working with infrastructure partners who are eager to provide production-grade Ceramic node hosting services that we will recommend once ready. Other options are for you to host a Ceramic node for your users, or alternatively, build your app using a full Ceramic node in-browser with `@ceramicnetwork/core` (instead of the `@ceramicnetwork/http-client` used in this tutorial). Future tutorials and guides will dive into how to set up production Ceramic deployments.

In the meantime, feel free to reach out on the [Ceramic Discord](https://chat.ceramic.network/?ref=blog.ceramic.network) if you need support deploying Ceramic.

## What's next?

Learn more about IDX by visiting the [IDX website](https://idx.xyz/?ref=blog.ceramic.network) and [documentation](https://idx.xyz/docs?ref=blog.ceramic.network).

If you need any help or just want to say hi, join the [IDX Discord channel](https://chat.idx.xyz/?ref=blog.ceramic.network)!
