From cd0eed3bc3e3db991e79aa3f3e469596019f03a9 Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Wed, 20 Dec 2023 07:32:53 -0700 Subject: [PATCH 01/19] feat: rename 'Core Concepts' section to 'Learn', add 'Build' section placeholder --- src/pages/_data/navigation/mainNav.json5 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/_data/navigation/mainNav.json5 b/src/pages/_data/navigation/mainNav.json5 index 7ef32bc89..df4b9525b 100644 --- a/src/pages/_data/navigation/mainNav.json5 +++ b/src/pages/_data/navigation/mainNav.json5 @@ -8,7 +8,7 @@ { title: "Setup For a Local Event", url: "/get-started/at-an-event/" }, ] }, - { title: "Core Concepts", url: "/concepts/1_the_basics/", children: [ + { title: "Learn", url: "/concepts/1_the_basics/", children: [ { title: "Application Architecture", url: "/concepts/2_application_architecture/" }, { title: "Source Chain", url: "/concepts/3_source_chain/" }, { title: "DHT", url: "/concepts/4_dht/" }, @@ -21,6 +21,9 @@ { title: "Lifecycle Events", url: "/concepts/11_lifecycle_events/" }, ] }, + { title: "Build", url: "/build/1_hello_world/", children: [ + ] + }, { title: "References", url: "/references/", children: [ { title: "HDK (Rust)", url: "https://docs.rs/hdk", external: true }, { title: "App API reference", url: "https://docs.rs/holochain_conductor_api/latest/holochain_conductor_api/enum.AppRequest.html", external: true }, From 5cc4a0ecbfd78e643a8d520fb12d7d59c44f45f6 Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 8 Jan 2024 14:23:43 -0700 Subject: [PATCH 02/19] chore: add build page placeholder --- src/pages/build/1_hello_world.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/pages/build/1_hello_world.md diff --git a/src/pages/build/1_hello_world.md b/src/pages/build/1_hello_world.md new file mode 100644 index 000000000..6664c9a87 --- /dev/null +++ b/src/pages/build/1_hello_world.md @@ -0,0 +1,5 @@ +--- +title: "BUILD PAGE PLACEHOLDER" +--- + + \ No newline at end of file From 1d7ecc08b7e4a9f2606e47049863b7943605cc38 Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 8 Jan 2024 15:27:11 -0700 Subject: [PATCH 03/19] feat: update footer links to match main nav --- src/pages/_data/navigation/footerLinks.json5 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/_data/navigation/footerLinks.json5 b/src/pages/_data/navigation/footerLinks.json5 index 681ccded4..4789bc801 100644 --- a/src/pages/_data/navigation/footerLinks.json5 +++ b/src/pages/_data/navigation/footerLinks.json5 @@ -4,7 +4,8 @@ title: "Developers", links: [ { title: "Get Started", url: "/get-started/" }, - { title: "Core Concepts", url: "/concepts/1_the_basics/" }, + { title: "Learn", url: "/concepts/1_the_basics/" }, + { title: "Build", url: "/build/1_hello_world/" }, { title: "Resources", url: "/references/" }, ] }, From 61ad68fc5dead5cdcd0edab0252e0bb179477247 Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 8 Jan 2024 15:28:31 -0700 Subject: [PATCH 04/19] feat: update footer link to match main nav --- src/pages/_data/navigation/footerLinks.json5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/_data/navigation/footerLinks.json5 b/src/pages/_data/navigation/footerLinks.json5 index 4789bc801..1ec745115 100644 --- a/src/pages/_data/navigation/footerLinks.json5 +++ b/src/pages/_data/navigation/footerLinks.json5 @@ -6,12 +6,12 @@ { title: "Get Started", url: "/get-started/" }, { title: "Learn", url: "/concepts/1_the_basics/" }, { title: "Build", url: "/build/1_hello_world/" }, - { title: "Resources", url: "/references/" }, + { title: "References", url: "/references/" }, ] }, { - title: "Resources", + title: "References", links: [ { title: "HDK (Rust)", url: "https://docs.rs/hdk", external: true }, { title: "App API reference", url: "https://docs.rs/holochain_conductor_api/latest/holochain_conductor_api/enum.AppRequest.html", external: true }, From e5027d40d1bd2dbeb3567b566a6ac8722b3184cd Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 8 Jan 2024 15:33:18 -0700 Subject: [PATCH 05/19] revert: rename Resources to References --- src/pages/_data/navigation/footerLinks.json5 | 4 ++-- src/pages/_data/navigation/mainNav.json5 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/_data/navigation/footerLinks.json5 b/src/pages/_data/navigation/footerLinks.json5 index 1ec745115..4789bc801 100644 --- a/src/pages/_data/navigation/footerLinks.json5 +++ b/src/pages/_data/navigation/footerLinks.json5 @@ -6,12 +6,12 @@ { title: "Get Started", url: "/get-started/" }, { title: "Learn", url: "/concepts/1_the_basics/" }, { title: "Build", url: "/build/1_hello_world/" }, - { title: "References", url: "/references/" }, + { title: "Resources", url: "/references/" }, ] }, { - title: "References", + title: "Resources", links: [ { title: "HDK (Rust)", url: "https://docs.rs/hdk", external: true }, { title: "App API reference", url: "https://docs.rs/holochain_conductor_api/latest/holochain_conductor_api/enum.AppRequest.html", external: true }, diff --git a/src/pages/_data/navigation/mainNav.json5 b/src/pages/_data/navigation/mainNav.json5 index df4b9525b..0888a9866 100644 --- a/src/pages/_data/navigation/mainNav.json5 +++ b/src/pages/_data/navigation/mainNav.json5 @@ -24,7 +24,7 @@ { title: "Build", url: "/build/1_hello_world/", children: [ ] }, - { title: "References", url: "/references/", children: [ + { title: "Resources", url: "/references/", children: [ { title: "HDK (Rust)", url: "https://docs.rs/hdk", external: true }, { title: "App API reference", url: "https://docs.rs/holochain_conductor_api/latest/holochain_conductor_api/enum.AppRequest.html", external: true }, { title: "Admin API reference", url: "https://docs.rs/holochain_conductor_api/latest/holochain_conductor_api/enum.AdminRequest.html", external: true }, From c5dfb128cde77b9eb4940cfb9da5603bd7d40787 Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 8 Jan 2024 15:34:20 -0700 Subject: [PATCH 06/19] revert --- src/pages/_data/navigation/mainNav.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/_data/navigation/mainNav.json5 b/src/pages/_data/navigation/mainNav.json5 index 0888a9866..df4b9525b 100644 --- a/src/pages/_data/navigation/mainNav.json5 +++ b/src/pages/_data/navigation/mainNav.json5 @@ -24,7 +24,7 @@ { title: "Build", url: "/build/1_hello_world/", children: [ ] }, - { title: "Resources", url: "/references/", children: [ + { title: "References", url: "/references/", children: [ { title: "HDK (Rust)", url: "https://docs.rs/hdk", external: true }, { title: "App API reference", url: "https://docs.rs/holochain_conductor_api/latest/holochain_conductor_api/enum.AppRequest.html", external: true }, { title: "Admin API reference", url: "https://docs.rs/holochain_conductor_api/latest/holochain_conductor_api/enum.AdminRequest.html", external: true }, From 67b799f4fda97bf846472588195e24996bff5146 Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Wed, 20 Dec 2023 07:37:43 -0700 Subject: [PATCH 07/19] refactor: split out hello world tutorial, forum tutorial, and deployment into seperate pages in 'Build' section --- src/pages/_data/navigation/mainNav.json5 | 2 + src/pages/build/1_hello_world.md | 105 +- src/pages/build/2_forum_tutorial.md | 1165 +++++++++++++++++++ src/pages/build/3_deployment.md | 92 ++ src/pages/get-started/index.md | 1315 ---------------------- 5 files changed, 1362 insertions(+), 1317 deletions(-) create mode 100644 src/pages/build/2_forum_tutorial.md create mode 100644 src/pages/build/3_deployment.md diff --git a/src/pages/_data/navigation/mainNav.json5 b/src/pages/_data/navigation/mainNav.json5 index df4b9525b..d33855b04 100644 --- a/src/pages/_data/navigation/mainNav.json5 +++ b/src/pages/_data/navigation/mainNav.json5 @@ -22,6 +22,8 @@ ] }, { title: "Build", url: "/build/1_hello_world/", children: [ + { title: "Forum App Tutorial", url: "/build/2_forum_tutorial/" }, + { title: "Packaging & Distribution", url: "/build/3_deployment/" }, ] }, { title: "References", url: "/references/", children: [ diff --git a/src/pages/build/1_hello_world.md b/src/pages/build/1_hello_world.md index 6664c9a87..e7bdd87e8 100644 --- a/src/pages/build/1_hello_world.md +++ b/src/pages/build/1_hello_world.md @@ -1,5 +1,106 @@ --- -title: "BUILD PAGE PLACEHOLDER" +title: "Build on Holochain: Hello World" --- - \ No newline at end of file +In this section, we’ll use Holochain’s scaff olding tool to generate a simple “Hello, World!” application. + +For this tutorial, we'll be working in `~/Holochain`. Create that folder now and move into it: + +```shell +mkdir ~/Holochain +``` + +```shell +cd ~/Holochain +``` + +## Scaffold a simple "Hello, World!" App + +In this section, we'll use Holochain's scaff +olding tool to generate a simple "Hello, World!" application. + +When getting started, seeing a simple but fully-functional app can be very helpful. You can have Holochain's scaffolding tool generate a "Hello, World!" application (but for a distributed multi-agent world) by typing the following in your command line terminal: + +```shell +nix run github:holochain/holochain#hc-scaffold -- example hello-world +``` + +The scaffolding tool should print out these four commands for you to run in order to run the app. Copy them from your terminal or from below: + +```shell +cd hello-world +``` +```shell +nix develop +``` +```shell +npm install +``` +```shell +npm start +``` + +After you run the last of these commands, you should see three windows open: + +![A screenshot showing two hApp windows in front of the Playground](/assets/img/get-started/1-running-app-first-look.png) + +* A web browser window with the Holochain Playground, which displays a visual representation of the app's state data +* Two windows showing the UI for two agents, both of which will have published a `Hello World` entry to the network. + +When you click on the "Look for Hellos" button, you should be able to see the hellos: + +![A screenshot showing one app window, with hello messages in different languages retrieved from the DHT](/assets/img/get-started/2-look-for-hellos.png) + +When you are done checking out this app, you can go back to the terminal and stop both agents by pressing Ctrl+C (Linux) or Cmd+C (macOS). + +!!! dig-deeper Understanding the layout of a scaffolded project + +Let's explore the different files and folders that make up the structure of the "Hello, World!" hApp that you just created. + +List the folders and files in our `hello-world/` folder by entering: + +```shell +ls +``` + +This table includes everything in the `hello-world/` folder as well as details of the contents of the `dnas/` subfolder since that makes up the bulk of the "Holochain" part of an application. For certain working folders, like `node_modules/`, `target/`, `tests/`, and `ui/`, the table only contains a high-level overview. + +| File/folder | Purpose | +|---------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +|
 ├── hello-world/         
| Root folder of the application. All other files and folders will reside here. | +|
 ├┬─ dnas/                
| This folder contains the DNA configuration and source code for the application. DNAs are one of the most important building blocks in Holochain. Simply put, **a DNA is the executable code for the game you are playing with your peers in Holochain.** And here is the twist: in Holochain, **every DNA creates its own peer-to-peer network** for the validation, storage, and serving of content. Every Holochain application contains at least one DNA. In this example hApp, we have just one: `hello_world`. | +|
 │└┬─ hello_world/        
| Folder for the `hello_world` DNA. It contains modules (zomes) that define the rules and API of this application. | +|
 │ ├┬─ workdir/           
| A working folder containing configuration files and compiled artifacts related to the DNA. | +|
 │ │├── dna.yaml          
| DNA manifest file. A YAML file that defines the properties and zomes of the DNA. YAML is a human-readable data serialization language. | +|
 │ │└── hello_world.dna   
| The compiled DNA file, which includes both the integrity and coordinator zomes. This file is used by Holochain to run the hApp. | +|
 │ └┬─ zomes/             
| The source code for zomes (short for chromosomes), which are the executable packages in a DNA. Each zome has its own name like `profile` or `chat`. Zomes define the core logic in a DNA, and can be composed together to create more powerful functionality. DNAs in Holochain are always composed out of one or more zomes. This folder contains zomes for the `hello_world` DNA. | +|
 │  ├┬─ coordinator/      
| This folder contains the coordinator zomes, which are responsible for this DNA's controller layer, such as reading/writing data and handling communication between peers. The public functions defined in these zomes' code become the application's API available to the UI and, depending on the needs of your app, to other peers in the same network. | +|
 │  │└┬─ hello_world/     
| Folder containing the source code for the package that will become the `hello_world` coordinator zome binary. Rust packages are called crates, and they have the following structure. | +|
 │  │ ├┬─ src/            
| Source code folder for the `hello_world` crate. | +|
 │  │ │└── lib.rs         
| The main source code file for the `hello_world` crate. In Rust, `lib.rs` is the entry point for a library crate, which is the kind of crate that a zome needs to be written as. If you have nothing else in here, you should have this file. | +|
 │  │ └── Cargo.toml      
| The manifest file for the crate that will become the `hello_world` coordinator zome, containing metadata, dependencies, and build options. This file tells Cargo, Rust's package manager, how to build the crate into a binary. | +|
 │  └┬─ integrity/        
| This folder contains the integrity zomes, which are responsible for the application's model layer, which define data structures and validation rules for application data. | +|
 │   └┬─ hello_world/     
| Folder containing the `hello_world_integrity` crate. | +|
 │    ├┬─ src/            
| Source code folder for the `hello_world_integrity` crate. | +|
 │    │└── lib.rs         
| The main source code file for the `hello_world_integrity` crate. | +|
 │    └── Cargo.toml      
| TThe Cargo manifest file for the `hello_world_integrity` crate. | +|
 ├── node_modules/        
| A folder containing cached JavaScript packages and dependencies for the user interface and tests. | +|
 ├── target/              
| A folder containing the compiled output from the Rust build process. | +|
 ├── tests/               
| A folder containing JavaScript-base test code for the application. | +|
 ├── ui/                  
| A folder containing the source code and assets for the web-based user interface of the "Hello, World!" application. This user interface will get distributed along with the application. | +|
 ├┬─ workdir/             
| A working folder containing configuration files and compliled artifacts related to the building of the whole hApp. | +|
 │├── happ.yaml           
| The manifest file for the hApp. It references the DNA files to be included, along with the roles they play in the application. In this case, there's only one DNA file, `hello_world`. | +|
 │├── hello_world.happ    
| The compiled hApp bundle, which includes all the DNAs (in case just the one). | +|
 │├── hello_world.webhapp 
| The compiled web hApp bundle, which includes the hApp bundle plus the zipped UI. | +|
 │└── web-happ.yaml       
| The manifest file for the hApp plus the UI. It references the compiled hApp bundle and zipped UI folder to be included. | +|
 ├── Cargo.lock           
| A file generated by Cargo, Rust's package manager, that lists the exact versions of dependencies used in the project. | +|
 ├── Cargo.toml           
| The main configuration file for the Rust project, containing dependencies, build options, and other metadata for all crates. | +|
 ├── flake.lock           
| A file generated by Nix, the package manager we use to distribute the Holochain development tools, that lists the exact versions of dependencies used in the project. | +|
 ├── flake.nix            
| A Nix file that defines the project's build environment and dependencies. | +|
 ├── package.json         
| The main configuration file for the JavaScript portions of the project, containing dependencies, scripts, and other metadata for the application's user interface and tests, as well certain build tools. | +|
 ├── package-lock.json    
| A file generated by npm, Node.js package manager, that lists the exact versions of dependencies used by Node.JS. | +|
 └── README.md            
| A Markdown file containing the documentation and instructions for the application, including how to build, run, and test the project. | + +These files and folders make up the structure of a Holochain application, with the main logic defined in the zomes (in the `dnas//zomes/` folders) and the user interface defined in the `ui/` folder. The manifest files bring all the Holochain and UI assets together, allowing the `hc` tool to bundle them into a single hApp file ready for distribution. + +!!! diff --git a/src/pages/build/2_forum_tutorial.md b/src/pages/build/2_forum_tutorial.md new file mode 100644 index 000000000..0b3b05cd1 --- /dev/null +++ b/src/pages/build/2_forum_tutorial.md @@ -0,0 +1,1165 @@ +--- +title: "Zero to built: creating a forum app" +tocData: + - text: 1. Scaffolding a hApp + href: 1-scaffolding-a-happ + - text: 2. Select user interface framework + href: 2-select-user-interface-framework + - text: 3. Set up Holonix development environment + href: 3-set-up-holonix-development-environment + - text: 4. Scaffold a DNA + href: 4-scaffold-a-dna + - text: 5. Scaffold a zome + href: 5-scaffold-a-zome + - text: 6. Scaffold entry types + href: 6-scaffold-entry-types + - text: 7. Scaffold a collection + href: 7-scaffold-a-collection + - text: 8. Run your applicaiton in dev mode + href: 8-run-your-application-in-dev-mode + - text: 9. Integrate the generated UI elements + href: 9-integrate-the-generated-ui-elements +--- + +First, navigate back to the folder where you want to keep your Holochain applications. If you followed our suggestion, you can get back to it by typing: + +```shell +cd ~/Holochain +``` + +Next up, we'll walk you through creating a forum application from scratch using Holochain's scaffolding tool, step-by-step. This forum application will enable participants to share text-based posts and to comment on those posts. + +Each post will have a title and content, and authors will be able to edit --- or update --- their posts. However, they won't be able to delete them. + +Each comment will be a reply to a particular post, will be limited in length to 140 characters, and will be able to be deleted but not updated. + +!!! info Validation tutorial coming soon +A future update to this guide will implement the above constraints as validation rules. For now, we'll just scaffold enough code to get a working UI. **Check back soon** to get the whole tutorial! +!!! + +We'll create a couple of other things along the way that will enable people to find these posts and comments, but we'll cover those things when we get there. + +The good news is that the Holochain scaffolding tool will do a lot of the heavy lifting in terms of generating folders, files, and boilerplate code. It will walk you through each step in the hApp generation process. In fact, the scaffolding tool does so much of the work for you that many people have commented that 90% or more of the time spent writing a Holochain app is focused on building out the front-end user interface and experience. + +First, let's use the scaffolding tool to generate the basic folders and files for our hApp. + +### 1. Scaffolding a hApp {#1-scaffolding-a-happ} + +To start, run the following command in your terminal: + +```shell +nix run github:/holochain/holochain#hc-scaffold -- web-app +``` + +You should then see: + +::: output-block +```text +? App name (no whitespaces): +``` +::: + +Enter the name of your forum application using snake_case. Enter: + +```text +my_forum_app +``` + +### 2. Select user interface framework + +You'll then be prompted to choose a user interface (UI) framework for your front end. + +For this example, use the arrow keys to choose `Svelte` and press Enter. + +### 3. Set up Holonix development environment + +Next, you'll be asked if you want to set up the Holonix development environment for the project. This allows you to enter a shell that has all the right tools and libraries for the version of Holochain that your code was generated for. + +Choose `Yes (recommended)` and press Enter. + +You should see: + +::: output-block +```text +Setting up nix development environment... +``` +::: + +along with some details of what is being added. Follow the instructions to set up the development environment for your hApp and continue to scaffold more of its elements. + +First, enter the hApp project folder: + +```shell +cd my_forum_app +``` + +Just to get an overview of what your first scaffold command set up for you, you can check the contents of that `my_forum_app` folder by typing: + +```shell +ls +``` + +It should look like it has set up a similar set of folders and configuration files to those you saw in the "Hello, World!" hApp. + +Now, fire up the nix development shell, which makes all scaffolding tools and the Holochain binaries directly available from the command line, by entering: + +```shell +nix develop +``` + +After a short while of installing packages, you should see: + +::: output-block +```text +Holochain development shell spawned. Type exit to leave. +``` +::: + +As it says, if you want to leave the nix development shell at any time, you can type `exit`. This will take you back to your familiar shell without any of the special Holochain dependencies. When you want to re-enter it, navigate to the `my_forum_app` folder and type `nix develop` again. But for now, install the Node Package Manager (npm) dependencies with: + +```shell +npm install +``` + +These dependencies are used by various tools and assets --- the scaffolded tests, the UI, and various development activities like spawning apps for testing. + +When that finishes, you should see some text that ends with something like: + +::: output-block +```text +added 371 packages, and audited 374 packages in 1m + +37 packages are looking for funding + run 'npm fund' for details +found 0 vulnerabilities +``` +::: + +If you see something like that, you've successfully downloaded the NPM dependencies for the UI and for building your app. + +Next up, you're going to start creating the foundational building block of any Holochain app: its DNA. + +!!! dig-deeper Scaffolding subcommands + +To get an overview of the subcommands that `hc scaffold`` makes available to you, type: + +```shell +hc scaffold --help +``` + +You should see something like: + +::: output-block +```text +holochain_scaffolding_cli 0.1.8 +The list of subcommands for `hc scaffold` + +USAGE: + hc-scaffold + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +SUBCOMMANDS: + collection Scaffold a collection of entries in an existing zome + dna Scaffold a DNA into an existing app + entry-type Scaffold an entry type and CRUD functions into an existing zome + example + help Prints this message or the help of the given subcommand(s) + link-type Scaffold a link type and its appropriate zome functions into an existing zome + template Set up the template used in this project + web-app Scaffold a new, empty web app + zome Scaffold one or multiple zomes into an existing DNA +``` +::: + +You can get help on every one of these subcommands and its parameters by typing `hc scaffold --help`. +!!! + +!!! info Backing out of a mistake +A quick note: if while scaffolding some part of your hApp, you realize you've made a mistake (a typo or wrong selection for instance), as long as you haven't finished scaffolding that portion, **you can stop the current step** by using Ctrl+C on Linux or Command+C on macOS. +!!! + +### Scaffold a DNA + +A DNA folder is where you will put the code that defines the rules of your application. You're going to stay in the `my_forum_app/` root folder and, with some simple commands, the scaffolding tool will do much of the creation of relevant folders and files for you. + +!!! dig-deeper DNAs: Context and Background {#about-dnas} + +#### Why do we use the term DNA? + +In Holochain, we are trying to enable people to **choose to participate in coherent social coordination**, or interact meaningfully with each other online without needing a central authority to define the rules and keep everyone safe. To do that, we are borrowing some patterns from how biological organisms are able to coordinate coherently even at scales that social organisations such as companies or nations have come nowhere close to. In living creatures like humans, dolphins, redwood trees, and coral reefs, many of the cells in the body of an organism (trillions of the cells in a human body, for instance) are each running a (roughly) identical copy of a rule set in the form of DNA. + +This enables many different independent parts (cells) to build relatively consistent superstructures (a body, for instance), move resources, identify and eliminate infections, and more --- all without centralized command and control. There is no "CEO" cell in the body telling everybody else what to do. It's a bunch of independent actors (cells) playing by a consistent set of rules (the DNA) coordinating in effective and resilient ways. + +A cell in the muscle of your bicep finds itself in a particular context, with certain resources and conditions that it is facing. Based on those signals, that cell behaves in particular ways, running relevant portions of the larger shared instruction set (DNA) and transforming resources in ways that make sense for a bicep muscle cell. A different cell in your blood, perhaps facing a context where there is a bacterial infection, will face a different set of circumstances and consequently will make use of other parts of the shared instruction set to guide how it behaves. In other words, many biological organisms make use of this pattern where **many participants run the same rule set, but each in its own context**, and that unlocks a powerful capacity for coherent coordination. + +Holochain borrows this pattern that we see in biological coordination to try to enable similarly coherent social coordination. However, our focus is on enabling such coherent social coordination to be "opted into" by the participants. We believe that this pattern of being able to choose which games you want to play --- and being able to leave them or adapt them as experience dictates --- is critical to enabling individual and collective adaptive capacity. We believe that it may enable a fundamental shift in the ability of individuals and communities to sense and respond to the situations that they face. + +To put it another way: if a group of us can all agree to the rules of a game, then together we can play that game. + +All of us opting in to those rules --- and helping to enforce them --- enables us to play that game together, whether it is a game of chess, chat, a forum app, or something much richer. + +#### DNA as boundary of network + +The network of participants that are running a DNA engage in "peer witnessing" of actions by the participants in that network. A (deterministically random) set of peers are responsible for validating, storing, and serving each particular piece of shared content. In other words, the users of a particular hApp agree to a set of rules and then work together collectively to enforce those rules and to store and serve content (state changes) that do not violate those rules. + +Every hApp needs to include at least one DNA. Moreover, as indicated above, **it is at the DNA level** (note: not the higher application level) **where participants will form a network of peers to validate, store, and serve content** in accordance with the rules defined in that DNA. This happens in the background as the application runs on each participant's machine. + +There are some powerful consequences to this architectural choice --- including freedom to have your application look and feel the way you want, or to combine multiple DNAs together in ways that work for you without having to get everyone else to agree to do the same --- but we'll save those details for later. + +#### So if we have multiple DNAs in our hApp... + +...then we are participating in multiple networks, with each network of peers that are participating in a particular DNA also helping maintain the shared database for each DNA, enforcing the DNA's rules while validating, storing, and serving content. Each network acts as a 'social organism' in cooperation with other networks in the hApp. + +This is similar to the way in which multiple DNA communities coexist in biological organisms. In fact, there are more cells in a human body that contain other DNA (like bacteria and other microorganisms) than cells that contain our DNA. This indicates that we are an _ecology_ of coherent communities that are interacting with --- and evolving alongside --- one another. + +When it comes to hApps, this lets us play coherent games with one another at the DNA level, while also participating in adjacent coherent games with others as well. That means that applications are not one-size-fits-all. You can choose to combine different bits of functionality in interesting and novel ways. + +!!! + +It's time to scaffold a new DNA by entering: + +```shell +hc scaffold dna +``` + +You should then see: + +::: output-block +```text +? DNA name (snake_case): +``` +::: + +Enter a name for the DNA: + +```text +forum +``` + +You should then see: + +::: output-block +```text +DNA "forum" scaffolded! +Add new zomes to your DNA with: + hc scaffold zome +``` +::: + +Success! Inside of your `dnas/` folder, the scaffolding tool generated a `forum/` folder and, inside of that, the folders and files that the DNA needs. At this point you have a skeleton structure for your `forum` DNA. As you take the following steps, the scaffolding tool will make additions and edits to some of those folders and files based on your instructions. + +### 5. Scaffold a zome + +DNAs are comprised of code modules, which we call zomes (short for chromosomes). Zomes are modules that typically focus on enabling some small unit of functionality. Building with this sort of modular pattern provides a number of advantages, including the ability to reuse a module in more than one DNA to provide similar functionality in a different context. For instance, the [profiles zome](https://github.com/holochain-open-dev/profiles) is one that many apps make use of. For the forum DNA, you'll be creating two zomes: `posts` and `posts_integrity`. + +Start by entering: + +```shell +hc scaffold zome +``` + +You should then see: + +::: output-block +```text +? What do you want to scaffold? › +❯ Integrity/coordinator zome-pair (recommended) + Only an integrity zome + Only a coordinator zome +``` +::: + +!!! dig-deeper Integrity zomes and coordinator zomes + +#### Integrity zomes + +An integrity zome, as the name suggests, is responsible for maintaining the data integrity of a Holochain application. It sets the rules and ensures that any data writes occurring within the application are consistent with those rules. In other words, it is responsible for ensuring that data is correct, complete, and trustworthy. Integrity zomes help maintain a secure and reliable distributed peer-to-peer network by enforcing the validation rules defined by the application developer --- in this case, you! + +#### Coordinator zomes + +On the other hand, a coordinator zome contains the code that actually commits data, retrieves it, or sends and receives messages between peers or between other portions of the application on a user's own device (between the back end and the front-end UI, for instance). A coordinator zome is where you define the API for your DNA, through which the network of peers and their data is made accessible to the user. + +#### Multiple zomes per DNA + +As you learned earlier, a DNA can have multiple integrity and coordinator zomes. Each integrity zome contributes to the full set of different types of valid data that can be written, while each coordinator zome contributes to the DNA's functionality that you expose through its API. In order to write data of a certain type, a coordinator zome needs to specify a dependency on the integrity zome that defines that data type. A coordinator zome can also depend on multiple integrity zomes. + +#### Why two types? + +They are separated from one another so we can update coordinator zomes without having to update the integrity zomes. This is important, because changes made to an integrity zome result in a change of the rule set, which results in an entirely new network. This is because the integrity code is what defines the 'rules of the game' for a group of participants. If you changed the code of an integrity zome, you would find yourself suddenly in a new and different network from the other folks who haven't yet changed their integrity zome --- and we want to minimize those sorts of forks to situations where they are needed (like when a community decides they want to play by different rules, for instance changing the maximum length of comments from 140 characters to 280 characters). + +At the same time, a community will want to be able to improve the ways in which things are done in a Holochain app. This can take the form of adding new features or fixing bugs, and we also want people to also be able to take advantage of the latest features in Holochain. Separating integrity and coordination enables them to do that more easily, because: + +* Holochain's coordinator zome API receives frequent updates while the integrity zome API is fairly stable, and +* coordinator zomes can be added to or removed from a DNA at runtime without affecting the DNA's hash. + +!!! + +For this app, you're going to want both an integrity zome and a coordinator zome, so use the arrow keys to select: + +::: output-block +```text +Integrity/coordinator zome-pair +``` +::: + +and press Enter. + +You should then see: + +::: output-block +```text +? Enter coordinator zome name (snake_case): + (The integrity zome will automatically be named '{name of coordinator zome}_integrity') +``` +::: + +Enter the name: + +```text +posts +``` + +and press Enter. + +You should then see prompts asking if you want to scaffold the integrity and coordinator zomes in their respective default folders. + +Press Y for both prompts. + +As that runs (which will take a moment as the scaffold makes changes to various files) you should then see something like: + +::: output-block +```text +Coordinator zome "posts" scaffolded! +Updating crates.io index + Fetch [===> ] ... +``` +::: + (then after download is done...) +::: output-block +```text + Downloaded 244 crates (46.7 MB) in 4.27s (largest was `windows` at 11.9 MB) + +Add new entry definitions to your zome with: + hc scaffold entry-type +``` +::: + +Once that is all done, your hApp skeleton will have filled out a bit. Before you scaffold the next piece, it might be good to get a little context for how content is "spoken into being" when a participant publishes a post in a forum hApp. Read the following section to learn more. + +!!! dig-deeper Source chains, actions, and entries + +#### Source chain + +Any time a participant in a hApp takes some action that changes data, they add a record to a journal called a **source chain**. Each participant has their own source chain, a local, tamper-proof, and chronological store of the participant's actions in that application. + +This is one of the main differences between Holochain and other systems such as blockchains or centralized server-based applications. Instead of recording a "global" (community-wide) record of what actions have taken place, in Holochain actions are taken by agents and are thought of as transformations of their own state. + +One big advantage of this approach is that a single agent can be considered authoritative about the order in which they took actions. From their perspective, first they did A, then B, then C, etc. The fact that someone else didn't get an update about these changes, and possibly received them in a different order, doesn't matter. The order that the authoring agent took those actions will be captured in the actions themselves (thanks to each action referencing the previous one that they had taken, thus creating an ordered sequence --- or chain --- of actions). + +#### Actions and entries + +You'll notice that we used the word "action" a lot. In fact, **we call the content of a source chain record an action**. In Holochain applications, data is always "spoken into being" by an agent (a participant). Each record captures their act of adding, modifying, or removing data, rather than simply capturing the data itself. + +There are a few different kinds of actions, but the most common one is `Create`, which creates an 'entry' --- an arbitrary blob of bytes. Entries store most of the actual content created by a participant, such as the text of a post in our forum hApp. When someone creates a forum post, they're recording an action to their source chain that reads something like: _I am creating this forum post entry with the title "Intros" and the content "Where are you from and what is something you love about where you live?" and I would like my peers in the network to publicly store a record of this act._ So while an action is useful for storing noun-like data like messages and images, it's actually a verb, a record of an action that someone took to update their own state and possibly the shared database state as well. That also makes it well-suited to verb-like data like real-time document edits, game moves, and transactions. + +Every action contains the ID of its author (actually a cryptographic public key), a timestamp, a pointer to the previous source chain record, and a pointer to the entry data, if there is any. In this way, actions provide historical context and provenance for the entries they operate on. + +The pointer to the previous source chain record creates an unbroken history from the current record all the way back to the source chain's starting point. This 'genesis' record contains the hash of the DNA, which servs as both the identifier for the specific set of validation rules that all following records should follow and the ID of the network that this source chain's actions are participating in. + +An action is cryptographically signed by its author and is immutable (can't be changed or erased from either the source chain or the network's data store) once written. This, along with the validation rules specified by the DNA hash in the genesis record, are examples of a concept we call "intrinsic data integrity", in which data carries enough information about itself to be self-validating. + +Just as with a centralized application, we aren't just going to add this data into some database without checking it first. When a participant tries to write an action, Holochain first: + +1. ensures that the action being taken doesn't violate the validation rules of the DNA, +2. adds it as the next record to the source chain, and then +3. tells the participant's network peers about it so they can validate and store it, if it's meant to be public. + +The bits of shared information that all the peers in a network are holding are collectively called a distributed hash table, or DHT. We'll explain more about the DHT later. + +If you want to learn more, check out [The Source Chain: A Personal Data Journal](/concepts/3_source_chain/) and [The DHT: A Shared, Distributed Graph Database](/concepts/4_dht/). You'll also get to see it all in action in a later step, when you run your hApp for the first time. + +!!! + +Now it's time to start defining the structure and validation rules for data within your application. + +### 6. Scaffold entry types + +An entry type is a fundamental building block used to define the structure and validation rules for data within a distributed application. Each entry type corresponds to a specific kind of data that can be stored, shared, and validated within the application. + +!!! dig-deeper Entry types and validation + +An entry type is just a label, an identifier for a certain type of data that your DNA deals with. It serves as something to attach validation rules to in your integrity zome, and those rules are what give an entry type its meaning. They take the form of code in a function that gets called any time something is about to be stored, and because they're just code, they can validate all sorts of things. Here are a few key examples: + +* **Data structure**: When you use the scaffolding tool to create an entry type, it generates a Rust-based data type that define fields in your entry type, and it also generates code in the validation function that attempts to convert the raw bytes into an instance of that type. By providing a well-defined structure, this type ensures that data can be understood by the application. If it can't be deserialized into the appropriate Rust structure, it's not valid. + +* **Constraints on data**: Beyond simple fields, validation code can constrain the values in an entry --- for instance, it can enforce a maximum number of characters in a text field or reject nonsensical calendar dates. + +* **Privileges**: Because it originates in a source chain, an entry comes with metadata about its author. This can be used to control who can create, edit, or delete an entry. + +* **Contextual conditions**: Because an action is part of a chain of actions, it can be validated based on the agent's history --- for instance, to prevent currency transactions beyond a credit limit or disallow more than two comments per minute to discourage spam. An entry can also point to other entries in the DHT upon which it depends, and the data from those entries can be used in its validation. + +!!! + +Your bare-bones forum needs two entry types: `post` and `comment`. You'll define these in the `posts` integrity zome you just created in the previous step. The `post` entry type will define a `title` field and a `content` field. The `comment` entry type will define a `comment_content` field and a way of indicating which post the comment is about. + +To do this, just follow the instructions that the scaffold suggested for adding new entry definitions to your zome. + +Start with the `post` entry type by entering this command: + +```shell +hc scaffold entry-type +``` + +You should then see: + +::: output-block +```text +✔ Entry type name (snake_case): +``` +::: + +Enter the name: + +```text +post +``` + +You should then see: + +::: output-block +```text +Which fields should the entry contain? + +? Choose field type: › +❯ String + bool + u32 + i32 + f32 + Timestamp + ActionHash + EntryHash + DnaHash + AgentPubKey + Enum + Option of... + Vector of... +``` +::: + +The scaffolding tool is now prompting you to add fields to the `post` entry type. + +Fields are the individual components or attributes within an entry type that define the structure of the data. They determine the specific pieces of information to be stored in an entry and their respective data types. The scaffolding tool supports a collection of native Rust types such as booleans, numbers, enums (a choice between several predetermined values), optional values, and vectors (lists of items of the same type), along with Holochain-specific types that refer to other pieces of data on the DHT. + +For your `post` entry type, you're going to add `title` and `content` fields. Select `String` as the first field's type, and enter: + +```text +title +``` + +as the field name. + +Press Y for the field to be visible in the UI, and use the arrow keys to select `TextField` as the widget to render this field. (A `TextField` is a single-line input field designed for capturing shorter pieces of text.) + +When you see: + +::: output-block +```text +?Add another field to the entry?(y/n) +``` +::: + +press Y. + +Select `String` for this field's type too. Then enter + +```text +content +``` + +as the field name. + +Press Y for the field to be visible in the UI, and select `TextArea` as the widget to render the field. (A `TextArea` is a multi-line input field that allows users to enter larger blocks of text. That'll work better for blog posts.) + +After adding the `title` and `content` fields, press N when asked if you want to add another field. Next, you should see: + +::: output-block +```text +Which CRUD functions should be scaffolded (SPACE to select/unselect, ENTER to continue)? + Update +✔ Delete +``` +::: + +The scaffolding tool can add zome and UI functions for updating and deleting entries of this type. In this case, we want authors to be able to update posts, but not delete them, so use the arrow keys and the spacebar to ensure that `Update` has a check and `Delete` does not. It should look like this: + +::: output-block +```text +Which CRUD functions should be scaffolded (SPACE to select/unselect, ENTER to continue)? +✔ Update + Delete +``` +::: + +Then press Enter. + +At this point you should see: + +::: output-block +```text +? Should a link from the original entry be created when this entry is updated? › +❯ Yes (more storage cost but better read performance, recommended) + No (less storage cost but worse read performance) +``` +::: + +Select `Yes` by pressing Enter. + +!!! dig-deeper CRUD (create, read, update, delete) {#crud-create-read-update-delete} + +#### Mutating immutable data and improving performance + +In short, the above choice is about how changes get dealt with when a piece of content is updated. + +Because all data in a Holochain application is immutable once it's written, we don't just go changing existing content, because that would break the integrity of the agent's source chain as well as the data already in the DHT. So instead we add metadata to the original data, indicating that people should now look elsewhere for the data or consider it deleted. This is produced by `Update` and `Delete` source chain actions. + +For an `Update` action, the original `Create` or `Update` action and its entry content on the DHT get a `ReplacedBy` pointer to the new `Update` action and its entry content. + +When the scaffolding tool asks you whether to create a link from the original entry, though it's not talking about this pointer. Instead, it's talking about an extra piece of metadata that points to the _very newest_ entry in a chain of updates. If an entry were to get updated, and that update were updated, and this were repeated three more times, anyone trying to retrieve the entry would have to query the DHT six times before they finally found the newest revision. This extra link, which is not a built-in feature, 'jumps' them past the entire chain of updates at the cost of a bit of extra storage. The scaffolding tool will generate all the extra code needed to write and read this metadata in its update and read functions. + +For a `Delete` action, the original action and its entry content are simply marked as deleted. In the cases of both updating and deleting, all original data is still accessible if the application needs it. + +#### Resolving conflicts + +Multiple participants can mark a single entry as updated or deleted at the same time. This might be surprising, but Holochain does this for two good reasons. First, it's surprisingly difficult to decide which is the 'correct' version of a piece of data in a distributed system, because contributions may come from any peer at any time, even appearing unexpectedly long after they've been created. There are many strategies for resolving the conflicts that arise from this, which brings us to the second good reason: we don't want to impose a specific conflict resolution strategy on you. Your application may not even consider parallel updates and deletes on a single entry to be a conflict at all. + +#### CRUD functions + +**By default, the scaffolding tool generates a `create_' function in your coordinator zome for an entry type** because creating new data is a fundamental part of any application, and it reflects the core principle of Holochain's agent-centric approach --- the ability to make changes to your own application's state. + +Similarly, when a public entry is published, it becomes accessible to other agents in the network. Public entries are meant to be shared and discovered by others, so **a `read_' function is provided by default** to ensure that agents can easily access and retrieve publicly shared entries. (The content of _private_ entries, however, are not shared to the network.) For more info on entries, see: the **Core Concepts sections on [Source Chains](/concepts/3_source_chain/) and [DHT](/concepts/4_dht/)**. + +Developers decide whether to let the scaffolding tool generate `update_` and `delete_` functions based on their specific application requirements. More details in the Core Concepts section on [CRUD](/concepts/6_crud_actions/). + +!!! + +Next, you should see: + +::: output-block +```text +Entry type "post" scaffolded! + +Add new collections for that entry type with: + + hc scaffold collection +``` +::: + +We'll dive into collections in a moment, but first create the `comment` entry type. + +Again type: + +```shell +hc scaffold entry-type +``` + +This time enter the name: + +```text +comment +``` + +for the entry type name. + +You're going to add a `comment_content` field, so select the `String` field type and enter: + +```text +comment_content +``` + +Then select the `TextArea` widget and press Enter. (Again, a `TextArea` is a multi-line input field that allows users to enter larger blocks of text. Perfect for a comment on a post.) + +Press Y to add another field. + +For this next field you'll want to create a field that will help you associate each particular comment to the post that it is commenting on. To do this, the next field in the `comment` entry type will store a reference to a `post`. + +Use the arrow keys to select `ActionHash` as the field type. + +!!! dig-deeper Hashes and other identifiers + +There are two kinds of unique identifiers or 'addresses' in Holochain: **hashes** for data and **public keys** for agents. + +A hash is a unique "digital fingerprint" for a piece of data, generated by running it through a mathematical function called a **hash function**. None of the original data is present in the hash, but even so, the hash is extremely unlikely to be identical to the hash of any other piece of data. If you change even one character of the entry's content, the hash will be radically (and unpredictably) different. + +Holochain uses a hash function called blake2b. You can play with [an online blake2b hash generator](https://toolkitbay.com/tkb/tool/BLAKE2b_512) to see how changing content a tiny bit alters the hash. Try hashing `hi` and then `Hi` and compare their hashes. + +To ensure data integrity and facilitate efficient data retrieval, each piece of data is identified by its hash. This serves the following purposes: + +* **Uniqueness:** The cryptographic hashing function ensures that the data has a unique hash value, which helps to differentiate it from other data on the network. +* **Efficient lookup:** The hash is used as a key (essentially an address) in the network's storage system, the distributed hash table (DHT). When an agent wants to retrieve data, they simply search for it by hash, without needing to know what peer machine it's stored on. In the background, Holochain reaches out simultaneously to multiple peers who are responsible for the hash based on an algorithm that matches peers to data based on the similarity of the hash to their agent IDs. This makes data lookup fast and resilient to unreliable peers or network conditions. +* **Fair distribution:** Because the participants in a network are responsible for validating and storing each other's public data based on its hash, the randomness of the hashing function ensures that that responsibility is spread fairly evenly among everyone. +* **Integrity verification:** `Hi` will always generate the same hash no matter who runs it through the hashing function. So when data is retrieved by hash, its hash can be recalculated and compared with the original requested hash to ensure that a third party hasn't tampered with the data. +* **Collusion resistance:** The network peers who take responsibility for validating and storing an entry are chosen randomly based on the similarity of their agent IDs to the `EntryHash`. It would take a huge amount of computing power to generate a hash that would fall under the responsibility of a colluding peer. And because Holochain can retrieve data from multiple peers, it's more likely that the requestor can find one honest peer to report problems with a piece of bad data. + +#### `ActionHash` + +An action is identified by its `ActionHash`. Because an action contains information about its author, the time it was written, the action that preceded it, and the entry it operates on, no two action hashes will be the same --- even for the same entry. This helps to disambiguate identical entries written at different times by different agents. + +#### `EntryHash` + +An entry is identified by its `EntryHash`, which can be retrieved from the `ActionHash` of the action that wrote it. Because they're two separate pieces of data, an entry is stored by different peers than the action that operates on it. + +#### `AgentPubKey` + +**Each agent in a network is identified by their cryptographic public key**, a unique number that's mathematically related to a private number that they hold on their machine. Public-key cryptography is a little complex for this guide --- it's enough to know that a participant's private key signs their source chain actions, and those signatures paired with their public key allow others to verify that they are the one who authored those actions. + +An `AgentPubKey` isn't a hash, but it's the same length, and it's unique just like a hash. So it can be used as a way of referring to an agent, like a user ID --- and this is also why it's used to choose the right peers in the DHT storage and retrieval algorithm. + +#### Summary + +Whereas `EntryHash` is used to uniquely identify, store, and efficiently retrieve an entry from the DHT, `ActionHash` is used to uniquely identify, store, and retrieve the action (metadata) that operated on it, which can provide information about the history and context of any associated entry (including what action preceded it). `ActionHash`es are also what enable any participant to retrieve and reconstruct the continuous sequence of actions (and any associated entries) in another agent's source chain. + +**Use `EntryHash` when** you want to link to or retrieve the actual content or data (e.g., when linking to a category in a forum application). + +**Use `ActionHash` when** you want to link to or retrieve the authorship or history of an entry (e.g., when distinguishing between two posts with identical content). + +**Use `AgentPubKey` when** you want to link to an agent (such as associating a profile or icon with them) or retrieve information about their history (such as scanning their source chain for posts and comments). + +You can check out the Core Concepts to dive a bit deeper into [how the distributed hash table helps](/concepts/4_dht/) to not only make these entries and actions available but helps to ensure that agents haven't gone back to try and change their own histories after the fact. But for now, let's dive into links. + +!!! + +After press Enter, you should see: + +::: output-block +```text +? Should a link from this field be created when this entry is created? (y/n) › +``` +::: + +Press Y to accept creating a link. + +Next you will see: + +::: output-block +```text +✔ Which entry type is this field referring to? +``` +::: + +Press Enter to accept the suggested entry type `Post`. + +Next, you will be asked to pick a field name. You can press Enter to accept the field name suggestion, which should be: + +```text +post_hash +``` + +Press N to decline adding another field to the entry. + +Then use the arrow keys to deselect Update, but leave Delete selected. It should look as follows: + +::: output-block +```text +Which CRUD functions should be scaffolded (SPACE to select/unselect, ENTER to continue)? + Update +✔ Delete +``` +::: + +Once that is done, press Enter to generate a delete function for the **`comment`** entry type. + +You should then see: + +::: output-block +```text +Entry type "comment" scaffolded! + +Add new collections for that entry type with: + + hc scaffold collection +``` +::: + +The scaffolding will now have both added the `comment` entry type, and added a bunch more very useful code to our app using the native Holochain affordance of links. Links allow us to create paths that agents can follow to find associated content. So, the scaffolding not only added a reference to the post in the comment's entry, but it also added code such that when a comment is added, a link from the post back to the comment will also be created. If you want to see some of that code, take a look at the `dnas/forum/zomes/integrity/posts/src/lib.rs` file and you should see right near the top that a function has been created for validating the creation of a `post_to_comments` link. Similarly, other validation functions related to the deletion of those links follow after. + +!!! dig-deeper How links are stored and retrieved in a Holochain app + +What exactly is a link? Where is it stored? How does it work? And what do they let us do that we couldn't do otherwise? + +Links enable us to build a graph of references from one piece of content to other pieces of content in a DHT and then to navigate that graph. This is important because without some sort of trail to follow, it is infeasible to just "search for all content" thanks to the address space (all possible hashes) being so large and spread out across machines that iterating through tme all could take millions of years. + +By linking from known things to unknown things, we enable the efficient discovery and retrieval of related content in our hApp. + +**Storage**: When an agent creates a link between two entries, a `CreateLink` action is written to their source chain. A link is so small that there's no entry for the action. It simply contains the address of the base, the address of the target, the link type (which describes the relationship), and an optional tag which contains a small amount of application-specific information. The base and target can be any sort of DHT address --- an `EntryHash`, an `ActionHash`, or an `AgentPubKey`. But there doesn't actually need to be any data at that base, which is useful for referencing data that exists in another hash-based data store outside the DHT. + +After storing the action in the local source chain, the agent then publishes the link to the DHT, where it goes to the peers who are responsible for storing the base address and gets attached to the address as metadata. + +**Lookup**: To look up and retrieve links in a Holochain app, agents can perform a `get_links` query on a base DHT address. This operation involves asking the DHT peers responsible for that address for any link metadata of a given link type attached to it, with an optional "starts-with" query on the link tag. The peers return a list of links matching the query, which contain the addresses of the targets, and the link types and tags. The agent can then retrieve the actual target data by performing a [`get`](https://docs.rs/hdk/latest/hdk/entry/fn.get.html) query on the target address, which may be an `EntryHash`, `ActionHash`, or `AgentPubKey` (or an empty result, in the case of data that doesn't exist on the DHT). + +For more information and examples, read the Core Concepts section on [Links and Anchors](/concepts/5_links_anchors/). + +!!! + +### 7. Scaffold a collection + +Now, let's create a collection that can be used to retrieve all the posts. A collection creates a link type for referring to the collected entry type (similarly to how a link type was created for linking from posts to comments), but collections also create an 'anchor' --- a small string --- as the base for the link so we can find all the items in the collection by starting from the anchor's known hash. + +To create a collection, type: + +```shell +hc scaffold collection +``` + +You should then see: + +::: output-block +```text +Collection name (snake_case, eg. "all_posts"): › +``` +::: + +Enter: + +```text +all_posts +``` + +and press Enter. You should then see: + +::: output-block +```text +? Which type of collection should be scaffolded? › +❯ Global (get all entries of the selected entry types) + By author (get entries of the selected entry types that a given author has created) +``` +::: + +Select **`Global`** and press Enter. You should then see: + +::: output-block +```text +? Which entry type should be collected? › +❯ Post + Comment +``` +::: + +Select **`Post`** and press Enter. You should then see: + +::: output-block +```text +Collection "all_posts" scaffolded! + +At first, the UI for this application is empty. If you want the newly scaffolded collection to be the entry point for its UI, import the element in `ui/src/App.svelte`: + + import AllPosts from './forum/posts/AllPosts.svelte'; + +And use the element in the `<div id="content" />` block by adding in this: + + <div id="content"><</AllPosts></div> +``` +::: + +These instructions tell us that if we want to include this generated UI component in the user interface of our hApp, we need to do some manual work: + + 1. Import the component, and + 2. Tell the UI to display the component. + +!!! dig-deeper How a collection is implemented + +We already explored how links make data in the DHT discoverable by connecting known DHT base addresses to unknown addresses. Essentially every address becomes an anchor point to hang a collection of links from. + +But there's one remaining problem: _where do you start?_ When someone starts their app for the first time, the only DHT base addresses they know about are their public key, the DNA hash, and the few actions and entries on their source chain. There's no obvious way to start discovering other people's data yet. + +This is where **collections** help out. A collection is just a bunch of links on a base address that's easy to find --- typically the address is hard-coded in the coordinator zome's code as the hash of a string such as `"all_posts"`. It's easy to get the links, because their base address is right there in the code. + +This pattern, which we call the "anchor pattern", is so useful that it's built right into Holochain's SDK --- integrity zomes that use it will have all the necessary entry and link types automatically defined, and coordinator zomes that use it will have functions that can retrieve anchors and the links attached to them. The scaffolded code uses this implementation behind the scenes. + +The built-in implementation is actually a simplification of a more general pattern called "paths", which is also built into the SDK. With paths, you can create trees of linked anchors, allowing you to create and query hierarchical structures. This can be used to implement categories, granular collections (for example, "all posts" → "all posts created in 2023" → "all posts created in 2023-05" → "all posts created on 2023-05-30"), and indexes for type-ahead search (for example, "all usernames" → "all usernames starting with 'mat'" → "all usernames starting with 'matt'"). What the SDK calls an `Anchor` is actually a tree with a depth of two, in which the root node is two empty bytes. + +Hierarchical paths serve another useful purpose. On the DHT, where every node is tasked with storing a portion of the whole data set, some anchors could become "hot spots" --- that is, they could have thousands or even millions of links attached to them. The nodes responsible for storing those links would bear a disproportionate data storage and serving burden. + +The examples of granular collections and type-ahead search indexes breaks up those anchors into increasingly smaller branches, so that each leaf node in the tree --- and hence each peer --- only has to store a small number of links. + +The scaffolding tool doesn't have any feature for building anchors and trees beyond simple one-anchor collections, but if you'd like to know more, you can read the Core Concepts section on [Links and Anchors](/concepts/5_links_anchors/) and the SDK reference for [`hash_path`](https://docs.rs/hdk/latest/hdk/hash_path/index.html) and [`anchor`](https://docs.rs/hdk/latest/hdk/hash_path/anchor/index.html). + +!!! + +Before you get started editing the UI, it's helpful to be able to actually run the scaffolded applciation. That way, you can watch changes take effect in real-time as you make them. So the next section will walk you through launching the application the tooling that's available there, and then in the section after that, we'll begin working with the `.svelte` files to build the UI. + +### 8. Run your application in dev mode + +At this stage, we'll incorporate some of the UI components that have been scaffolded by the scaffolding tool into our main application interface. Our aim here is to make all the functionality of our forum application accessible from a single, unified interface. We'll use Svelte to accomplish this, as it is the framework that we have chosen for the UI layer of our application. + +Start the forum hApp in develop mode from the command line: go to your terminal and, from the root folder (`my_forum_app/`), enter: + +```shell +npm start +``` + +!!! info Work in the nix shell +If you are having an issue, make sure that you are still in the nix shell. If not, re-enter `nix develop` first, then type the above command again. And remember that you can always exit nix shell by typing `exit` to get back to your normal shell. +!!! + +When you start the hApp with `npm start`, this launches Holochain in sandbox mode with two agents running that hApp, and opens three windows: + +1. A web browser window with Holochain Playground, a tool that makes visible the various actions that have taken place in our forum hApp. You should be able to see a couple of agents in a DHT, with mostly empty source chains and, correspondingly, a mostly empty graph. +2. An application window with one agent (conductor 0) running the forum hApp. This window lets us take actions as that agent (0, or Alice, if you prefer). +3. Another application window with a second agent (conductor 1) running the forum hApp. This window lets us take actions as the other agent (1, or Bob). + +![Three windows: two agent UIs and a web browser window with the Holochain Playground](/assets/img/get-started/3-two-uis-and-playground.png) + +These application windows allow us to test multiple agents in a Holochain network interacting with one another. It is all running on our one device, but the two conductors behave very much the same as separate agents on different machines would, minus network lag. + +Remember that a **conductor** is a Holochain runtime process executing on your computer. For more details see the [Application Architecture](/concepts/2_application_architecture/) section in the Core Concepts guide. + +These three windows together will let us interact with our hApp as we are building it. + +The Holochain Playground in particular is helpful because it creates visual representations of the data that has been created and the way it relates to other content. Take a look at it and click one of the two items in the **DHT Cells** window. These are your two agents. When you click one of them, some content gets displayed in the **Source Chain** window. These are the initial actions in that agent's source chain. The arrows point from newer content back to older content. + +From oldest to newest, in the newly created source chains, the records are: + +1. `DNA`, recording the hash of the DNA to be used to validate all subsequent source chain actions, +2. `AgentValidationPkg`, providing proof that this participant is allowed to participate in this hApp ([see more](https://www.holochain.org/how-does-it-work/) in Holochain: How does it work?), +3. A `Create` action which records the author's `AgentID`, which is their public key and serves as their ID in the network and its graph database. + +As agents begin writing posts, comments, and links to the DHT, you'll see the following records appear: + +4. `InitComplete`, indicating that all coordinator zomes have had a chance to do initial setup, then +5. Whatever actions the agent takes after that. + +The two application UI windows let you interact with the application and see what is working, what is not working, and how data propagates when we take particular actions. + +At first, each of the UI windows (conductors 0 for Alice and 1 for Bob) include instructions for you to go and examine the scaffolded UI elements by looking at the contents in the folder `ui/src///`, where `` and `` are generic placeholders for your DNA (`forum`) and zome (`post`). + +### 9. Integrate the generated UI elements + +Thus far, seven different UI components should have been generated as `.svelte` files in the `ui/src/forum/posts/` folder. Note that for ease of development, the sandbox testing environment live-reloads the UI as you edit UI files. So don't quit the process you started with `npm start`; instead, **open a new terminal window**. Then navigate to the root folder of your hApp (`my_forum_app/`) and list the files in `ui/src/forum/posts/` by entering: + +```shell +ls ui/src/forum/posts/ +``` + +You should see seven different `.svelte` files, plus a `types.ts` file: + +::: output-block +```text +AllPosts.svelte CreateComment.svelte PostDetail.svelte +CommentDetail.svelte CreatePost.svelte types.ts +CommentsForPost.svelte EditPost.svelte +``` +::: + +The next step is to edit the UI files in the text editor or integrated development environment of your choice to add scaffolded components and build a fully featured UI. To integrate all of these generated UI elements, you'll need to add them to `App.svelte` file located in the `ui/src/` folder, or to some other `.svelte` file that eventually gets included in `App.svelte`. + +If you don't yet have path commands for opening files in your prefered IDE, there are instructions for [VSCode/VSCodium](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line), [Sublime Text](https://www.sublimetext.com/docs/command_line.html#setup) and [WebStorm](https://www.jetbrains.com/help/webstorm/working-with-the-ide-features-from-command-line.html#5d6e8844). Going forward in this tutorial, we are going to use the `code` command when we mean for you to open files in your IDE, but you should substitute a different command (ex: `subl`, `vim`, `emacs` etc.) for `code` if you are using a different editor. + +Open the `App.svelte` file with your preferred IDE. + +```shell +code ui/src/App.svelte +``` + +Your `App.svelte` file will have three sections: + +1. a script section, +2. a main section containing a markup template, and +3. a style section containing a stylesheet template. + +!!! dig-deeper Detailed breakdown of `App.svelte` + +#### ` +``` + +This section contains the JavaScript/TypeScript code for the component. It imports various dependencies needed to build a single-page web app: + +* `svelte` is the Svelte engine itself, and its `onMount` function lets you register a handler to be run when the component is initialized, while `setContext` lets you pass data to be used in the rendering of the component. +* `@holochain/client` is the Holochain client library; first we load in some useful Holochain-related TypeScript types, followed by the client object itself. +* `@mwc/material-circular-progress` is just a UI component that gives us a spinner when something is loading. +* `./contexts` is generated by the scaffolding tool. It just contains a constant, the app-wide name for the 'context' that makes the Holochain client accessible to all components. In Svelte, a context is a state shared across components. + +After importing dependencies, it does some initial setup. This is run when the component file is imported --- in this case the component, `App.svelte`, is the main component for the entire application, and it's imported into `main.ts` where it's 'mounted' (more on mounting in a moment). + +Next some variables are instantiated: one to hold the Holochain client that connects to the hApp backend via the conductor, and one to keep track of whether the client is connected yet. (This variable will be used to show a loading spinner while it's still connecting.) + +**Take note of the line that starts with `$:`**. This is a special Svelte label that turns regular variables into **reactive variables**. We won't get too deep into Svelte right now, because this is a tutorial about Holochain, but when a reactive variable changes, Svelte will re-render the entire component. This lets you write a template declaratively, enclosing the reactive variable in `{}` braces, and let Svelte handle the updating of the template wherever the variable changes. + +Finally, there's an `onMount` handler, which is run when the component is first displayed. The handler currently does one thing: it connects to the hApp backend via the conductor, waits until the connection is establised, sets `loading` to false, and adds the resulting client connection to the context so that all components can access it. + +#### `
` section + +```svelte +
+ {#if loading} +
+ +
+ {:else} +
+

EDIT ME! Add the components of your app here.

+ + Look in the ui/src/DNA/ZOME folders for UI elements that are generated with hc scaffold entry-type, hc scaffold collection and hc scaffold link-type and add them here as appropriate. + + For example, if you have scaffolded a "todos" dna, a "todos" zome, a "todo_item" entry type, and a collection called "all_todos", you might want to add an element here to create and list your todo items, with the generated ui/src/todos/todos/AllTodos.svelte and ui/src/todos/todos/CreateTodo.svelte elements. + + So, to use those elements here: +
    +
  1. Import the elements with: +
    +import AllTodos from './todos/todos/AllTodos.svelte';
    +import CreateTodo from './todos/todos/CreateTodo.svelte';
    +        
    +
  2. +
  3. Replace this "EDIT ME!" section with <CreateTodo></CreateTodo><AllTodos></AllTodos>.
  4. +
+
+ {/if} +
+``` + +This section is a template for the displayable content of the main app component. Using an `{#if}` block to test whether the reactive variable `loading` is true, this section displays a spinner until the backend can be accessed. Once the UI is connected to the backend, it shows some boilerplate text telling you to add something meaningful to the template. + +#### ` +``` + +This section is a template for the CSS styles that get applied to the HTML in the `
` section of the component. You can also use reactive variables here, and the styling will update whenever the variables change. These scaffolded styles set the component up with some basic layout to make it readable at small and large window sizes. + +**All Svelte components follow this general pattern**. `App.svelte` has special status as the root component, but otherwise it's just like any other component. + +!!! + +First you'll be adding a list of posts to the app, which means the components called `AllPosts.svelte` needs to be imported. + +At the top of the file, there is a list of scripts that are imported. Following the instructions that the scaffolding tool and the two conductor windows gave you, copy the following text and paste it into the script block of the `App.svelte` file, on the line below `import { clientContext } from './contexts';` + +```typescript +import AllPosts from './forum/posts/AllPosts.svelte'; +``` + +Next, add the component to the markup template in the `
` section of the file, where the "EDIT ME!" content now lives. Remove everything inside the `div` element that starts with this tag: + +:::output-block +```svelte +
+``` +::: + +and replace it with this line: + +```svelte + +``` + +Your `
` block should now look like this: + +```svelte +
+ {#if loading} +
+ +
+ {:else} +
+ +
+ {/if} +
+``` + +!!! info Svelte component tags +The `AllPosts` element is obviously not standard HTML. In Svelte, each component has a correspondingly named custom element that will get replaced by the rendered component's markup wherever it appears in another component's template. +!!! + +Save that file and take a look again at the two UI windows. They should both say 'No posts found'. + +![A UI showing the AllPosts component, which says 'No posts found'](/assets/img/get-started/4-no-posts-found.png) + +Let's fix that by adding the post creation component to the UI so we can add our first post. Import the `CreatePost.svelte` component by adding this line in the script section, just below the `AllPosts` component you previously imported: + +```typescript +import CreatePost from './forum/posts/CreatePost.svelte'; +``` + +Add this new component to the `
` block above the component you added: + +```svelte + +``` + +Now your `
` block should look like this: + +```svelte +
+ {#if loading} +
+ +
+ {:else} +
+ + +
+ {/if} +
+``` + +Save the file and switch to one of the two conductor windows. You should now see a post form. + +![The UI after adding the CreatePost component](/assets/img/get-started/5-create-post-component.png) + +Type something into one of the two conductor windows like: + +* Title: `Hi from Alice` +* Content: `Hello Bob!` + +and then press the "Create Post" button. + +You'll immediately notice that the `AllPosts` component has changed from saying "No posts found" to showing the newly created post. And if you take a look at the Holochain Playground window, you will see that two new actions have been created. If you click the `App` element that's appeared in Alice's source chain, it will pull up some details in the Entry Contents section, including the title and content of Alice's forum post. Note the hash of that entry (top of the Entry Contents window). Then click on the `Create` action that's pointing toward that `App` entry in the source chain. If you look back at the contents window, you will see that it is now sharing the contents of the action. And if you look down the list a bit, you will see the hash of the entry for the first post. + +![The Holochain playground showing a single agent's source chain, containing the actions that create a post, as well as the transformations in the DHT that resulted from these actions](/assets/img/get-started/6-playground-first-post.png) + +!!! dig-deeper Relationships in a source chain versus relationships in the DHT + +At this point, in our DHT graph it should look like we have two different agents and then a separate floating entry and action. But we know that the new post is associated with a source chain which is associated with an agent. So why aren't they connected on the DHT? + +A source chain merely serves as a history of one agent's attempts to manipulate the state of the graph database contained in the DHT. It's useful to think of the DHT as a completely separate data store that doesn't necessarily reflect agent-to-entry relationships unless you explicitly create a link type for them. + +For the purpose of this hApp, we're not interested in agent-to-posts relationships, so it's fine that they're not linked. But if you wanted to create a page that showed all posts by an author, that's when you might want to scaffold that link type. `hc scaffold collection` will do this for you if you choose a by-author collection, and will also create a `get_posts_by_author` function. + +!!! + +You may also notice that only Alice's UI showed the new post, while Bob's didn't. Just as with a traditional web app, database changes don't automatically send out a notification to everyone who is interested. (Alice's UI sees the changes because it knows how to update its own state for local changes.) You can create this functionality using a feature called [signals](/concepts/9_signals/), but let's keep things simple for now. Right-click anywhere in Bob's UI then choose "Reload" from the menu, and you'll see that the changes have been copied from Alice's app instance to Bob's --- all without a database server in the middle! + +Let's edit that post. In Alice's UI window, click the edit adjacent to the post content (it should look like a pencil icon). The post content will be replaced by an editing form. + +Now alter the content a bit. Maybe change it from `Hello Bob!` to `Hello, World!` and click "Save". + +![The UI of one agent, showing a post about to be edited](/assets/img/get-started/7-edit-post.png) + +That should update the post (at least for Alice). Bob's UI will show the updated version the next time it's reloaded. + +If you look at the Holochain Playground, you should see that the update was added to Alice's source chain. Specifically, it created: + +1. a new entry (with our `Hello, World!` text), +2. an `Update` action that indicated this entry is to replace the original entry, and +3. a `CreateLink` action that connects the original create action to the update action. + +![The Holochain playground, showing the source chain of the agent who edited the post along with new data in the DHT reflecting the edit](/assets/img/get-started/8-playground-after-edits.png) + +As explained [previously](#crud-create-read-update-delete), the original forum post already has a 'link' of sorts pointing from its action to the `Update` action, which can be accessed when the original is retrieved. The extra link created by the `CreateLink` action is optional --- it merely speeds up retrieval when an action has been edited many times and has a long chain of update links, by allowing you to jump to the end of the chain. In the screenshot above, the link is highlighted in the DHT pane. + +Now it's time to add commenting to your app. + +Previously, you added new components to the `App.svelte` component. That made sense because posts were a global data type. But comments are related to a post, so from now on you'll be modifying the `PostDetail.svelte` component instead. + +Open up `PostDetail.svelte` in your IDE: + +```shell +code ui/src/forum/posts/PostDetail.svelte +``` + +Just as before, first you'll need to import the components near the top of the file (just after the line that imports `EditPost.svelte`): + +```typescript +import CreateComment from './CreateComment.svelte'; +import CommentsForPost from './CommentsForPost.svelte'; +``` + +Further down the file, in the template block, add the components' elements to the template. Put them both before the closing `
` tag. + +Here, the comment components need to know what post they're related to. The post hash is the unique ID for the post, and the comment components' elements both expect a `postHash` attribute. This hash is available in the `PostDetail` component as a variable of the same name, so it can be passed to the comment widgets. + +```svelte + + +``` + +Save the file, then go back to the UI windows to see the changes. Try typing in a comment or two, then deleting them. (You may need to refresh the UI windows to see the changes to the content.) Watch the Playground --- see how the authors' source chains and the graph in the DHT change as new information is added. The deleted comments are still there and can be accessed by code in your zomes if needed, but neither the application backend (that is, the functions defined in the coordinator zome) nor the UI have the capacity to show them. + +![One UI window with the comment components added, with the Playground in the background showing a populated DHT](/assets/img/get-started/10-comment-components.png) + + +## 2. Next steps + +Congratulations! You've learned how to create a new Holochain application, understand its layout, work with core concepts, and deploy and test the application. + +Now that you have a basic understanding of Holochain development, you can continue exploring more advanced topics, such as: + +* Validating data +* Writing tests for a zome +* Implementing access and write privileges +* Building more complex data structures and relationships +* Optimizing your application for performance and scalability + + +### 2.1 Further exploration and resources + +Now that you have successfully built a basic forum application using Holochain and integrated it with a frontend, you may want to explore more advanced topics and techniques to further enhance your application or create new ones. Here are some resources and ideas to help you get started: + +#### Holochain developer documentation + +The official Holochain developer documentation is a valuable resource for deepening your understanding of Holochain concepts, techniques, and best practices. Be sure to explore the documentation thoroughly: + +* [Holochain Core Concepts](/concepts/1_the_basics/) +* [Holochain Developer Kit (HDK) reference](https://docs.rs/hdk/latest/hdk) + +#### Community resources + +The Holochain community is an excellent source of support, inspiration, and collaboration. Consider engaging with the community to further your learning and development: + +* [Holochain GitHub repositories](https://github.com/holochain) +* [Holochain Discord server](https://discord.com/invite/k55DS5dmPH) + +#### Example applications and tutorials + +Studying existing Holochain applications and tutorials can provide valuable insights and inspiration for your projects. Here are some resources to explore: + +* [Holochain Open Dev](https://github.com/holochain-open-dev) +* [Holochain Foundation sample apps](https://github.com/holochain-apps) diff --git a/src/pages/build/3_deployment.md b/src/pages/build/3_deployment.md new file mode 100644 index 000000000..09dfece5f --- /dev/null +++ b/src/pages/build/3_deployment.md @@ -0,0 +1,92 @@ +--- +title: "Deploying your Holochain application" +tocData: + - text: Packaging + href: packaging + - text: Runtimes + href: runtimes + children: + - text: Launcher + href: launcher-the-multi-app-runtime + - text: Standalone + href: standalone-executable +--- + + +Now that you've built an application, it's time to get it into other people's hands. First an app must be packaged into a distributable bundle format. Then it can be published somewhere a user can access it. + +## Packaging + +You specify the components of a hApp using manifest files, written in [YAML](https://yaml.org/), and the `hc` CLI looks for them when it's building a distributable hApp for you. If you look in the `workdir` folder: + +```shell +ls workdir +``` + +You'll see that the scaffolding tool has generated two manifest files for you: + +:::output-block +```text +happ.yaml web-happ.yaml +``` +::: output-block + +The first step is to package your app: + +```shell +npm run package +``` + +This command does a number of things: + +1. Triggers the Rust compiler to build the zomes, +2. Uses the `hc` CLI too to combine the built zomes and the DNA manifest into a `.dna` file, +3. Combines all the DNAs and the hApp manifest into a `.happ` file, +3. Builds the UI and compresses it into a `.zip` file, and +4. Combines the hApp file, the UI zip, and the web hApp manifest into a `.webhapp` file. + +Of course, this application only has one zome and one DNA, but more complex apps may have many of each. + +Now you'll see some new files in `workdir`: + +```shell +ls workdir +``` + +::: output-block +```text +happ.yaml my_forum_app.happ my_forum_app.webhapp web-happ.yaml +``` +::: output-block + +The packed app is now ready for deployment to a Holochain runtime. + +## Runtimes + +In the centralized world, deployment is usually achieved by Continuous Integration (CI) automation that builds up code changes and sends them to whatever server or cloud-based platform you're using. In the decentralized world of Holochain, deployment happens when end-users download and run your hApp in the Holochain runtime. + +From the end-user perspective there are currently there are two ways to go about this, both of which will feel familiar: + +1. Download Holochain's official Launcher runtime and install the app from its app store or the filesystem. +2. Download an your app as its own standalone desktop executable, as they would any other application for their computer. + +### Launcher, the multi-app runtime + +Holochain's official end-user runtime is the [Holochain Launcher](https://github.com/holochain/launcher). It allows people to install apps from a built-in app store or from the filesystem. Installed apps can then be launched from a friendly UI. Note that the app store is itself a distributed Holochain application which provides details on applications that are available for download. As a developer you can either go through a simple publishing process and add your app to the app store where it will be available for installation by all people who use the Launcher, or you can share your application directly with end-users through your own channels and they can install it into their Holochain Launcher manually from the file system. + +You can try this latter approach immediately by downloading and running the Launcher! + +The steps for publishing an app to the Launcher's app store are documented in the Github repository of the Holochain Launcher [here](https://github.com/holochain/launcher#publishing-and-updating-an-app-in-the-devhub). + +### Standalone executable + +If you prefer to distribute your app as a full standalone executable, you will need to bundle the Holochain runtime and your app together and take care of the necessary interactions between them. Because Holochain itself is really just a set of Rust libraries, you can of course build your own application that uses those libraries, but that's a fair amount of work. Currently there are two much simpler paths for doing this: using either the [Electron](https://www.electronjs.org/) or [Tauri](https://tauri.app/) frameworks, both of which can generate cross-platform executables from standard web UIs. These frameworks also support inclusion of additional binaries, which in our case are the [holochain conductor](https://docs.rs/holochain/latest/holochain/) and the [lair keystore](https://docs.rs/lair_keystore/latest/lair_keystore/). Though there is quite a bit of complexity in setting things up for these frameworks, all the hard work has already been done for you: + +* **Electron**: Refer to the community-supported [electron-holochain-template](https://github.com/lightningrodlabs/electron-holochain-template/) repo. +* **Tauri**: See the officially supported [holochain-kanagroo](https://github.com/holochain-apps/holochain-kangaroo) repo. + +Both of these are GitHub template repos with detailed instructions on how to clone the repos and add in your UI and DNA, as well as build and release commands that will create the cross-platform executables that you can then deliver to your end users. + +!!! note Code Signing +For macOS and Windows, you will probably also want to go through the process of registering as a developer so that your application can be "code-signed". This is needed so that users don't get the "unsigned code" warnings when launching the applications on those platforms. Both of the above templates include instructions for CI automation to run the code-signing steps on release once you have acquired the necessary certificates. +!!! \ No newline at end of file diff --git a/src/pages/get-started/index.md b/src/pages/get-started/index.md index a31e45ded..fb56bf351 100644 --- a/src/pages/get-started/index.md +++ b/src/pages/get-started/index.md @@ -5,38 +5,6 @@ tocData: href: 1-introduction-to-holochain - text: 2. Installing Holochain development environment href: 2-installing-holochain-development-environment - - text: 3. Scaffold a simple "Hello, World!" Holochain application - href: 3-scaffold-a-simple-hello-world-holochain-application - - text: "4. Zero to built: creating a forum app" - href: 4-zero-to-built-creating-a-forum-app - children: - - text: 4.1. Scaffolding a hApp - href: 4-1-scaffolding-a-happ - - text: 4.2. Select user interface framework - href: 4-2-select-user-interface-framework - - text: 4.3. Set up Holonix development environment - href: 4-3-set-up-holonix-development-environment - - text: 4.4. Scaffold a DNA - href: 4-4-scaffold-a-dna - - text: 4.5. Scaffold a zome - href: 4-5-scaffold-a-zome - - text: 4.6. Scaffold entry types - href: 4-6-scaffold-entry-types - - text: 4.7. Scaffold a collection - href: 4-7-scaffold-a-collection - - text: 4.8. Run your applicaiton in dev mode - href: 4-8-run-your-application-in-dev-mode - - text: 4.9. Integrate the generated UI elements - href: 4-9-integrate-the-generated-ui-elements - - text: 5. Deploying your Holochain application - href: 5-deploying-your-holochain-application - children: - - text: 5.1 Packaging - href: 5-1-packaging - - text: 5.2 Runtimes - href: 5-2-runtimes - - text: 6. Next steps - href: 6-next-steps --- Welcome to the Getting Started with Holochain guide! This guide will walk you through the process of installing the Holochain development tools and creating a simple forum application. By the end of this guide, you'll be familiar with the core concepts of Holochain and have a basic understanding of how to develop peer-to-peer applications using the Holochain framework. @@ -117,1212 +85,6 @@ holochain_scaffolding_cli x.y.z Congratulations! The Holochain development environment is now set up successfully on your system. -**Before moving on to the next step**, find a folder to put your work. For this tutorial, we'll be working in `~/Holochain`. Create that folder now and move into it: - -```shell -mkdir ~/Holochain -``` - -```shell -cd ~/Holochain -``` - -## 3. Scaffold a simple "Hello, World!" Holochain application - -In this section, we'll use Holochain's scaffolding tool to generate a simple "Hello, World!" application. - -When getting started, seeing a simple but fully-functional app can be very helpful. You can have Holochain's scaffolding tool generate a "Hello, World!" application (but for a distributed multi-agent world) by typing the following in your command line terminal: - -```shell -nix run github:holochain/holochain#hc-scaffold -- example hello-world -``` - -The scaffolding tool should print out these four commands for you to run in order to run the app. Copy them from your terminal or from below: - -```shell -cd hello-world -``` -```shell -nix develop -``` -```shell -npm install -``` -```shell -npm start -``` - -After you run the last of these commands, you should see three windows open: - -![A screenshot showing two hApp windows in front of the Playground](/assets/img/get-started/1-running-app-first-look.png) - -* A web browser window with the Holochain Playground, which displays a visual representation of the app's state data -* Two windows showing the UI for two agents, both of which will have published a `Hello World` entry to the network. - -When you click on the "Look for Hellos" button, you should be able to see the hellos: - -![A screenshot showing one app window, with hello messages in different languages retrieved from the DHT](/assets/img/get-started/2-look-for-hellos.png) - -When you are done checking out this app, you can go back to the terminal and stop both agents by pressing Ctrl+C (Linux) or Cmd+C (macOS). - -!!! dig-deeper Understanding the layout of a scaffolded project - -Let's explore the different files and folders that make up the structure of the "Hello, World!" hApp that you just created. - -List the folders and files in our `hello-world/` folder by entering: - -```shell -ls -``` - -This table includes everything in the `hello-world/` folder as well as details of the contents of the `dnas/` subfolder since that makes up the bulk of the "Holochain" part of an application. For certain working folders, like `node_modules/`, `target/`, `tests/`, and `ui/`, the table only contains a high-level overview. - -| File/folder | Purpose | -|---------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -|
 ├── hello-world/         
| Root folder of the application. All other files and folders will reside here. | -|
 ├┬─ dnas/                
| This folder contains the DNA configuration and source code for the application. DNAs are one of the most important building blocks in Holochain. Simply put, **a DNA is the executable code for the game you are playing with your peers in Holochain.** And here is the twist: in Holochain, **every DNA creates its own peer-to-peer network** for the validation, storage, and serving of content. Every Holochain application contains at least one DNA. In this example hApp, we have just one: `hello_world`. | -|
 │└┬─ hello_world/        
| Folder for the `hello_world` DNA. It contains modules (zomes) that define the rules and API of this application. | -|
 │ ├┬─ workdir/           
| A working folder containing configuration files and compiled artifacts related to the DNA. | -|
 │ │├── dna.yaml          
| DNA manifest file. A YAML file that defines the properties and zomes of the DNA. YAML is a human-readable data serialization language. | -|
 │ │└── hello_world.dna   
| The compiled DNA file, which includes both the integrity and coordinator zomes. This file is used by Holochain to run the hApp. | -|
 │ └┬─ zomes/             
| The source code for zomes (short for chromosomes), which are the executable packages in a DNA. Each zome has its own name like `profile` or `chat`. Zomes define the core logic in a DNA, and can be composed together to create more powerful functionality. DNAs in Holochain are always composed out of one or more zomes. This folder contains zomes for the `hello_world` DNA. | -|
 │  ├┬─ coordinator/      
| This folder contains the coordinator zomes, which are responsible for this DNA's controller layer, such as reading/writing data and handling communication between peers. The public functions defined in these zomes' code become the application's API available to the UI and, depending on the needs of your app, to other peers in the same network. | -|
 │  │└┬─ hello_world/     
| Folder containing the source code for the package that will become the `hello_world` coordinator zome binary. Rust packages are called crates, and they have the following structure. | -|
 │  │ ├┬─ src/            
| Source code folder for the `hello_world` crate. | -|
 │  │ │└── lib.rs         
| The main source code file for the `hello_world` crate. In Rust, `lib.rs` is the entry point for a library crate, which is the kind of crate that a zome needs to be written as. If you have nothing else in here, you should have this file. | -|
 │  │ └── Cargo.toml      
| The manifest file for the crate that will become the `hello_world` coordinator zome, containing metadata, dependencies, and build options. This file tells Cargo, Rust's package manager, how to build the crate into a binary. | -|
 │  └┬─ integrity/        
| This folder contains the integrity zomes, which are responsible for the application's model layer, which define data structures and validation rules for application data. | -|
 │   └┬─ hello_world/     
| Folder containing the `hello_world_integrity` crate. | -|
 │    ├┬─ src/            
| Source code folder for the `hello_world_integrity` crate. | -|
 │    │└── lib.rs         
| The main source code file for the `hello_world_integrity` crate. | -|
 │    └── Cargo.toml      
| TThe Cargo manifest file for the `hello_world_integrity` crate. | -|
 ├── node_modules/        
| A folder containing cached JavaScript packages and dependencies for the user interface and tests. | -|
 ├── target/              
| A folder containing the compiled output from the Rust build process. | -|
 ├── tests/               
| A folder containing JavaScript-base test code for the application. | -|
 ├── ui/                  
| A folder containing the source code and assets for the web-based user interface of the "Hello, World!" application. This user interface will get distributed along with the application. | -|
 ├┬─ workdir/             
| A working folder containing configuration files and compliled artifacts related to the building of the whole hApp. | -|
 │├── happ.yaml           
| The manifest file for the hApp. It references the DNA files to be included, along with the roles they play in the application. In this case, there's only one DNA file, `hello_world`. | -|
 │├── hello_world.happ    
| The compiled hApp bundle, which includes all the DNAs (in case just the one). | -|
 │├── hello_world.webhapp 
| The compiled web hApp bundle, which includes the hApp bundle plus the zipped UI. | -|
 │└── web-happ.yaml       
| The manifest file for the hApp plus the UI. It references the compiled hApp bundle and zipped UI folder to be included. | -|
 ├── Cargo.lock           
| A file generated by Cargo, Rust's package manager, that lists the exact versions of dependencies used in the project. | -|
 ├── Cargo.toml           
| The main configuration file for the Rust project, containing dependencies, build options, and other metadata for all crates. | -|
 ├── flake.lock           
| A file generated by Nix, the package manager we use to distribute the Holochain development tools, that lists the exact versions of dependencies used in the project. | -|
 ├── flake.nix            
| A Nix file that defines the project's build environment and dependencies. | -|
 ├── package.json         
| The main configuration file for the JavaScript portions of the project, containing dependencies, scripts, and other metadata for the application's user interface and tests, as well certain build tools. | -|
 ├── package-lock.json    
| A file generated by npm, Node.js package manager, that lists the exact versions of dependencies used by Node.JS. | -|
 └── README.md            
| A Markdown file containing the documentation and instructions for the application, including how to build, run, and test the project. | - -These files and folders make up the structure of a Holochain application, with the main logic defined in the zomes (in the `dnas//zomes/` folders) and the user interface defined in the `ui/` folder. The manifest files bring all the Holochain and UI assets together, allowing the `hc` tool to bundle them into a single hApp file ready for distribution. - -!!! - -## 4. Zero to built: creating a forum app - -First, navigate back to the folder where you want to keep your Holochain applications. If you followed our suggestion, you can get back to it by typing: - -```shell -cd ~/Holochain -``` - -Next up, we'll walk you through creating a forum application from scratch using Holochain's scaffolding tool, step-by-step. This forum application will enable participants to share text-based posts and to comment on those posts. - -Each post will have a title and content, and authors will be able to edit --- or update --- their posts. However, they won't be able to delete them. - -Each comment will be a reply to a particular post, will be limited in length to 140 characters, and will be able to be deleted but not updated. - -!!! info Validation tutorial coming soon -A future update to this guide will implement the above constraints as validation rules. For now, we'll just scaffold enough code to get a working UI. **Check back soon** to get the whole tutorial! -!!! - -We'll create a couple of other things along the way that will enable people to find these posts and comments, but we'll cover those things when we get there. - -The good news is that the Holochain scaffolding tool will do a lot of the heavy lifting in terms of generating folders, files, and boilerplate code. It will walk you through each step in the hApp generation process. In fact, the scaffolding tool does so much of the work for you that many people have commented that 90% or more of the time spent writing a Holochain app is focused on building out the front-end user interface and experience. - -First, let's use the scaffolding tool to generate the basic folders and files for our hApp. - -### 4.1. Scaffolding a hApp {#4-1-scaffolding-a-happ} - -To start, run the following command in your terminal: - -```shell -nix run github:/holochain/holochain#hc-scaffold -- web-app -``` - -You should then see: - -::: output-block -```text -? App name (no whitespaces): -``` -::: - -Enter the name of your forum application using snake_case. Enter: - -```text -my_forum_app -``` - -### 4.2. Select user interface framework - -You'll then be prompted to choose a user interface (UI) framework for your front end. - -For this example, use the arrow keys to choose `Svelte` and press Enter. - -### 4.3. Set up Holonix development environment - -Next, you'll be asked if you want to set up the Holonix development environment for the project. This allows you to enter a shell that has all the right tools and libraries for the version of Holochain that your code was generated for. - -Choose `Yes (recommended)` and press Enter. - -You should see: - -::: output-block -```text -Setting up nix development environment... -``` -::: - -along with some details of what is being added. Follow the instructions to set up the development environment for your hApp and continue to scaffold more of its elements. - -First, enter the hApp project folder: - -```shell -cd my_forum_app -``` - -Just to get an overview of what your first scaffold command set up for you, you can check the contents of that `my_forum_app` folder by typing: - -```shell -ls -``` - -It should look like it has set up a similar set of folders and configuration files to those you saw in the "Hello, World!" hApp. - -Now, fire up the nix development shell, which makes all scaffolding tools and the Holochain binaries directly available from the command line, by entering: - -```shell -nix develop -``` - -After a short while of installing packages, you should see: - -::: output-block -```text -Holochain development shell spawned. Type exit to leave. -``` -::: - -As it says, if you want to leave the nix development shell at any time, you can type `exit`. This will take you back to your familiar shell without any of the special Holochain dependencies. When you want to re-enter it, navigate to the `my_forum_app` folder and type `nix develop` again. But for now, install the Node Package Manager (npm) dependencies with: - -```shell -npm install -``` - -These dependencies are used by various tools and assets --- the scaffolded tests, the UI, and various development activities like spawning apps for testing. - -When that finishes, you should see some text that ends with something like: - -::: output-block -```text -added 371 packages, and audited 374 packages in 1m - -37 packages are looking for funding - run 'npm fund' for details -found 0 vulnerabilities -``` -::: - -If you see something like that, you've successfully downloaded the NPM dependencies for the UI and for building your app. - -Next up, you're going to start creating the foundational building block of any Holochain app: its DNA. - -!!! dig-deeper Scaffolding subcommands - -To get an overview of the subcommands that `hc scaffold`` makes available to you, type: - -```shell -hc scaffold --help -``` - -You should see something like: - -::: output-block -```text -holochain_scaffolding_cli 0.1.8 -The list of subcommands for `hc scaffold` - -USAGE: - hc-scaffold - -FLAGS: - -h, --help Prints help information - -V, --version Prints version information - -SUBCOMMANDS: - collection Scaffold a collection of entries in an existing zome - dna Scaffold a DNA into an existing app - entry-type Scaffold an entry type and CRUD functions into an existing zome - example - help Prints this message or the help of the given subcommand(s) - link-type Scaffold a link type and its appropriate zome functions into an existing zome - template Set up the template used in this project - web-app Scaffold a new, empty web app - zome Scaffold one or multiple zomes into an existing DNA -``` -::: - -You can get help on every one of these subcommands and its parameters by typing `hc scaffold --help`. -!!! - -!!! info Backing out of a mistake -A quick note: if while scaffolding some part of your hApp, you realize you've made a mistake (a typo or wrong selection for instance), as long as you haven't finished scaffolding that portion, **you can stop the current step** by using Ctrl+C on Linux or Command+C on macOS. -!!! - -### 4.4. Scaffold a DNA - -A DNA folder is where you will put the code that defines the rules of your application. You're going to stay in the `my_forum_app/` root folder and, with some simple commands, the scaffolding tool will do much of the creation of relevant folders and files for you. - -!!! dig-deeper DNAs: Context and Background {#about-dnas} - -#### Why do we use the term DNA? - -In Holochain, we are trying to enable people to **choose to participate in coherent social coordination**, or interact meaningfully with each other online without needing a central authority to define the rules and keep everyone safe. To do that, we are borrowing some patterns from how biological organisms are able to coordinate coherently even at scales that social organisations such as companies or nations have come nowhere close to. In living creatures like humans, dolphins, redwood trees, and coral reefs, many of the cells in the body of an organism (trillions of the cells in a human body, for instance) are each running a (roughly) identical copy of a rule set in the form of DNA. - -This enables many different independent parts (cells) to build relatively consistent superstructures (a body, for instance), move resources, identify and eliminate infections, and more --- all without centralized command and control. There is no "CEO" cell in the body telling everybody else what to do. It's a bunch of independent actors (cells) playing by a consistent set of rules (the DNA) coordinating in effective and resilient ways. - -A cell in the muscle of your bicep finds itself in a particular context, with certain resources and conditions that it is facing. Based on those signals, that cell behaves in particular ways, running relevant portions of the larger shared instruction set (DNA) and transforming resources in ways that make sense for a bicep muscle cell. A different cell in your blood, perhaps facing a context where there is a bacterial infection, will face a different set of circumstances and consequently will make use of other parts of the shared instruction set to guide how it behaves. In other words, many biological organisms make use of this pattern where **many participants run the same rule set, but each in its own context**, and that unlocks a powerful capacity for coherent coordination. - -Holochain borrows this pattern that we see in biological coordination to try to enable similarly coherent social coordination. However, our focus is on enabling such coherent social coordination to be "opted into" by the participants. We believe that this pattern of being able to choose which games you want to play --- and being able to leave them or adapt them as experience dictates --- is critical to enabling individual and collective adaptive capacity. We believe that it may enable a fundamental shift in the ability of individuals and communities to sense and respond to the situations that they face. - -To put it another way: if a group of us can all agree to the rules of a game, then together we can play that game. - -All of us opting in to those rules --- and helping to enforce them --- enables us to play that game together, whether it is a game of chess, chat, a forum app, or something much richer. - -#### DNA as boundary of network - -The network of participants that are running a DNA engage in "peer witnessing" of actions by the participants in that network. A (deterministically random) set of peers are responsible for validating, storing, and serving each particular piece of shared content. In other words, the users of a particular hApp agree to a set of rules and then work together collectively to enforce those rules and to store and serve content (state changes) that do not violate those rules. - -Every hApp needs to include at least one DNA. Moreover, as indicated above, **it is at the DNA level** (note: not the higher application level) **where participants will form a network of peers to validate, store, and serve content** in accordance with the rules defined in that DNA. This happens in the background as the application runs on each participant's machine. - -There are some powerful consequences to this architectural choice --- including freedom to have your application look and feel the way you want, or to combine multiple DNAs together in ways that work for you without having to get everyone else to agree to do the same --- but we'll save those details for later. - -#### So if we have multiple DNAs in our hApp... - -...then we are participating in multiple networks, with each network of peers that are participating in a particular DNA also helping maintain the shared database for each DNA, enforcing the DNA's rules while validating, storing, and serving content. Each network acts as a 'social organism' in cooperation with other networks in the hApp. - -This is similar to the way in which multiple DNA communities coexist in biological organisms. In fact, there are more cells in a human body that contain other DNA (like bacteria and other microorganisms) than cells that contain our DNA. This indicates that we are an _ecology_ of coherent communities that are interacting with --- and evolving alongside --- one another. - -When it comes to hApps, this lets us play coherent games with one another at the DNA level, while also participating in adjacent coherent games with others as well. That means that applications are not one-size-fits-all. You can choose to combine different bits of functionality in interesting and novel ways. - -!!! - -It's time to scaffold a new DNA by entering: - -```shell -hc scaffold dna -``` - -You should then see: - -::: output-block -```text -? DNA name (snake_case): -``` -::: - -Enter a name for the DNA: - -```text -forum -``` - -You should then see: - -::: output-block -```text -DNA "forum" scaffolded! -Add new zomes to your DNA with: - hc scaffold zome -``` -::: - -Success! Inside of your `dnas/` folder, the scaffolding tool generated a `forum/` folder and, inside of that, the folders and files that the DNA needs. At this point you have a skeleton structure for your `forum` DNA. As you take the following steps, the scaffolding tool will make additions and edits to some of those folders and files based on your instructions. - -### 4.5. Scaffold a zome - -DNAs are comprised of code modules, which we call zomes (short for chromosomes). Zomes are modules that typically focus on enabling some small unit of functionality. Building with this sort of modular pattern provides a number of advantages, including the ability to reuse a module in more than one DNA to provide similar functionality in a different context. For instance, the [profiles zome](https://github.com/holochain-open-dev/profiles) is one that many apps make use of. For the forum DNA, you'll be creating two zomes: `posts` and `posts_integrity`. - -Start by entering: - -```shell -hc scaffold zome -``` - -You should then see: - -::: output-block -```text -? What do you want to scaffold? › -❯ Integrity/coordinator zome-pair (recommended) - Only an integrity zome - Only a coordinator zome -``` -::: - -!!! dig-deeper Integrity zomes and coordinator zomes - -#### Integrity zomes - -An integrity zome, as the name suggests, is responsible for maintaining the data integrity of a Holochain application. It sets the rules and ensures that any data writes occurring within the application are consistent with those rules. In other words, it is responsible for ensuring that data is correct, complete, and trustworthy. Integrity zomes help maintain a secure and reliable distributed peer-to-peer network by enforcing the validation rules defined by the application developer --- in this case, you! - -#### Coordinator zomes - -On the other hand, a coordinator zome contains the code that actually commits data, retrieves it, or sends and receives messages between peers or between other portions of the application on a user's own device (between the back end and the front-end UI, for instance). A coordinator zome is where you define the API for your DNA, through which the network of peers and their data is made accessible to the user. - -#### Multiple zomes per DNA - -As you learned earlier, a DNA can have multiple integrity and coordinator zomes. Each integrity zome contributes to the full set of different types of valid data that can be written, while each coordinator zome contributes to the DNA's functionality that you expose through its API. In order to write data of a certain type, a coordinator zome needs to specify a dependency on the integrity zome that defines that data type. A coordinator zome can also depend on multiple integrity zomes. - -#### Why two types? - -They are separated from one another so we can update coordinator zomes without having to update the integrity zomes. This is important, because changes made to an integrity zome result in a change of the rule set, which results in an entirely new network. This is because the integrity code is what defines the 'rules of the game' for a group of participants. If you changed the code of an integrity zome, you would find yourself suddenly in a new and different network from the other folks who haven't yet changed their integrity zome --- and we want to minimize those sorts of forks to situations where they are needed (like when a community decides they want to play by different rules, for instance changing the maximum length of comments from 140 characters to 280 characters). - -At the same time, a community will want to be able to improve the ways in which things are done in a Holochain app. This can take the form of adding new features or fixing bugs, and we also want people to also be able to take advantage of the latest features in Holochain. Separating integrity and coordination enables them to do that more easily, because: - -* Holochain's coordinator zome API receives frequent updates while the integrity zome API is fairly stable, and -* coordinator zomes can be added to or removed from a DNA at runtime without affecting the DNA's hash. - -!!! - -For this app, you're going to want both an integrity zome and a coordinator zome, so use the arrow keys to select: - -::: output-block -```text -Integrity/coordinator zome-pair -``` -::: - -and press Enter. - -You should then see: - -::: output-block -```text -? Enter coordinator zome name (snake_case): - (The integrity zome will automatically be named '{name of coordinator zome}_integrity') -``` -::: - -Enter the name: - -```text -posts -``` - -and press Enter. - -You should then see prompts asking if you want to scaffold the integrity and coordinator zomes in their respective default folders. - -Press Y for both prompts. - -As that runs (which will take a moment as the scaffold makes changes to various files) you should then see something like: - -::: output-block -```text -Coordinator zome "posts" scaffolded! -Updating crates.io index - Fetch [===> ] ... -``` -::: - (then after download is done...) -::: output-block -```text - Downloaded 244 crates (46.7 MB) in 4.27s (largest was `windows` at 11.9 MB) - -Add new entry definitions to your zome with: - hc scaffold entry-type -``` -::: - -Once that is all done, your hApp skeleton will have filled out a bit. Before you scaffold the next piece, it might be good to get a little context for how content is "spoken into being" when a participant publishes a post in a forum hApp. Read the following section to learn more. - -!!! dig-deeper Source chains, actions, and entries - -#### Source chain - -Any time a participant in a hApp takes some action that changes data, they add a record to a journal called a **source chain**. Each participant has their own source chain, a local, tamper-proof, and chronological store of the participant's actions in that application. - -This is one of the main differences between Holochain and other systems such as blockchains or centralized server-based applications. Instead of recording a "global" (community-wide) record of what actions have taken place, in Holochain actions are taken by agents and are thought of as transformations of their own state. - -One big advantage of this approach is that a single agent can be considered authoritative about the order in which they took actions. From their perspective, first they did A, then B, then C, etc. The fact that someone else didn't get an update about these changes, and possibly received them in a different order, doesn't matter. The order that the authoring agent took those actions will be captured in the actions themselves (thanks to each action referencing the previous one that they had taken, thus creating an ordered sequence --- or chain --- of actions). - -#### Actions and entries - -You'll notice that we used the word "action" a lot. In fact, **we call the content of a source chain record an action**. In Holochain applications, data is always "spoken into being" by an agent (a participant). Each record captures their act of adding, modifying, or removing data, rather than simply capturing the data itself. - -There are a few different kinds of actions, but the most common one is `Create`, which creates an 'entry' --- an arbitrary blob of bytes. Entries store most of the actual content created by a participant, such as the text of a post in our forum hApp. When someone creates a forum post, they're recording an action to their source chain that reads something like: _I am creating this forum post entry with the title "Intros" and the content "Where are you from and what is something you love about where you live?" and I would like my peers in the network to publicly store a record of this act._ So while an action is useful for storing noun-like data like messages and images, it's actually a verb, a record of an action that someone took to update their own state and possibly the shared database state as well. That also makes it well-suited to verb-like data like real-time document edits, game moves, and transactions. - -Every action contains the ID of its author (actually a cryptographic public key), a timestamp, a pointer to the previous source chain record, and a pointer to the entry data, if there is any. In this way, actions provide historical context and provenance for the entries they operate on. - -The pointer to the previous source chain record creates an unbroken history from the current record all the way back to the source chain's starting point. This 'genesis' record contains the hash of the DNA, which servs as both the identifier for the specific set of validation rules that all following records should follow and the ID of the network that this source chain's actions are participating in. - -An action is cryptographically signed by its author and is immutable (can't be changed or erased from either the source chain or the network's data store) once written. This, along with the validation rules specified by the DNA hash in the genesis record, are examples of a concept we call "intrinsic data integrity", in which data carries enough information about itself to be self-validating. - -Just as with a centralized application, we aren't just going to add this data into some database without checking it first. When a participant tries to write an action, Holochain first: - -1. ensures that the action being taken doesn't violate the validation rules of the DNA, -2. adds it as the next record to the source chain, and then -3. tells the participant's network peers about it so they can validate and store it, if it's meant to be public. - -The bits of shared information that all the peers in a network are holding are collectively called a distributed hash table, or DHT. We'll explain more about the DHT later. - -If you want to learn more, check out [The Source Chain: A Personal Data Journal](/concepts/3_source_chain/) and [The DHT: A Shared, Distributed Graph Database](/concepts/4_dht/). You'll also get to see it all in action in a later step, when you run your hApp for the first time. - -!!! - -Now it's time to start defining the structure and validation rules for data within your application. - -### 4.6. Scaffold entry types - -An entry type is a fundamental building block used to define the structure and validation rules for data within a distributed application. Each entry type corresponds to a specific kind of data that can be stored, shared, and validated within the application. - -!!! dig-deeper Entry types and validation - -An entry type is just a label, an identifier for a certain type of data that your DNA deals with. It serves as something to attach validation rules to in your integrity zome, and those rules are what give an entry type its meaning. They take the form of code in a function that gets called any time something is about to be stored, and because they're just code, they can validate all sorts of things. Here are a few key examples: - -* **Data structure**: When you use the scaffolding tool to create an entry type, it generates a Rust-based data type that define fields in your entry type, and it also generates code in the validation function that attempts to convert the raw bytes into an instance of that type. By providing a well-defined structure, this type ensures that data can be understood by the application. If it can't be deserialized into the appropriate Rust structure, it's not valid. - -* **Constraints on data**: Beyond simple fields, validation code can constrain the values in an entry --- for instance, it can enforce a maximum number of characters in a text field or reject nonsensical calendar dates. - -* **Privileges**: Because it originates in a source chain, an entry comes with metadata about its author. This can be used to control who can create, edit, or delete an entry. - -* **Contextual conditions**: Because an action is part of a chain of actions, it can be validated based on the agent's history --- for instance, to prevent currency transactions beyond a credit limit or disallow more than two comments per minute to discourage spam. An entry can also point to other entries in the DHT upon which it depends, and the data from those entries can be used in its validation. - -!!! - -Your bare-bones forum needs two entry types: `post` and `comment`. You'll define these in the `posts` integrity zome you just created in the previous step. The `post` entry type will define a `title` field and a `content` field. The `comment` entry type will define a `comment_content` field and a way of indicating which post the comment is about. - -To do this, just follow the instructions that the scaffold suggested for adding new entry definitions to your zome. - -Start with the `post` entry type by entering this command: - -```shell -hc scaffold entry-type -``` - -You should then see: - -::: output-block -```text -✔ Entry type name (snake_case): -``` -::: - -Enter the name: - -```text -post -``` - -You should then see: - -::: output-block -```text -Which fields should the entry contain? - -? Choose field type: › -❯ String - bool - u32 - i32 - f32 - Timestamp - ActionHash - EntryHash - DnaHash - AgentPubKey - Enum - Option of... - Vector of... -``` -::: - -The scaffolding tool is now prompting you to add fields to the `post` entry type. - -Fields are the individual components or attributes within an entry type that define the structure of the data. They determine the specific pieces of information to be stored in an entry and their respective data types. The scaffolding tool supports a collection of native Rust types such as booleans, numbers, enums (a choice between several predetermined values), optional values, and vectors (lists of items of the same type), along with Holochain-specific types that refer to other pieces of data on the DHT. - -For your `post` entry type, you're going to add `title` and `content` fields. Select `String` as the first field's type, and enter: - -```text -title -``` - -as the field name. - -Press Y for the field to be visible in the UI, and use the arrow keys to select `TextField` as the widget to render this field. (A `TextField` is a single-line input field designed for capturing shorter pieces of text.) - -When you see: - -::: output-block -```text -?Add another field to the entry?(y/n) -``` -::: - -press Y. - -Select `String` for this field's type too. Then enter - -```text -content -``` - -as the field name. - -Press Y for the field to be visible in the UI, and select `TextArea` as the widget to render the field. (A `TextArea` is a multi-line input field that allows users to enter larger blocks of text. That'll work better for blog posts.) - -After adding the `title` and `content` fields, press N when asked if you want to add another field. Next, you should see: - -::: output-block -```text -Which CRUD functions should be scaffolded (SPACE to select/unselect, ENTER to continue)? - Update -✔ Delete -``` -::: - -The scaffolding tool can add zome and UI functions for updating and deleting entries of this type. In this case, we want authors to be able to update posts, but not delete them, so use the arrow keys and the spacebar to ensure that `Update` has a check and `Delete` does not. It should look like this: - -::: output-block -```text -Which CRUD functions should be scaffolded (SPACE to select/unselect, ENTER to continue)? -✔ Update - Delete -``` -::: - -Then press Enter. - -At this point you should see: - -::: output-block -```text -? Should a link from the original entry be created when this entry is updated? › -❯ Yes (more storage cost but better read performance, recommended) - No (less storage cost but worse read performance) -``` -::: - -Select `Yes` by pressing Enter. - -!!! dig-deeper CRUD (create, read, update, delete) {#crud-create-read-update-delete} - -#### Mutating immutable data and improving performance - -In short, the above choice is about how changes get dealt with when a piece of content is updated. - -Because all data in a Holochain application is immutable once it's written, we don't just go changing existing content, because that would break the integrity of the agent's source chain as well as the data already in the DHT. So instead we add metadata to the original data, indicating that people should now look elsewhere for the data or consider it deleted. This is produced by `Update` and `Delete` source chain actions. - -For an `Update` action, the original `Create` or `Update` action and its entry content on the DHT get a `ReplacedBy` pointer to the new `Update` action and its entry content. - -When the scaffolding tool asks you whether to create a link from the original entry, though it's not talking about this pointer. Instead, it's talking about an extra piece of metadata that points to the _very newest_ entry in a chain of updates. If an entry were to get updated, and that update were updated, and this were repeated three more times, anyone trying to retrieve the entry would have to query the DHT six times before they finally found the newest revision. This extra link, which is not a built-in feature, 'jumps' them past the entire chain of updates at the cost of a bit of extra storage. The scaffolding tool will generate all the extra code needed to write and read this metadata in its update and read functions. - -For a `Delete` action, the original action and its entry content are simply marked as deleted. In the cases of both updating and deleting, all original data is still accessible if the application needs it. - -#### Resolving conflicts - -Multiple participants can mark a single entry as updated or deleted at the same time. This might be surprising, but Holochain does this for two good reasons. First, it's surprisingly difficult to decide which is the 'correct' version of a piece of data in a distributed system, because contributions may come from any peer at any time, even appearing unexpectedly long after they've been created. There are many strategies for resolving the conflicts that arise from this, which brings us to the second good reason: we don't want to impose a specific conflict resolution strategy on you. Your application may not even consider parallel updates and deletes on a single entry to be a conflict at all. - -#### CRUD functions - -**By default, the scaffolding tool generates a `create_' function in your coordinator zome for an entry type** because creating new data is a fundamental part of any application, and it reflects the core principle of Holochain's agent-centric approach --- the ability to make changes to your own application's state. - -Similarly, when a public entry is published, it becomes accessible to other agents in the network. Public entries are meant to be shared and discovered by others, so **a `read_' function is provided by default** to ensure that agents can easily access and retrieve publicly shared entries. (The content of _private_ entries, however, are not shared to the network.) For more info on entries, see: the **Core Concepts sections on [Source Chains](/concepts/3_source_chain/) and [DHT](/concepts/4_dht/)**. - -Developers decide whether to let the scaffolding tool generate `update_` and `delete_` functions based on their specific application requirements. More details in the Core Concepts section on [CRUD](/concepts/6_crud_actions/). - -!!! - -Next, you should see: - -::: output-block -```text -Entry type "post" scaffolded! - -Add new collections for that entry type with: - - hc scaffold collection -``` -::: - -We'll dive into collections in a moment, but first create the `comment` entry type. - -Again type: - -```shell -hc scaffold entry-type -``` - -This time enter the name: - -```text -comment -``` - -for the entry type name. - -You're going to add a `comment_content` field, so select the `String` field type and enter: - -```text -comment_content -``` - -Then select the `TextArea` widget and press Enter. (Again, a `TextArea` is a multi-line input field that allows users to enter larger blocks of text. Perfect for a comment on a post.) - -Press Y to add another field. - -For this next field you'll want to create a field that will help you associate each particular comment to the post that it is commenting on. To do this, the next field in the `comment` entry type will store a reference to a `post`. - -Use the arrow keys to select `ActionHash` as the field type. - -!!! dig-deeper Hashes and other identifiers - -There are two kinds of unique identifiers or 'addresses' in Holochain: **hashes** for data and **public keys** for agents. - -A hash is a unique "digital fingerprint" for a piece of data, generated by running it through a mathematical function called a **hash function**. None of the original data is present in the hash, but even so, the hash is extremely unlikely to be identical to the hash of any other piece of data. If you change even one character of the entry's content, the hash will be radically (and unpredictably) different. - -Holochain uses a hash function called blake2b. You can play with [an online blake2b hash generator](https://toolkitbay.com/tkb/tool/BLAKE2b_512) to see how changing content a tiny bit alters the hash. Try hashing `hi` and then `Hi` and compare their hashes. - -To ensure data integrity and facilitate efficient data retrieval, each piece of data is identified by its hash. This serves the following purposes: - -* **Uniqueness:** The cryptographic hashing function ensures that the data has a unique hash value, which helps to differentiate it from other data on the network. -* **Efficient lookup:** The hash is used as a key (essentially an address) in the network's storage system, the distributed hash table (DHT). When an agent wants to retrieve data, they simply search for it by hash, without needing to know what peer machine it's stored on. In the background, Holochain reaches out simultaneously to multiple peers who are responsible for the hash based on an algorithm that matches peers to data based on the similarity of the hash to their agent IDs. This makes data lookup fast and resilient to unreliable peers or network conditions. -* **Fair distribution:** Because the participants in a network are responsible for validating and storing each other's public data based on its hash, the randomness of the hashing function ensures that that responsibility is spread fairly evenly among everyone. -* **Integrity verification:** `Hi` will always generate the same hash no matter who runs it through the hashing function. So when data is retrieved by hash, its hash can be recalculated and compared with the original requested hash to ensure that a third party hasn't tampered with the data. -* **Collusion resistance:** The network peers who take responsibility for validating and storing an entry are chosen randomly based on the similarity of their agent IDs to the `EntryHash`. It would take a huge amount of computing power to generate a hash that would fall under the responsibility of a colluding peer. And because Holochain can retrieve data from multiple peers, it's more likely that the requestor can find one honest peer to report problems with a piece of bad data. - -#### `ActionHash` - -An action is identified by its `ActionHash`. Because an action contains information about its author, the time it was written, the action that preceded it, and the entry it operates on, no two action hashes will be the same --- even for the same entry. This helps to disambiguate identical entries written at different times by different agents. - -#### `EntryHash` - -An entry is identified by its `EntryHash`, which can be retrieved from the `ActionHash` of the action that wrote it. Because they're two separate pieces of data, an entry is stored by different peers than the action that operates on it. - -#### `AgentPubKey` - -**Each agent in a network is identified by their cryptographic public key**, a unique number that's mathematically related to a private number that they hold on their machine. Public-key cryptography is a little complex for this guide --- it's enough to know that a participant's private key signs their source chain actions, and those signatures paired with their public key allow others to verify that they are the one who authored those actions. - -An `AgentPubKey` isn't a hash, but it's the same length, and it's unique just like a hash. So it can be used as a way of referring to an agent, like a user ID --- and this is also why it's used to choose the right peers in the DHT storage and retrieval algorithm. - -#### Summary - -Whereas `EntryHash` is used to uniquely identify, store, and efficiently retrieve an entry from the DHT, `ActionHash` is used to uniquely identify, store, and retrieve the action (metadata) that operated on it, which can provide information about the history and context of any associated entry (including what action preceded it). `ActionHash`es are also what enable any participant to retrieve and reconstruct the continuous sequence of actions (and any associated entries) in another agent's source chain. - -**Use `EntryHash` when** you want to link to or retrieve the actual content or data (e.g., when linking to a category in a forum application). - -**Use `ActionHash` when** you want to link to or retrieve the authorship or history of an entry (e.g., when distinguishing between two posts with identical content). - -**Use `AgentPubKey` when** you want to link to an agent (such as associating a profile or icon with them) or retrieve information about their history (such as scanning their source chain for posts and comments). - -You can check out the Core Concepts to dive a bit deeper into [how the distributed hash table helps](/concepts/4_dht/) to not only make these entries and actions available but helps to ensure that agents haven't gone back to try and change their own histories after the fact. But for now, let's dive into links. - -!!! - -After press Enter, you should see: - -::: output-block -```text -? Should a link from this field be created when this entry is created? (y/n) › -``` -::: - -Press Y to accept creating a link. - -Next you will see: - -::: output-block -```text -✔ Which entry type is this field referring to? -``` -::: - -Press Enter to accept the suggested entry type `Post`. - -Next, you will be asked to pick a field name. You can press Enter to accept the field name suggestion, which should be: - -```text -post_hash -``` - -Press N to decline adding another field to the entry. - -Then use the arrow keys to deselect Update, but leave Delete selected. It should look as follows: - -::: output-block -```text -Which CRUD functions should be scaffolded (SPACE to select/unselect, ENTER to continue)? - Update -✔ Delete -``` -::: - -Once that is done, press Enter to generate a delete function for the **`comment`** entry type. - -You should then see: - -::: output-block -```text -Entry type "comment" scaffolded! - -Add new collections for that entry type with: - - hc scaffold collection -``` -::: - -The scaffolding will now have both added the `comment` entry type, and added a bunch more very useful code to our app using the native Holochain affordance of links. Links allow us to create paths that agents can follow to find associated content. So, the scaffolding not only added a reference to the post in the comment's entry, but it also added code such that when a comment is added, a link from the post back to the comment will also be created. If you want to see some of that code, take a look at the `dnas/forum/zomes/integrity/posts/src/lib.rs` file and you should see right near the top that a function has been created for validating the creation of a `post_to_comments` link. Similarly, other validation functions related to the deletion of those links follow after. - -!!! dig-deeper How links are stored and retrieved in a Holochain app - -What exactly is a link? Where is it stored? How does it work? And what do they let us do that we couldn't do otherwise? - -Links enable us to build a graph of references from one piece of content to other pieces of content in a DHT and then to navigate that graph. This is important because without some sort of trail to follow, it is infeasible to just "search for all content" thanks to the address space (all possible hashes) being so large and spread out across machines that iterating through tme all could take millions of years. - -By linking from known things to unknown things, we enable the efficient discovery and retrieval of related content in our hApp. - -**Storage**: When an agent creates a link between two entries, a `CreateLink` action is written to their source chain. A link is so small that there's no entry for the action. It simply contains the address of the base, the address of the target, the link type (which describes the relationship), and an optional tag which contains a small amount of application-specific information. The base and target can be any sort of DHT address --- an `EntryHash`, an `ActionHash`, or an `AgentPubKey`. But there doesn't actually need to be any data at that base, which is useful for referencing data that exists in another hash-based data store outside the DHT. - -After storing the action in the local source chain, the agent then publishes the link to the DHT, where it goes to the peers who are responsible for storing the base address and gets attached to the address as metadata. - -**Lookup**: To look up and retrieve links in a Holochain app, agents can perform a `get_links` query on a base DHT address. This operation involves asking the DHT peers responsible for that address for any link metadata of a given link type attached to it, with an optional "starts-with" query on the link tag. The peers return a list of links matching the query, which contain the addresses of the targets, and the link types and tags. The agent can then retrieve the actual target data by performing a [`get`](https://docs.rs/hdk/latest/hdk/entry/fn.get.html) query on the target address, which may be an `EntryHash`, `ActionHash`, or `AgentPubKey` (or an empty result, in the case of data that doesn't exist on the DHT). - -For more information and examples, read the Core Concepts section on [Links and Anchors](/concepts/5_links_anchors/). - -!!! - -### 4.7. Scaffold a collection - -Now, let's create a collection that can be used to retrieve all the posts. A collection creates a link type for referring to the collected entry type (similarly to how a link type was created for linking from posts to comments), but collections also create an 'anchor' --- a small string --- as the base for the link so we can find all the items in the collection by starting from the anchor's known hash. - -To create a collection, type: - -```shell -hc scaffold collection -``` - -You should then see: - -::: output-block -```text -Collection name (snake_case, eg. "all_posts"): › -``` -::: - -Enter: - -```text -all_posts -``` - -and press Enter. You should then see: - -::: output-block -```text -? Which type of collection should be scaffolded? › -❯ Global (get all entries of the selected entry types) - By author (get entries of the selected entry types that a given author has created) -``` -::: - -Select **`Global`** and press Enter. You should then see: - -::: output-block -```text -? Which entry type should be collected? › -❯ Post - Comment -``` -::: - -Select **`Post`** and press Enter. You should then see: - -::: output-block -```text -Collection "all_posts" scaffolded! - -At first, the UI for this application is empty. If you want the newly scaffolded collection to be the entry point for its UI, import the element in `ui/src/App.svelte`: - - import AllPosts from './forum/posts/AllPosts.svelte'; - -And use the element in the `<div id="content" />` block by adding in this: - - <div id="content"><</AllPosts></div> -``` -::: - -These instructions tell us that if we want to include this generated UI component in the user interface of our hApp, we need to do some manual work: - - 1. Import the component, and - 2. Tell the UI to display the component. - -!!! dig-deeper How a collection is implemented - -We already explored how links make data in the DHT discoverable by connecting known DHT base addresses to unknown addresses. Essentially every address becomes an anchor point to hang a collection of links from. - -But there's one remaining problem: _where do you start?_ When someone starts their app for the first time, the only DHT base addresses they know about are their public key, the DNA hash, and the few actions and entries on their source chain. There's no obvious way to start discovering other people's data yet. - -This is where **collections** help out. A collection is just a bunch of links on a base address that's easy to find --- typically the address is hard-coded in the coordinator zome's code as the hash of a string such as `"all_posts"`. It's easy to get the links, because their base address is right there in the code. - -This pattern, which we call the "anchor pattern", is so useful that it's built right into Holochain's SDK --- integrity zomes that use it will have all the necessary entry and link types automatically defined, and coordinator zomes that use it will have functions that can retrieve anchors and the links attached to them. The scaffolded code uses this implementation behind the scenes. - -The built-in implementation is actually a simplification of a more general pattern called "paths", which is also built into the SDK. With paths, you can create trees of linked anchors, allowing you to create and query hierarchical structures. This can be used to implement categories, granular collections (for example, "all posts" → "all posts created in 2023" → "all posts created in 2023-05" → "all posts created on 2023-05-30"), and indexes for type-ahead search (for example, "all usernames" → "all usernames starting with 'mat'" → "all usernames starting with 'matt'"). What the SDK calls an `Anchor` is actually a tree with a depth of two, in which the root node is two empty bytes. - -Hierarchical paths serve another useful purpose. On the DHT, where every node is tasked with storing a portion of the whole data set, some anchors could become "hot spots" --- that is, they could have thousands or even millions of links attached to them. The nodes responsible for storing those links would bear a disproportionate data storage and serving burden. - -The examples of granular collections and type-ahead search indexes breaks up those anchors into increasingly smaller branches, so that each leaf node in the tree --- and hence each peer --- only has to store a small number of links. - -The scaffolding tool doesn't have any feature for building anchors and trees beyond simple one-anchor collections, but if you'd like to know more, you can read the Core Concepts section on [Links and Anchors](/concepts/5_links_anchors/) and the SDK reference for [`hash_path`](https://docs.rs/hdk/latest/hdk/hash_path/index.html) and [`anchor`](https://docs.rs/hdk/latest/hdk/hash_path/anchor/index.html). - -!!! - -Before you get started editing the UI, it's helpful to be able to actually run the scaffolded applciation. That way, you can watch changes take effect in real-time as you make them. So the next section will walk you through launching the application the tooling that's available there, and then in the section after that, we'll begin working with the `.svelte` files to build the UI. - -### 4.8. Run your application in dev mode - -At this stage, we'll incorporate some of the UI components that have been scaffolded by the scaffolding tool into our main application interface. Our aim here is to make all the functionality of our forum application accessible from a single, unified interface. We'll use Svelte to accomplish this, as it is the framework that we have chosen for the UI layer of our application. - -Start the forum hApp in develop mode from the command line: go to your terminal and, from the root folder (`my_forum_app/`), enter: - -```shell -npm start -``` - -!!! info Work in the nix shell -If you are having an issue, make sure that you are still in the nix shell. If not, re-enter `nix develop` first, then type the above command again. And remember that you can always exit nix shell by typing `exit` to get back to your normal shell. -!!! - -When you start the hApp with `npm start`, this launches Holochain in sandbox mode with two agents running that hApp, and opens three windows: - -1. A web browser window with Holochain Playground, a tool that makes visible the various actions that have taken place in our forum hApp. You should be able to see a couple of agents in a DHT, with mostly empty source chains and, correspondingly, a mostly empty graph. -2. An application window with one agent (conductor 0) running the forum hApp. This window lets us take actions as that agent (0, or Alice, if you prefer). -3. Another application window with a second agent (conductor 1) running the forum hApp. This window lets us take actions as the other agent (1, or Bob). - -![Three windows: two agent UIs and a web browser window with the Holochain Playground](/assets/img/get-started/3-two-uis-and-playground.png) - -These application windows allow us to test multiple agents in a Holochain network interacting with one another. It is all running on our one device, but the two conductors behave very much the same as separate agents on different machines would, minus network lag. - -Remember that a **conductor** is a Holochain runtime process executing on your computer. For more details see the [Application Architecture](/concepts/2_application_architecture/) section in the Core Concepts guide. - -These three windows together will let us interact with our hApp as we are building it. - -The Holochain Playground in particular is helpful because it creates visual representations of the data that has been created and the way it relates to other content. Take a look at it and click one of the two items in the **DHT Cells** window. These are your two agents. When you click one of them, some content gets displayed in the **Source Chain** window. These are the initial actions in that agent's source chain. The arrows point from newer content back to older content. - -From oldest to newest, in the newly created source chains, the records are: - -1. `DNA`, recording the hash of the DNA to be used to validate all subsequent source chain actions, -2. `AgentValidationPkg`, providing proof that this participant is allowed to participate in this hApp ([see more](https://www.holochain.org/how-does-it-work/) in Holochain: How does it work?), -3. A `Create` action which records the author's `AgentID`, which is their public key and serves as their ID in the network and its graph database. - -As agents begin writing posts, comments, and links to the DHT, you'll see the following records appear: - -4. `InitComplete`, indicating that all coordinator zomes have had a chance to do initial setup, then -5. Whatever actions the agent takes after that. - -The two application UI windows let you interact with the application and see what is working, what is not working, and how data propagates when we take particular actions. - -At first, each of the UI windows (conductors 0 for Alice and 1 for Bob) include instructions for you to go and examine the scaffolded UI elements by looking at the contents in the folder `ui/src///`, where `` and `` are generic placeholders for your DNA (`forum`) and zome (`post`). - -### 4.9. Integrate the generated UI elements - -Thus far, seven different UI components should have been generated as `.svelte` files in the `ui/src/forum/posts/` folder. Note that for ease of development, the sandbox testing environment live-reloads the UI as you edit UI files. So don't quit the process you started with `npm start`; instead, **open a new terminal window**. Then navigate to the root folder of your hApp (`my_forum_app/`) and list the files in `ui/src/forum/posts/` by entering: - -```shell -ls ui/src/forum/posts/ -``` - -You should see seven different `.svelte` files, plus a `types.ts` file: - -::: output-block -```text -AllPosts.svelte CreateComment.svelte PostDetail.svelte -CommentDetail.svelte CreatePost.svelte types.ts -CommentsForPost.svelte EditPost.svelte -``` -::: - -The next step is to edit the UI files in the text editor or integrated development environment of your choice to add scaffolded components and build a fully featured UI. To integrate all of these generated UI elements, you'll need to add them to `App.svelte` file located in the `ui/src/` folder, or to some other `.svelte` file that eventually gets included in `App.svelte`. - -If you don't yet have path commands for opening files in your prefered IDE, there are instructions for [VSCode/VSCodium](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line), [Sublime Text](https://www.sublimetext.com/docs/command_line.html#setup) and [WebStorm](https://www.jetbrains.com/help/webstorm/working-with-the-ide-features-from-command-line.html#5d6e8844). Going forward in this tutorial, we are going to use the `code` command when we mean for you to open files in your IDE, but you should substitute a different command (ex: `subl`, `vim`, `emacs` etc.) for `code` if you are using a different editor. - -Open the `App.svelte` file with your preferred IDE. - -```shell -code ui/src/App.svelte -``` - -Your `App.svelte` file will have three sections: - -1. a script section, -2. a main section containing a markup template, and -3. a style section containing a stylesheet template. - -!!! dig-deeper Detailed breakdown of `App.svelte` - -#### ` -``` - -This section contains the JavaScript/TypeScript code for the component. It imports various dependencies needed to build a single-page web app: - -* `svelte` is the Svelte engine itself, and its `onMount` function lets you register a handler to be run when the component is initialized, while `setContext` lets you pass data to be used in the rendering of the component. -* `@holochain/client` is the Holochain client library; first we load in some useful Holochain-related TypeScript types, followed by the client object itself. -* `@mwc/material-circular-progress` is just a UI component that gives us a spinner when something is loading. -* `./contexts` is generated by the scaffolding tool. It just contains a constant, the app-wide name for the 'context' that makes the Holochain client accessible to all components. In Svelte, a context is a state shared across components. - -After importing dependencies, it does some initial setup. This is run when the component file is imported --- in this case the component, `App.svelte`, is the main component for the entire application, and it's imported into `main.ts` where it's 'mounted' (more on mounting in a moment). - -Next some variables are instantiated: one to hold the Holochain client that connects to the hApp backend via the conductor, and one to keep track of whether the client is connected yet. (This variable will be used to show a loading spinner while it's still connecting.) - -**Take note of the line that starts with `$:`**. This is a special Svelte label that turns regular variables into **reactive variables**. We won't get too deep into Svelte right now, because this is a tutorial about Holochain, but when a reactive variable changes, Svelte will re-render the entire component. This lets you write a template declaratively, enclosing the reactive variable in `{}` braces, and let Svelte handle the updating of the template wherever the variable changes. - -Finally, there's an `onMount` handler, which is run when the component is first displayed. The handler currently does one thing: it connects to the hApp backend via the conductor, waits until the connection is establised, sets `loading` to false, and adds the resulting client connection to the context so that all components can access it. - -#### `
` section - -```svelte -
- {#if loading} -
- -
- {:else} -
-

EDIT ME! Add the components of your app here.

- - Look in the ui/src/DNA/ZOME folders for UI elements that are generated with hc scaffold entry-type, hc scaffold collection and hc scaffold link-type and add them here as appropriate. - - For example, if you have scaffolded a "todos" dna, a "todos" zome, a "todo_item" entry type, and a collection called "all_todos", you might want to add an element here to create and list your todo items, with the generated ui/src/todos/todos/AllTodos.svelte and ui/src/todos/todos/CreateTodo.svelte elements. - - So, to use those elements here: -
    -
  1. Import the elements with: -
    -import AllTodos from './todos/todos/AllTodos.svelte';
    -import CreateTodo from './todos/todos/CreateTodo.svelte';
    -        
    -
  2. -
  3. Replace this "EDIT ME!" section with <CreateTodo></CreateTodo><AllTodos></AllTodos>.
  4. -
-
- {/if} -
-``` - -This section is a template for the displayable content of the main app component. Using an `{#if}` block to test whether the reactive variable `loading` is true, this section displays a spinner until the backend can be accessed. Once the UI is connected to the backend, it shows some boilerplate text telling you to add something meaningful to the template. - -#### ` -``` - -This section is a template for the CSS styles that get applied to the HTML in the `
` section of the component. You can also use reactive variables here, and the styling will update whenever the variables change. These scaffolded styles set the component up with some basic layout to make it readable at small and large window sizes. - -**All Svelte components follow this general pattern**. `App.svelte` has special status as the root component, but otherwise it's just like any other component. - -!!! - -First you'll be adding a list of posts to the app, which means the components called `AllPosts.svelte` needs to be imported. - -At the top of the file, there is a list of scripts that are imported. Following the instructions that the scaffolding tool and the two conductor windows gave you, copy the following text and paste it into the script block of the `App.svelte` file, on the line below `import { clientContext } from './contexts';` - -```typescript -import AllPosts from './forum/posts/AllPosts.svelte'; -``` - -Next, add the component to the markup template in the `
` section of the file, where the "EDIT ME!" content now lives. Remove everything inside the `div` element that starts with this tag: - -:::output-block -```svelte -
-``` -::: - -and replace it with this line: - -```svelte - -``` - -Your `
` block should now look like this: - -```svelte -
- {#if loading} -
- -
- {:else} -
- -
- {/if} -
-``` - -!!! info Svelte component tags -The `AllPosts` element is obviously not standard HTML. In Svelte, each component has a correspondingly named custom element that will get replaced by the rendered component's markup wherever it appears in another component's template. -!!! - -Save that file and take a look again at the two UI windows. They should both say 'No posts found'. - -![A UI showing the AllPosts component, which says 'No posts found'](/assets/img/get-started/4-no-posts-found.png) - -Let's fix that by adding the post creation component to the UI so we can add our first post. Import the `CreatePost.svelte` component by adding this line in the script section, just below the `AllPosts` component you previously imported: - -```typescript -import CreatePost from './forum/posts/CreatePost.svelte'; -``` - -Add this new component to the `
` block above the component you added: - -```svelte - -``` - -Now your `
` block should look like this: - -```svelte -
- {#if loading} -
- -
- {:else} -
- - -
- {/if} -
-``` - -Save the file and switch to one of the two conductor windows. You should now see a post form. - -![The UI after adding the CreatePost component](/assets/img/get-started/5-create-post-component.png) - -Type something into one of the two conductor windows like: - -* Title: `Hi from Alice` -* Content: `Hello Bob!` - -and then press the "Create Post" button. - -You'll immediately notice that the `AllPosts` component has changed from saying "No posts found" to showing the newly created post. And if you take a look at the Holochain Playground window, you will see that two new actions have been created. If you click the `App` element that's appeared in Alice's source chain, it will pull up some details in the Entry Contents section, including the title and content of Alice's forum post. Note the hash of that entry (top of the Entry Contents window). Then click on the `Create` action that's pointing toward that `App` entry in the source chain. If you look back at the contents window, you will see that it is now sharing the contents of the action. And if you look down the list a bit, you will see the hash of the entry for the first post. - -![The Holochain playground showing a single agent's source chain, containing the actions that create a post, as well as the transformations in the DHT that resulted from these actions](/assets/img/get-started/6-playground-first-post.png) - -!!! dig-deeper Relationships in a source chain versus relationships in the DHT - -At this point, in our DHT graph it should look like we have two different agents and then a separate floating entry and action. But we know that the new post is associated with a source chain which is associated with an agent. So why aren't they connected on the DHT? - -A source chain merely serves as a history of one agent's attempts to manipulate the state of the graph database contained in the DHT. It's useful to think of the DHT as a completely separate data store that doesn't necessarily reflect agent-to-entry relationships unless you explicitly create a link type for them. - -For the purpose of this hApp, we're not interested in agent-to-posts relationships, so it's fine that they're not linked. But if you wanted to create a page that showed all posts by an author, that's when you might want to scaffold that link type. `hc scaffold collection` will do this for you if you choose a by-author collection, and will also create a `get_posts_by_author` function. - -!!! - -You may also notice that only Alice's UI showed the new post, while Bob's didn't. Just as with a traditional web app, database changes don't automatically send out a notification to everyone who is interested. (Alice's UI sees the changes because it knows how to update its own state for local changes.) You can create this functionality using a feature called [signals](/concepts/9_signals/), but let's keep things simple for now. Right-click anywhere in Bob's UI then choose "Reload" from the menu, and you'll see that the changes have been copied from Alice's app instance to Bob's --- all without a database server in the middle! - -Let's edit that post. In Alice's UI window, click the edit adjacent to the post content (it should look like a pencil icon). The post content will be replaced by an editing form. - -Now alter the content a bit. Maybe change it from `Hello Bob!` to `Hello, World!` and click "Save". - -![The UI of one agent, showing a post about to be edited](/assets/img/get-started/7-edit-post.png) - -That should update the post (at least for Alice). Bob's UI will show the updated version the next time it's reloaded. - -If you look at the Holochain Playground, you should see that the update was added to Alice's source chain. Specifically, it created: - -1. a new entry (with our `Hello, World!` text), -2. an `Update` action that indicated this entry is to replace the original entry, and -3. a `CreateLink` action that connects the original create action to the update action. - -![The Holochain playground, showing the source chain of the agent who edited the post along with new data in the DHT reflecting the edit](/assets/img/get-started/8-playground-after-edits.png) - -As explained [previously](#crud-create-read-update-delete), the original forum post already has a 'link' of sorts pointing from its action to the `Update` action, which can be accessed when the original is retrieved. The extra link created by the `CreateLink` action is optional --- it merely speeds up retrieval when an action has been edited many times and has a long chain of update links, by allowing you to jump to the end of the chain. In the screenshot above, the link is highlighted in the DHT pane. - -Now it's time to add commenting to your app. - -Previously, you added new components to the `App.svelte` component. That made sense because posts were a global data type. But comments are related to a post, so from now on you'll be modifying the `PostDetail.svelte` component instead. - -Open up `PostDetail.svelte` in your IDE: - -```shell -code ui/src/forum/posts/PostDetail.svelte -``` - -Just as before, first you'll need to import the components near the top of the file (just after the line that imports `EditPost.svelte`): - -```typescript -import CreateComment from './CreateComment.svelte'; -import CommentsForPost from './CommentsForPost.svelte'; -``` - -Further down the file, in the template block, add the components' elements to the template. Put them both before the closing `
` tag. - -Here, the comment components need to know what post they're related to. The post hash is the unique ID for the post, and the comment components' elements both expect a `postHash` attribute. This hash is available in the `PostDetail` component as a variable of the same name, so it can be passed to the comment widgets. - -```svelte - - -``` - -Save the file, then go back to the UI windows to see the changes. Try typing in a comment or two, then deleting them. (You may need to refresh the UI windows to see the changes to the content.) Watch the Playground --- see how the authors' source chains and the graph in the DHT change as new information is added. The deleted comments are still there and can be accessed by code in your zomes if needed, but neither the application backend (that is, the functions defined in the coordinator zome) nor the UI have the capacity to show them. - -![One UI window with the comment components added, with the Playground in the background showing a populated DHT](/assets/img/get-started/10-comment-components.png) - -## 5. Deploying your Holochain application - -### 5.1 Packaging - -Now that you've built an application, it's time to get it into other people's hands. You specify the components of a hApp using manifest files, written in [YAML](https://yaml.org/), and the `hc` CLI looks for them when it's building a distributable hApp for you. If you look in the `workdir` folder: - -```shell -ls workdir -``` - -You'll see that the scaffolding tool has generated two manifest files for you: - -:::output-block -```text -happ.yaml web-happ.yaml -``` -::: output-block - -The first step is to package your app: - -```shell -npm run package -``` - -This command does a number of things: - -1. Triggers the Rust compiler to build the zomes, -2. Uses the `hc` CLI too to combine the built zomes and the DNA manifest into a `.dna` file, -3. Combines all the DNAs and the hApp manifest into a `.happ` file, -3. Builds the UI and compresses it into a `.zip` file, and -4. Combines the hApp file, the UI zip, and the web hApp manifest into a `.webhapp` file. - -Of course, this application only has one zome and one DNA, but more complex apps may have many of each. - -Now you'll see some new files in `workdir`: - -```shell -ls workdir -``` - -::: output-block -```text -happ.yaml my_forum_app.happ my_forum_app.webhapp web-happ.yaml -``` -::: output-block - -The packed app is now ready for deployment to a Holochain runtime. - -### 5.2 Runtimes - -In the centralized world, deployment is usually achieved by Continuous Integration (CI) automation that builds up code changes and sends them to whatever server or cloud-based platform you're using. In the decentralized world of Holochain, deployment happens when end-users download and run your hApp in the Holochain runtime. - -From the end-user perspective there are currently there are two ways to go about this, both of which will feel familiar: - -1. Download Holochain's official Launcher runtime and install the app from its app store or the filesystem. -2. Download an your app as its own standalone desktop executable, as they would any other application for their computer. - -#### 5.2.1 Launcher, the multi-app runtime - -Holochain's official end-user runtime is the [Holochain Launcher](https://github.com/holochain/launcher). It allows people to install apps from a built-in app store or from the filesystem. Installed apps can then be launched from a friendly UI. Note that the app store is itself a distributed Holochain application which provides details on applications that are available for download. As a developer you can either go through a simple publishing process and add your app to the app store where it will be available for installation by all people who use the Launcher, or you can share your application directly with end-users through your own channels and they can install it into their Holochain Launcher manually from the file system. - -You can try this latter approach immediately by downloading and running the Launcher! - -The steps for publishing an app to the Launcher's app store are documented in the Github repository of the Holochain Launcher [here](https://github.com/holochain/launcher#publishing-and-updating-an-app-in-the-devhub). - -#### 5.2.2 Standalone executable - -If you prefer to distribute your app as a full standalone executable, you will need to bundle the Holochain runtime and your app together and take care of the necessary interactions between them. Because Holochain itself is really just a set of Rust libraries, you can of course build your own application that uses those libraries, but that's a fair amount of work. Currently there are two much simpler paths for doing this: using either the [Electron](https://www.electronjs.org/) or [Tauri](https://tauri.app/) frameworks, both of which can generate cross-platform executables from standard web UIs. These frameworks also support inclusion of additional binaries, which in our case are the [holochain conductor](https://docs.rs/holochain/latest/holochain/) and the [lair keystore](https://docs.rs/lair_keystore/latest/lair_keystore/). Though there is quite a bit of complexity in setting things up for these frameworks, all the hard work has already been done for you: - -* **Electron**: Refer to the community-supported [electron-holochain-template](https://github.com/lightningrodlabs/electron-holochain-template/) repo. -* **Tauri**: See the officially supported [holochain-kanagroo](https://github.com/holochain-apps/holochain-kangaroo) repo. - -Both of these are GitHub template repos with detailed instructions on how to clone the repos and add in your UI and DNA, as well as build and release commands that will create the cross-platform executables that you can then deliver to your end users. - -!!! note Code Signing -For macOS and Windows, you will probably also want to go through the process of registering as a developer so that your application can be "code-signed". This is needed so that users don't get the "unsigned code" warnings when launching the applications on those platforms. Both of the above templates include instructions for CI automation to run the code-signing steps on release once you have acquired the necessary certificates. -!!! - - - - - - -## 6. Next steps - -Congratulations! You've learned how to create a new Holochain application, understand its layout, work with core concepts, and deploy and test the application. - -Now that you have a basic understanding of Holochain development, you can continue exploring more advanced topics, such as: - -* Validating data -* Writing tests for a zome -* Implementing access and write privileges -* Building more complex data structures and relationships -* Optimizing your application for performance and scalability - -### 6.1 Further exploration and resources - -Now that you have successfully built a basic forum application using Holochain and integrated it with a frontend, you may want to explore more advanced topics and techniques to further enhance your application or create new ones. Here are some resources and ideas to help you get started: - -#### Holochain developer documentation - -The official Holochain developer documentation is a valuable resource for deepening your understanding of Holochain concepts, techniques, and best practices. Be sure to explore the documentation thoroughly: - -* [Holochain Core Concepts](/concepts/1_the_basics/) -* [Holochain Developer Kit (HDK) reference](https://docs.rs/hdk/latest/hdk) - -#### Community resources - -The Holochain community is an excellent source of support, inspiration, and collaboration. Consider engaging with the community to further your learning and development: - -* [Holochain GitHub repositories](https://github.com/holochain) -* [Holochain Discord server](https://discord.com/invite/k55DS5dmPH) - -#### Example applications and tutorials - -Studying existing Holochain applications and tutorials can provide valuable insights and inspiration for your projects. Here are some resources to explore: - -* [Holochain Open Dev](https://github.com/holochain-open-dev) -* [Holochain Foundation sample apps](https://github.com/holochain-apps) +[Try 'Hello World' →](../2-hello-world/){.btn-purple} \ No newline at end of file From dcac146893f3a9a660200b64a6cb6c7fc8ae40a4 Mon Sep 17 00:00:00 2001 From: Paul d'Aoust Date: Mon, 11 Mar 2024 14:08:26 -0700 Subject: [PATCH 14/19] fix spelling mistakes --- src/pages/get-started/2-hello-world.md | 2 +- src/pages/get-started/3-forum-app-tutorial.md | 18 ++++++++---------- .../4-packaging-and-distribution.md | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/pages/get-started/2-hello-world.md b/src/pages/get-started/2-hello-world.md index ef9f72671..f82ae2def 100644 --- a/src/pages/get-started/2-hello-world.md +++ b/src/pages/get-started/2-hello-world.md @@ -87,7 +87,7 @@ This table includes everything in the `hello-world/` folder as well as details o |
 ├── target/              
| A folder containing the compiled output from the Rust build process. | |
 ├── tests/               
| A folder containing JavaScript-base test code for the application. | |
 ├── ui/                  
| A folder containing the source code and assets for the web-based user interface of the "Hello, World!" application. This user interface will get distributed along with the application. | -|
 ├┬─ workdir/             
| A working folder containing configuration files and compliled artifacts related to the building of the whole hApp. | +|
 ├┬─ workdir/             
| A working folder containing configuration files and compiled artifacts related to the building of the whole hApp. | |
 │├── happ.yaml           
| The manifest file for the hApp. It references the DNA files to be included, along with the roles they play in the application. In this case, there's only one DNA file, `hello_world`. | |
 │├── hello_world.happ    
| The compiled hApp bundle, which includes all the DNAs (in case just the one). | |
 │├── hello_world.webhapp 
| The compiled web hApp bundle, which includes the hApp bundle plus the zipped UI. | diff --git a/src/pages/get-started/3-forum-app-tutorial.md b/src/pages/get-started/3-forum-app-tutorial.md index c43dc272d..316d4e239 100644 --- a/src/pages/get-started/3-forum-app-tutorial.md +++ b/src/pages/get-started/3-forum-app-tutorial.md @@ -15,7 +15,7 @@ tocData: href: 6-scaffold-entry-types - text: 7. Scaffold a collection href: 7-scaffold-a-collection - - text: 8. Run your applicaiton in dev mode + - text: 8. Run your application in dev mode href: 8-run-your-application-in-dev-mode - text: 9. Integrate the generated UI elements href: 9-integrate-the-generated-ui-elements @@ -191,7 +191,7 @@ A DNA folder is where you will put the code that defines the rules of your appli ### Why do we use the term DNA? -In Holochain, we are trying to enable people to **choose to participate in coherent social coordination**, or interact meaningfully with each other online without needing a central authority to define the rules and keep everyone safe. To do that, we are borrowing some patterns from how biological organisms are able to coordinate coherently even at scales that social organisations such as companies or nations have come nowhere close to. In living creatures like humans, dolphins, redwood trees, and coral reefs, many of the cells in the body of an organism (trillions of the cells in a human body, for instance) are each running a (roughly) identical copy of a rule set in the form of DNA. +In Holochain, we are trying to enable people to **choose to participate in coherent social coordination**, or interact meaningfully with each other online without needing a central authority to define the rules and keep everyone safe. To do that, we are borrowing some patterns from how biological organisms are able to coordinate coherently even at scales that social organizations such as companies or nations have come nowhere close to. In living creatures like humans, dolphins, redwood trees, and coral reefs, many of the cells in the body of an organism (trillions of the cells in a human body, for instance) are each running a (roughly) identical copy of a rule set in the form of DNA. This enables many different independent parts (cells) to build relatively consistent superstructures (a body, for instance), move resources, identify and eliminate infections, and more --- all without centralized command and control. There is no "CEO" cell in the body telling everybody else what to do. It's a bunch of independent actors (cells) playing by a consistent set of rules (the DNA) coordinating in effective and resilient ways. @@ -369,7 +369,7 @@ There are a few different kinds of actions, but the most common one is `Create`, Every action contains the ID of its author (actually a cryptographic public key), a timestamp, a pointer to the previous source chain record, and a pointer to the entry data, if there is any. In this way, actions provide historical context and provenance for the entries they operate on. -The pointer to the previous source chain record creates an unbroken history from the current record all the way back to the source chain's starting point. This 'genesis' record contains the hash of the DNA, which servs as both the identifier for the specific set of validation rules that all following records should follow and the ID of the network that this source chain's actions are participating in. +The pointer to the previous source chain record creates an unbroken history from the current record all the way back to the source chain's starting point. This 'genesis' record contains the hash of the DNA, which serves as both the identifier for the specific set of validation rules that all following records should follow and the ID of the network that this source chain's actions are participating in. An action is cryptographically signed by its author and is immutable (can't be changed or erased from either the source chain or the network's data store) once written. This, along with the validation rules specified by the DNA hash in the genesis record, are examples of a concept we call "intrinsic data integrity", in which data carries enough information about itself to be self-validating. @@ -791,7 +791,7 @@ The scaffolding tool doesn't have any feature for building anchors and trees bey !!! -Before you get started editing the UI, it's helpful to be able to actually run the scaffolded applciation. That way, you can watch changes take effect in real-time as you make them. So the next section will walk you through launching the application the tooling that's available there, and then in the section after that, we'll begin working with the `.svelte` files to build the UI. +Before you get started editing the UI, it's helpful to be able to actually run the scaffolded application. That way, you can watch changes take effect in real-time as you make them. So the next section will walk you through launching the application the tooling that's available there, and then in the section after that, we'll begin working with the `.svelte` files to build the UI. ## 8. Run your application in dev mode @@ -858,7 +858,7 @@ CommentsForPost.svelte EditPost.svelte The next step is to edit the UI files in the text editor or integrated development environment of your choice to add scaffolded components and build a fully featured UI. To integrate all of these generated UI elements, you'll need to add them to `App.svelte` file located in the `ui/src/` folder, or to some other `.svelte` file that eventually gets included in `App.svelte`. -If you don't yet have path commands for opening files in your prefered IDE, there are instructions for [VSCode/VSCodium](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line), [Sublime Text](https://www.sublimetext.com/docs/command_line.html#setup) and [WebStorm](https://www.jetbrains.com/help/webstorm/working-with-the-ide-features-from-command-line.html#5d6e8844). Going forward in this tutorial, we are going to use the `code` command when we mean for you to open files in your IDE, but you should substitute a different command (ex: `subl`, `vim`, `emacs` etc.) for `code` if you are using a different editor. +If you don't yet have path commands for opening files in your preferred IDE, there are instructions for [VSCode/VSCodium](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line), [Sublime Text](https://www.sublimetext.com/docs/command_line.html#setup) and [WebStorm](https://www.jetbrains.com/help/webstorm/working-with-the-ide-features-from-command-line.html#5d6e8844). Going forward in this tutorial, we are going to use the `code` command when we mean for you to open files in your IDE, but you should substitute a different command (ex: `subl`, `vim`, `emacs` etc.) for `code` if you are using a different editor. Open the `App.svelte` file with your preferred IDE. @@ -915,7 +915,7 @@ Next some variables are instantiated: one to hold the Holochain client that conn **Take note of the line that starts with `$:`**. This is a special Svelte label that turns regular variables into **reactive variables**. We won't get too deep into Svelte right now, because this is a tutorial about Holochain, but when a reactive variable changes, Svelte will re-render the entire component. This lets you write a template declaratively, enclosing the reactive variable in `{}` braces, and let Svelte handle the updating of the template wherever the variable changes. -Finally, there's an `onMount` handler, which is run when the component is first displayed. The handler currently does one thing: it connects to the hApp backend via the conductor, waits until the connection is establised, sets `loading` to false, and adds the resulting client connection to the context so that all components can access it. +Finally, there's an `onMount` handler, which is run when the component is first displayed. The handler currently does one thing: it connects to the hApp backend via the conductor, waits until the connection is established, sets `loading` to false, and adds the resulting client connection to the context so that all components can access it. ### `
` section @@ -1002,8 +1002,7 @@ Your `
` block should now look like this: ```svelte
{#if loading} -
+
{:else} @@ -1039,8 +1038,7 @@ Now your `
` block should look like this: ```svelte
{#if loading} -
+
{:else} diff --git a/src/pages/get-started/4-packaging-and-distribution.md b/src/pages/get-started/4-packaging-and-distribution.md index 6eeba3cb6..680248fef 100644 --- a/src/pages/get-started/4-packaging-and-distribution.md +++ b/src/pages/get-started/4-packaging-and-distribution.md @@ -84,7 +84,7 @@ The steps for publishing an app to the Launcher's app store are documented in th If you prefer to distribute your app as a full standalone executable, you will need to bundle the Holochain runtime and your app together and take care of the necessary interactions between them. Because Holochain itself is really just a set of Rust libraries, you can of course build your own application that uses those libraries, but that's a fair amount of work. Currently there are two much simpler paths for doing this: using either the [Electron](https://www.electronjs.org/) or [Tauri](https://tauri.app/) frameworks, both of which can generate cross-platform executables from standard web UIs. These frameworks also support inclusion of additional binaries, which in our case are the [holochain conductor](https://docs.rs/holochain/latest/holochain/) and the [lair keystore](https://docs.rs/lair_keystore/latest/lair_keystore/). Though there is quite a bit of complexity in setting things up for these frameworks, all the hard work has already been done for you: * **Electron**: Refer to the community-supported [electron-holochain-template](https://github.com/lightningrodlabs/electron-holochain-template/) repo. -* **Tauri**: See the officially supported [holochain-kanagroo](https://github.com/holochain-apps/holochain-kangaroo) repo. +* **Tauri**: See the officially supported [holochain-kangaroo](https://github.com/holochain-apps/holochain-kangaroo) repo. Both of these are GitHub template repos with detailed instructions on how to clone the repos and add in your UI and DNA, as well as build and release commands that will create the cross-platform executables that you can then deliver to your end users. From 593175fc05dab63e94165001764e1226d7c0a315 Mon Sep 17 00:00:00 2001 From: Paul d'Aoust Date: Mon, 11 Mar 2024 14:11:49 -0700 Subject: [PATCH 15/19] fix get started sequence links --- src/pages/get-started/2-hello-world.md | 2 +- src/pages/get-started/3-forum-app-tutorial.md | 2 +- src/pages/get-started/index.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/get-started/2-hello-world.md b/src/pages/get-started/2-hello-world.md index f82ae2def..bbc869b9b 100644 --- a/src/pages/get-started/2-hello-world.md +++ b/src/pages/get-started/2-hello-world.md @@ -108,4 +108,4 @@ These files and folders make up the structure of a Holochain application, with t Now it's time to try scaffolding your own application. Follow the instructions in the next guide to learn how to generate back-end and UI code. -[Forum app tutorial →](../3-forum-app-tutorial/){.btn-purple} \ No newline at end of file +[Forum app tutorial →](/get-started/3-forum-app-tutorial/){.btn-purple} \ No newline at end of file diff --git a/src/pages/get-started/3-forum-app-tutorial.md b/src/pages/get-started/3-forum-app-tutorial.md index 316d4e239..5fef34a8c 100644 --- a/src/pages/get-started/3-forum-app-tutorial.md +++ b/src/pages/get-started/3-forum-app-tutorial.md @@ -1129,4 +1129,4 @@ Save the file, then go back to the UI windows to see the changes. Try typing in Now that you've built a hApp, you can learn how to package it for distribution to your users. -[Package your hApp →](../4-packaging-and-distribution/){.btn-purple} \ No newline at end of file +[Package your hApp →](/get-started/4-packaging-and-distribution/){.btn-purple} \ No newline at end of file diff --git a/src/pages/get-started/index.md b/src/pages/get-started/index.md index 9dc3f9308..4ad25803b 100644 --- a/src/pages/get-started/index.md +++ b/src/pages/get-started/index.md @@ -89,4 +89,4 @@ Congratulations! The Holochain development environment is now set up successfull Now it's time to download, compile, and try an example Holochain application. -[Try 'Hello World' →](../2-hello-world/){.btn-purple} \ No newline at end of file +[Try 'Hello World' →](/get-started/2-hello-world/){.btn-purple} \ No newline at end of file From d179b8df6b8c34ad38c6877274c49d0f82aa39c3 Mon Sep 17 00:00:00 2001 From: Paul d'Aoust Date: Tue, 12 Mar 2024 14:28:04 -0700 Subject: [PATCH 16/19] proofreading sweep on broken-up getting started guide --- src/pages/get-started/2-hello-world.md | 43 ++++------ src/pages/get-started/3-forum-app-tutorial.md | 86 +++++++++---------- .../4-packaging-and-distribution.md | 20 ++--- src/pages/get-started/index.md | 18 ++-- 4 files changed, 82 insertions(+), 85 deletions(-) diff --git a/src/pages/get-started/2-hello-world.md b/src/pages/get-started/2-hello-world.md index bbc869b9b..8a5e8ea04 100644 --- a/src/pages/get-started/2-hello-world.md +++ b/src/pages/get-started/2-hello-world.md @@ -2,29 +2,24 @@ title: "Scaffold a Simple Hello World Application" --- -In this section, we’ll use Holochain’s scaffolding tool to generate a simple “Hello, World!” application. +In this section, we’ll use Holochain’s scaffolding tool to generate a simple “Hello World!” application. For this tutorial, we'll be working in `~/Holochain`. Create that folder now and move into it: ```shell mkdir ~/Holochain ``` - ```shell cd ~/Holochain ``` -## Scaffold a simple "Hello, World!" app - -In this section, we'll use Holochain's scaffolding tool to generate a simple "Hello, World!" application. - -When getting started, seeing a simple but fully-functional app can be very helpful. You can have Holochain's scaffolding tool generate a "Hello, World!" application (but for a distributed multi-agent world) by typing the following in your command line terminal: +When getting started, seeing a simple but fully-functional app can be very helpful. You can have Holochain's scaffolding tool generate a "Hello World!" application (but for a distributed multi-agent world) by typing the following in your command line terminal: ```shell nix run github:holochain/holochain#hc-scaffold -- example hello-world ``` -The scaffolding tool should print out these four commands for you to run in order to run the app. Copy them from your terminal or from below: +The scaffolding tool should print out these four commands for you to run in order to compile and run the app. Copy them from your terminal or from below: ```shell cd hello-world @@ -43,18 +38,18 @@ After you run the last of these commands, you should see three windows open: ![A screenshot showing two hApp windows in front of the Playground](/assets/img/get-started/1-running-app-first-look.png) -* A web browser window with the Holochain Playground, which displays a visual representation of the app's state data -* Two windows showing the UI for two agents, both of which will have published a `Hello World` entry to the network. +* A web browser window with the Holochain Playground, which displays a visual representation of the app's state data across all the peers +* Two windows showing the UI for two agents, both of which will have published a `hello` entry to the network -When you click on the "Look for Hellos" button, you should be able to see the hellos: +The first thing the app does upon initialization is create a `hello` entry and store it to the shared application state (this is called the application's [DHT](/concepts/4_dht/)). Remember that, because each participant runs the app on their device, a greeting will be stored for each person. When you click on the "Look for Hellos" button, you should be able to see a greeting from both participants: ![A screenshot showing one app window, with hello messages in different languages retrieved from the DHT](/assets/img/get-started/2-look-for-hellos.png) -When you are done checking out this app, you can go back to the terminal and stop both agents by pressing Ctrl+C (Linux) or Cmd+C (macOS). +When you're done checking out this app, you can go back to the terminal and stop both agents by pressing Ctrl+C (Linux) or Cmd+C (macOS). !!! dig-deeper Understanding the layout of a scaffolded project -Let's explore the different files and folders that make up the structure of the "Hello, World!" hApp that you just created. +Let's explore the different files and folders that make up the structure of the "Hello World!" hApp that you just created. List the folders and files in our `hello-world/` folder by entering: @@ -68,12 +63,12 @@ This table includes everything in the `hello-world/` folder as well as details o |---------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |
 ├── hello-world/         
| Root folder of the application. All other files and folders will reside here. | |
 ├┬─ dnas/                
| This folder contains the DNA configuration and source code for the application. DNAs are one of the most important building blocks in Holochain. Simply put, **a DNA is the executable code for the game you are playing with your peers in Holochain.** And here is the twist: in Holochain, **every DNA creates its own peer-to-peer network** for the validation, storage, and serving of content. Every Holochain application contains at least one DNA. In this example hApp, we have just one: `hello_world`. | -|
 │└┬─ hello_world/        
| Folder for the `hello_world` DNA. It contains modules (zomes) that define the rules and API of this application. | -|
 │ ├┬─ workdir/           
| A working folder containing configuration files and compiled artifacts related to the DNA. | +|
 │└┬─ hello_world/        
| Folder for the `hello_world` DNA. It contains the source code and other artifacts for the modules of the DNA (zomes) that define the rules and API of this application. | +|
 │ ├┬─ workdir/           
| A working folder containing a bundle manifest for the DNA, as well as the bundled DNA file once it's been built. | |
 │ │├── dna.yaml          
| DNA manifest file. A YAML file that defines the properties and zomes of the DNA. YAML is a human-readable data serialization language. | -|
 │ │└── hello_world.dna   
| The compiled DNA file, which includes both the integrity and coordinator zomes. This file is used by Holochain to run the hApp. | +|
 │ │└── hello_world.dna   
| The compiled DNA file, which includes both the integrity and coordinator zomes. This file contains the back-end code needed to participate in a single component of the hApp, and will be bundled into the `.happ` file. | |
 │ └┬─ zomes/             
| The source code for zomes (short for chromosomes), which are the executable packages in a DNA. Each zome has its own name like `profile` or `chat`. Zomes define the core logic in a DNA, and can be composed together to create more powerful functionality. DNAs in Holochain are always composed out of one or more zomes. This folder contains zomes for the `hello_world` DNA. | -|
 │  ├┬─ coordinator/      
| This folder contains the coordinator zomes, which are responsible for this DNA's controller layer, such as reading/writing data and handling communication between peers. The public functions defined in these zomes' code become the application's API available to the UI and, depending on the needs of your app, to other peers in the same network. | +|
 │  ├┬─ coordinator/      
| This folder contains the coordinator zomes, which are responsible for this DNA's controller layer, such as reading/writing data and handling communication between peers. The public functions defined in these zomes' code become the DNA's API available to the UI and, depending on the needs of your app, to other peers in the same network. | |
 │  │└┬─ hello_world/     
| Folder containing the source code for the package that will become the `hello_world` coordinator zome binary. Rust packages are called crates, and they have the following structure. | |
 │  │ ├┬─ src/            
| Source code folder for the `hello_world` crate. | |
 │  │ │└── lib.rs         
| The main source code file for the `hello_world` crate. In Rust, `lib.rs` is the entry point for a library crate, which is the kind of crate that a zome needs to be written as. If you have nothing else in here, you should have this file. | @@ -82,21 +77,21 @@ This table includes everything in the `hello-world/` folder as well as details o |
 │   └┬─ hello_world/     
| Folder containing the `hello_world_integrity` crate. | |
 │    ├┬─ src/            
| Source code folder for the `hello_world_integrity` crate. | |
 │    │└── lib.rs         
| The main source code file for the `hello_world_integrity` crate. | -|
 │    └── Cargo.toml      
| TThe Cargo manifest file for the `hello_world_integrity` crate. | -|
 ├── node_modules/        
| A folder containing cached JavaScript packages and dependencies for the user interface and tests. | +|
 │    └── Cargo.toml      
| The Cargo manifest file for the `hello_world_integrity` crate. | +|
 ├── node_modules/        
| A folder containing cached JavaScript packages and dependencies for the user interface, tests, and build scripts. | |
 ├── target/              
| A folder containing the compiled output from the Rust build process. | -|
 ├── tests/               
| A folder containing JavaScript-base test code for the application. | -|
 ├── ui/                  
| A folder containing the source code and assets for the web-based user interface of the "Hello, World!" application. This user interface will get distributed along with the application. | -|
 ├┬─ workdir/             
| A working folder containing configuration files and compiled artifacts related to the building of the whole hApp. | +|
 ├── tests/               
| A folder containing JavaScript test code for the application. | +|
 ├── ui/                  
| A folder containing the source code and assets for the web-based user interface of the "Hello World!" application. This user interface will get distributed along with the application. | +|
 ├┬─ workdir/             
| A working folder containing bundle manifest for the whole hApp, as well as the hApp file once it's built. | |
 │├── happ.yaml           
| The manifest file for the hApp. It references the DNA files to be included, along with the roles they play in the application. In this case, there's only one DNA file, `hello_world`. | -|
 │├── hello_world.happ    
| The compiled hApp bundle, which includes all the DNAs (in case just the one). | +|
 │├── hello_world.happ    
| The compiled hApp bundle, which includes all the DNAs (in this case, just the one). | |
 │├── hello_world.webhapp 
| The compiled web hApp bundle, which includes the hApp bundle plus the zipped UI. | |
 │└── web-happ.yaml       
| The manifest file for the hApp plus the UI. It references the compiled hApp bundle and zipped UI folder to be included. | |
 ├── Cargo.lock           
| A file generated by Cargo, Rust's package manager, that lists the exact versions of dependencies used in the project. | |
 ├── Cargo.toml           
| The main configuration file for the Rust project, containing dependencies, build options, and other metadata for all crates. | |
 ├── flake.lock           
| A file generated by Nix, the package manager we use to distribute the Holochain development tools, that lists the exact versions of dependencies used in the project. | |
 ├── flake.nix            
| A Nix file that defines the project's build environment and dependencies. | -|
 ├── package.json         
| The main configuration file for the JavaScript portions of the project, containing dependencies, scripts, and other metadata for the application's user interface and tests, as well certain build tools. | +|
 ├── package.json         
| The configuration file for the JavaScript portions of the project, containing dependencies, scripts, and other metadata for the application's user interface and tests, as well certain build tools. | |
 ├── package-lock.json    
| A file generated by npm, Node.js package manager, that lists the exact versions of dependencies used by Node.JS. | |
 └── README.md            
| A Markdown file containing the documentation and instructions for the application, including how to build, run, and test the project. | diff --git a/src/pages/get-started/3-forum-app-tutorial.md b/src/pages/get-started/3-forum-app-tutorial.md index 5fef34a8c..691d20a1a 100644 --- a/src/pages/get-started/3-forum-app-tutorial.md +++ b/src/pages/get-started/3-forum-app-tutorial.md @@ -101,7 +101,7 @@ Just to get an overview of what your first scaffold command set up for you, you ls ``` -It should look like it has set up a similar set of folders and configuration files to those you saw in the "Hello, World!" hApp. +It should look like it has set up a similar set of folders and configuration files to those you saw in the "Hello World!" hApp. Now, fire up the nix development shell, which makes all scaffolding tools and the Holochain binaries directly available from the command line, by entering: @@ -117,7 +117,7 @@ Holochain development shell spawned. Type exit to leave. ``` ::: -As it says, if you want to leave the nix development shell at any time, you can type `exit`. This will take you back to your familiar shell without any of the special Holochain dependencies. When you want to re-enter it, navigate to the `my_forum_app` folder and type `nix develop` again. But for now, install the Node Package Manager (npm) dependencies with: +As it says, if you want to leave the nix development shell at any time, you can type `exit`. This will take you back to your familiar shell without any of the special Holochain dependencies. When you want to re-enter it, navigate to the `my_forum_app` folder and type `nix develop` again. But for now, let's move on to installing the Node Package Manager (npm) dependencies with: ```shell npm install @@ -153,7 +153,7 @@ You should see something like: ::: output-block ```text -holochain_scaffolding_cli 0.1.8 +holochain_scaffolding_cli 0.x.x The list of subcommands for `hc scaffold` USAGE: @@ -191,13 +191,13 @@ A DNA folder is where you will put the code that defines the rules of your appli ### Why do we use the term DNA? -In Holochain, we are trying to enable people to **choose to participate in coherent social coordination**, or interact meaningfully with each other online without needing a central authority to define the rules and keep everyone safe. To do that, we are borrowing some patterns from how biological organisms are able to coordinate coherently even at scales that social organizations such as companies or nations have come nowhere close to. In living creatures like humans, dolphins, redwood trees, and coral reefs, many of the cells in the body of an organism (trillions of the cells in a human body, for instance) are each running a (roughly) identical copy of a rule set in the form of DNA. +With Holochain, we're trying to enable people to **choose to participate in coherent social coordination**, or interact meaningfully with each other online without needing a central authority to define the rules and keep everyone safe. To do that, we are borrowing some patterns from how biological organisms are able to coordinate coherently even at scales that social organizations such as companies or nations have come nowhere close to. In living creatures like humans, dolphins, redwood trees, and coral reefs, many of the cells in the body of an organism (trillions of the cells in a human body, for instance) are each running a (roughly) identical copy of a rule set in the form of DNA. This enables many different independent parts (cells) to build relatively consistent superstructures (a body, for instance), move resources, identify and eliminate infections, and more --- all without centralized command and control. There is no "CEO" cell in the body telling everybody else what to do. It's a bunch of independent actors (cells) playing by a consistent set of rules (the DNA) coordinating in effective and resilient ways. -A cell in the muscle of your bicep finds itself in a particular context, with certain resources and conditions that it is facing. Based on those signals, that cell behaves in particular ways, running relevant portions of the larger shared instruction set (DNA) and transforming resources in ways that make sense for a bicep muscle cell. A different cell in your blood, perhaps facing a context where there is a bacterial infection, will face a different set of circumstances and consequently will make use of other parts of the shared instruction set to guide how it behaves. In other words, many biological organisms make use of this pattern where **many participants run the same rule set, but each in its own context**, and that unlocks a powerful capacity for coherent coordination. +A cell in the muscle of your bicep finds itself in a particular context, surrounded by certain resources and conditions. Based on those signals, that cell behaves in particular ways, running relevant portions of the larger shared instruction set (DNA) and transforming resources in ways that make sense for a bicep muscle cell. A different cell in your blood, perhaps facing a context where there is a bacterial infection, will face a different set of circumstances and consequently will make use of other parts of the shared instruction set to guide how it behaves. In other words, many biological organisms make use of this pattern where **all participants run the same rule set, but each in its own context**, and that unlocks a powerful capacity for coherent coordination. -Holochain borrows this pattern that we see in biological coordination to try to enable similarly coherent social coordination. However, our focus is on enabling such coherent social coordination to be "opted into" by the participants. We believe that this pattern of being able to choose which games you want to play --- and being able to leave them or adapt them as experience dictates --- is critical to enabling individual and collective adaptive capacity. We believe that it may enable a fundamental shift in the ability of individuals and communities to sense and respond to the situations that they face. +Holochain borrows this pattern that we see in biological coordination to try to enable similarly coherent social coordination. However, our focus is on enabling participants to "opt into" such coherent social coordination. We believe that this pattern of being able to choose which games you want to play --- and being able to leave them or adapt them as experience suggests --- is critical to enabling individual and collective adaptive capacity. We believe that it may enable a fundamental shift in the ability of individuals and communities to sense and respond to the situations that they face. To put it another way: if a group of us can all agree to the rules of a game, then together we can play that game. @@ -205,7 +205,7 @@ All of us opting in to those rules --- and helping to enforce them --- enables u ### DNA as boundary of network -The network of participants that are running a DNA engage in "peer witnessing" of actions by the participants in that network. A (deterministically random) set of peers are responsible for validating, storing, and serving each particular piece of shared content. In other words, the users of a particular hApp agree to a set of rules and then work together collectively to enforce those rules and to store and serve content (state changes) that do not violate those rules. +The network of participants that are running a DNA engage in "peer witnessing" of each other's actions in that network. A (deterministically random) set of peers are responsible for validating, storing, and serving each particular piece of shared content. In other words, the users of a particular hApp agree to a set of rules and then work together collectively to enforce those rules and to store and serve content (state changes) that do not violate those rules. Every hApp needs to include at least one DNA. Moreover, as indicated above, **it is at the DNA level** (note: not the higher application level) **where participants will form a network of peers to validate, store, and serve content** in accordance with the rules defined in that DNA. This happens in the background as the application runs on each participant's machine. @@ -213,7 +213,7 @@ There are some powerful consequences to this architectural choice --- including ### So if we have multiple DNAs in our hApp... -...then we are participating in multiple networks, with each network of peers that are participating in a particular DNA also helping maintain the shared database for each DNA, enforcing the DNA's rules while validating, storing, and serving content. Each network acts as a 'social organism' in cooperation with other networks in the hApp. +...then we are participating in multiple networks, with each network of peers that are participating in a particular DNA also helping maintain the shared database for that DNA, enforcing its rules while validating, storing, and serving content. Each network acts as a 'social organism' in cooperation with other networks in the hApp. This is similar to the way in which multiple DNA communities coexist in biological organisms. In fact, there are more cells in a human body that contain other DNA (like bacteria and other microorganisms) than cells that contain our DNA. This indicates that we are an _ecology_ of coherent communities that are interacting with --- and evolving alongside --- one another. @@ -278,11 +278,11 @@ You should then see: ### Integrity zomes -An integrity zome, as the name suggests, is responsible for maintaining the data integrity of a Holochain application. It sets the rules and ensures that any data writes occurring within the application are consistent with those rules. In other words, it is responsible for ensuring that data is correct, complete, and trustworthy. Integrity zomes help maintain a secure and reliable distributed peer-to-peer network by enforcing the validation rules defined by the application developer --- in this case, you! +An integrity zome, as the name suggests, is responsible for maintaining the data integrity of a Holochain application. It sets the rules and ensures that any data writes occurring within the application are consistent with those rules. In other words, it's responsible for ensuring that data is correct, complete, and trustworthy. Integrity zomes help maintain a secure and reliable distributed peer-to-peer network by enforcing the validation rules defined by the application developer --- in this case, you! ### Coordinator zomes -On the other hand, a coordinator zome contains the code that actually commits data, retrieves it, or sends and receives messages between peers or between other portions of the application on a user's own device (between the back end and the front-end UI, for instance). A coordinator zome is where you define the API for your DNA, through which the network of peers and their data is made accessible to the user. +On the other hand, a coordinator zome contains the code that actually commits data, retrieves it, or sends and receives messages between peers or between other portions of the application on a user's own device (between the back end and the UI, for instance). A coordinator zome is where you define the API for your DNA, through which the network of peers and their data is made accessible to the user. ### Multiple zomes per DNA @@ -290,7 +290,7 @@ As you learned earlier, a DNA can have multiple integrity and coordinator zomes. ### Why two types? -They are separated from one another so we can update coordinator zomes without having to update the integrity zomes. This is important, because changes made to an integrity zome result in a change of the rule set, which results in an entirely new network. This is because the integrity code is what defines the 'rules of the game' for a group of participants. If you changed the code of an integrity zome, you would find yourself suddenly in a new and different network from the other folks who haven't yet changed their integrity zome --- and we want to minimize those sorts of forks to situations where they are needed (like when a community decides they want to play by different rules, for instance changing the maximum length of comments from 140 characters to 280 characters). +They are separated from one another so we can update coordinator zomes without having to update the integrity zomes. This is important, because changes made to an integrity zome result in a change of the rule set, which results in an entirely new network. This is because the integrity code is what defines the 'rules of the game' for a group of participants. If you changed the code of an integrity zome, Holochain would consider it a new 'game' and you would find yourself suddenly in a new and different network from the other folks who haven't yet changed their integrity zome --- and we want to minimize those sorts of forks to situations where they are needed (like when a community decides they want to play by different rules, for instance changing the maximum length of comments from 140 characters to 280 characters). At the same time, a community will want to be able to improve the ways in which things are done in a Holochain app. This can take the form of adding new features or fixing bugs, and we also want people to also be able to take advantage of the latest features in Holochain. Separating integrity and coordination enables them to do that more easily, because: @@ -355,17 +355,17 @@ Once that is all done, your hApp skeleton will have filled out a bit. Before you ### Source chain -Any time a participant in a hApp takes some action that changes data, they add a record to a journal called a **source chain**. Each participant has their own source chain, a local, tamper-proof, and chronological store of the participant's actions in that application. +Any time a participant in a hApp takes some action that changes data, they do it by adding a record to a journal called a **source chain**. Each participant has their own source chain, a local, tamper-proof, and chronological store of the participant's actions in that application. -This is one of the main differences between Holochain and other systems such as blockchains or centralized server-based applications. Instead of recording a "global" (community-wide) record of what actions have taken place, in Holochain actions are taken by agents and are thought of as transformations of their own state. +This is one of the main differences between Holochain and other systems such as blockchains or centralized server-based applications. Instead of recording a "global" (community-wide) timeline of what actions have taken place, in Holochain actions are recorded on individual timelines. They can be thought of as both a change to the individual's state and an attempt to change shared state. One big advantage of this approach is that a single agent can be considered authoritative about the order in which they took actions. From their perspective, first they did A, then B, then C, etc. The fact that someone else didn't get an update about these changes, and possibly received them in a different order, doesn't matter. The order that the authoring agent took those actions will be captured in the actions themselves (thanks to each action referencing the previous one that they had taken, thus creating an ordered sequence --- or chain --- of actions). ### Actions and entries -You'll notice that we used the word "action" a lot. In fact, **we call the content of a source chain record an action**. In Holochain applications, data is always "spoken into being" by an agent (a participant). Each record captures their act of adding, modifying, or removing data, rather than simply capturing the data itself. +You'll notice that we used the word "action" a lot. In fact, **we call the a source chain record an action**. In Holochain applications, data is always "spoken into being" by an agent (a participant). Each record captures their act of adding, modifying, or removing data, rather than simply capturing the data itself. -There are a few different kinds of actions, but the most common one is `Create`, which creates an 'entry' --- an arbitrary blob of bytes. Entries store most of the actual content created by a participant, such as the text of a post in our forum hApp. When someone creates a forum post, they're recording an action to their source chain that reads something like: _I am creating this forum post entry with the title "Intros" and the content "Where are you from and what is something you love about where you live?" and I would like my peers in the network to publicly store a record of this act._ So while an action is useful for storing noun-like data like messages and images, it's actually a verb, a record of an action that someone took to update their own state and possibly the shared database state as well. That also makes it well-suited to verb-like data like real-time document edits, game moves, and transactions. +There are a few different kinds of actions, but the most common one is `Create`, which creates an 'entry' --- an arbitrary blob of bytes. Entries store most of the actual content created by a participant, such as the text of a post in our forum hApp. When someone creates a forum post, they're recording an action to their source chain that reads something like: _I am creating this forum post entry with the title "Intros" and the content "Where are you from and what is something you love about where you live?" and I would like my peers in the network to publicly store a record of this act along with the data itself._ So while an action is useful for storing noun-like data like messages and images, it's actually a verb, a record of an action that someone took to update their own state and possibly the shared state as well. That also makes it well-suited to verb-like data like real-time document edits, game moves, and transactions. Every action contains the ID of its author (actually a cryptographic public key), a timestamp, a pointer to the previous source chain record, and a pointer to the entry data, if there is any. In this way, actions provide historical context and provenance for the entries they operate on. @@ -395,17 +395,17 @@ An entry type is a fundamental building block used to define the structure and v An entry type is just a label, an identifier for a certain type of data that your DNA deals with. It serves as something to attach validation rules to in your integrity zome, and those rules are what give an entry type its meaning. They take the form of code in a function that gets called any time something is about to be stored, and because they're just code, they can validate all sorts of things. Here are a few key examples: -* **Data structure**: When you use the scaffolding tool to create an entry type, it generates a Rust-based data type that define fields in your entry type, and it also generates code in the validation function that attempts to convert the raw bytes into an instance of that type. By providing a well-defined structure, this type ensures that data can be understood by the application. If it can't be deserialized into the appropriate Rust structure, it's not valid. +* **Data structure**: When you use the scaffolding tool to create an entry type, it generates a Rust struct that defines fields in your entry type, and it also generates code in the validation function that attempts to convert the raw bytes into an instance of that type. By providing a well-defined structure, this type ensures that data can be understood by the application. If it can't be deserialized into the appropriate Rust structure, it's not valid. * **Constraints on data**: Beyond simple fields, validation code can constrain the values in an entry --- for instance, it can enforce a maximum number of characters in a text field or reject nonsensical calendar dates. * **Privileges**: Because it originates in a source chain, an entry comes with metadata about its author. This can be used to control who can create, edit, or delete an entry. -* **Contextual conditions**: Because an action is part of a chain of actions, it can be validated based on the agent's history --- for instance, to prevent currency transactions beyond a credit limit or disallow more than two comments per minute to discourage spam. An entry can also point to other entries in the DHT upon which it depends, and the data from those entries can be used in its validation. +* **Context**: Because an action is part of a chain of actions, it can be validated based on the agent's history --- for instance, to prevent currency transactions beyond a credit limit or disallow more than two comments per minute to discourage spam. An entry can also point to other actions and entries in the DHT upon which it depends, and their data can be used in its validation. !!! -Your bare-bones forum needs two entry types: `post` and `comment`. You'll define these in the `posts` integrity zome you just created in the previous step. The `post` entry type will define a `title` field and a `content` field. The `comment` entry type will define a `comment_content` field and a way of indicating which post the comment is about. +Your bare-bones forum needs two entry types: `post` and `comment`. You'll define these in the `posts` integrity zome you just created in the previous step. The `post` entry type will define a `title` field and a `content` field. The `comment` entry type will define a `comment_content` field and a reference to the post it should be attached to. To do this, just follow the instructions that the scaffold suggested for adding new entry definitions to your zome. @@ -454,7 +454,7 @@ Which fields should the entry contain? The scaffolding tool is now prompting you to add fields to the `post` entry type. -Fields are the individual components or attributes within an entry type that define the structure of the data. They determine the specific pieces of information to be stored in an entry and their respective data types. The scaffolding tool supports a collection of native Rust types such as booleans, numbers, enums (a choice between several predetermined values), optional values, and vectors (lists of items of the same type), along with Holochain-specific types that refer to other pieces of data on the DHT. +Fields are the individual components or attributes within a Rust struct. They determine the specific pieces of information to be stored in an entry and their respective data types. The scaffolding tool supports a collection of native Rust types such as booleans, numbers, enums (a choice between several predetermined values), optional values, and vectors (lists of items of the same type), along with Holochain-specific types that refer to other pieces of data on the DHT. For your `post` entry type, you're going to add `title` and `content` fields. Select `String` as the first field's type, and enter: @@ -464,7 +464,7 @@ title as the field name. -Press Y for the field to be visible in the UI, and use the arrow keys to select `TextField` as the widget to render this field. (A `TextField` is a single-line input field designed for capturing shorter pieces of text.) +Press Y for the field to be visible in the UI, and select `TextField` as the widget to render this field. (A `TextField` is a single-line input field designed for capturing shorter pieces of text.) When you see: @@ -476,7 +476,7 @@ When you see: press Y. -Select `String` for this field's type too. Then enter +Select `String` for this field's type too. Then enter: ```text content @@ -530,9 +530,9 @@ Because all data in a Holochain application is immutable once it's written, we d For an `Update` action, the original `Create` or `Update` action and its entry content on the DHT get a `ReplacedBy` pointer to the new `Update` action and its entry content. -When the scaffolding tool asks you whether to create a link from the original entry, though it's not talking about this pointer. Instead, it's talking about an extra piece of metadata that points to the _very newest_ entry in a chain of updates. If an entry were to get updated, and that update were updated, and this were repeated three more times, anyone trying to retrieve the entry would have to query the DHT six times before they finally found the newest revision. This extra link, which is not a built-in feature, 'jumps' them past the entire chain of updates at the cost of a bit of extra storage. The scaffolding tool will generate all the extra code needed to write and read this metadata in its update and read functions. +When the scaffolding tool asks you whether to create a link from the original entry, though, it's not talking about this pointer. Instead, it's talking about an extra piece of metadata that points to the _very newest_ entry in a chain of updates. If an entry were to get updated, and that update were updated, and this were repeated three more times, anyone trying to retrieve the entry would have to query the DHT six times before they finally found the newest revision. This extra link, which is not a built-in feature of updates, 'jumps' them past the entire chain of updates at the cost of a bit of extra storage. The scaffolding tool will generate all the extra code needed to write and read this metadata in its update and read functions. You can read more about links in the Core Concepts secton on [Links and Anchors](https://developer.holochain.org/concepts/5_links_anchors/). -For a `Delete` action, the original action and its entry content are simply marked as deleted. In the cases of both updating and deleting, all original data is still accessible if the application needs it. +For a `Delete` action, the original action and its entry content are simply marked as dead. In the cases of both updating and deleting, all original data is still accessible if the application needs it. ### Resolving conflicts @@ -586,7 +586,7 @@ Then select the `TextArea` widget and press Enter. (Again, a `TextAre Press Y to add another field. -For this next field you'll want to create a field that will help you associate each particular comment to the post that it is commenting on. To do this, the next field in the `comment` entry type will store a reference to a `post`. +For this next field you'll want to create a field that will help you associate each particular comment to the post that it's commenting on. To do this, the next field in the `comment` entry type will store a reference to a `post`. Use the arrow keys to select `ActionHash` as the field type. @@ -602,27 +602,27 @@ To ensure data integrity and facilitate efficient data retrieval, each piece of * **Uniqueness:** The cryptographic hashing function ensures that the data has a unique hash value, which helps to differentiate it from other data on the network. * **Efficient lookup:** The hash is used as a key (essentially an address) in the network's storage system, the distributed hash table (DHT). When an agent wants to retrieve data, they simply search for it by hash, without needing to know what peer machine it's stored on. In the background, Holochain reaches out simultaneously to multiple peers who are responsible for the hash based on an algorithm that matches peers to data based on the similarity of the hash to their agent IDs. This makes data lookup fast and resilient to unreliable peers or network conditions. -* **Fair distribution:** Because the participants in a network are responsible for validating and storing each other's public data based on its hash, the randomness of the hashing function ensures that that responsibility is spread fairly evenly among everyone. +* **Fair distribution:** Because the participants in a network are responsible for validating and storing each other's public data based on its hash, the randomness of the hashing function ensures that the responsibility for the entire data set is spread fairly evenly among everyone. * **Integrity verification:** `Hi` will always generate the same hash no matter who runs it through the hashing function. So when data is retrieved by hash, its hash can be recalculated and compared with the original requested hash to ensure that a third party hasn't tampered with the data. * **Collusion resistance:** The network peers who take responsibility for validating and storing an entry are chosen randomly based on the similarity of their agent IDs to the `EntryHash`. It would take a huge amount of computing power to generate a hash that would fall under the responsibility of a colluding peer. And because Holochain can retrieve data from multiple peers, it's more likely that the requestor can find one honest peer to report problems with a piece of bad data. ### `ActionHash` -An action is identified by its `ActionHash`. Because an action contains information about its author, the time it was written, the action that preceded it, and the entry it operates on, no two action hashes will be the same --- even for the same entry. This helps to disambiguate identical entries written at different times by different agents. +An action is identified by its `ActionHash`. Because an action contains information about its author, the time it was written, the action that preceded it, and the entry it operates on, no two action hashes will be the same --- even for two `Create` actions that write the same entry. This helps to disambiguate identical entries written at different times or by different agents. ### `EntryHash` -An entry is identified by its `EntryHash`, which can be retrieved from the `ActionHash` of the action that wrote it. Because they're two separate pieces of data, an entry is stored by different peers than the action that operates on it. +An entry is identified by its `EntryHash`, which can be retrieved from the action that wrote it. Because they're two separate pieces of data, an entry and its action are stored by different peers in the network. ### `AgentPubKey` **Each agent in a network is identified by their cryptographic public key**, a unique number that's mathematically related to a private number that they hold on their machine. Public-key cryptography is a little complex for this guide --- it's enough to know that a participant's private key signs their source chain actions, and those signatures paired with their public key allow others to verify that they are the one who authored those actions. -An `AgentPubKey` isn't a hash, but it's the same length, and it's unique just like a hash. So it can be used as a way of referring to an agent, like a user ID --- and this is also why it's used to choose the right peers in the DHT storage and retrieval algorithm. +An `AgentPubKey` isn't a hash, but it's the same length, and it's unique just like a hash. So it can be used as a way of referring to an agent, like a user ID --- and this is also why it's used to choose peers in the DHT storage and retrieval algorithm. ### Summary -Whereas `EntryHash` is used to uniquely identify, store, and efficiently retrieve an entry from the DHT, `ActionHash` is used to uniquely identify, store, and retrieve the action (metadata) that operated on it, which can provide information about the history and context of any associated entry (including what action preceded it). `ActionHash`es are also what enable any participant to retrieve and reconstruct the continuous sequence of actions (and any associated entries) in another agent's source chain. +Whereas `EntryHash` is used to uniquely identify, store, and efficiently retrieve an entry from the DHT, `ActionHash` does the same for the action that operated on it, which can provide information about the history and context of any associated entry (including what action preceded it). `ActionHash`es are also what enable any participant to retrieve and reconstruct the continuous sequence of actions (and any associated entries) in another agent's source chain. **Use `EntryHash` when** you want to link to or retrieve the actual content or data (e.g., when linking to a category in a forum application). @@ -654,7 +654,7 @@ Next you will see: Press Enter to accept the suggested entry type `Post`. -Next, you will be asked to pick a field name. You can press Enter to accept the field name suggestion, which should be: +Next, you'll be asked to pick a field name. You can press Enter to accept the field name suggestion, which should be: ```text post_hash @@ -662,7 +662,7 @@ post_hash Press N to decline adding another field to the entry. -Then use the arrow keys to deselect Update, but leave Delete selected. It should look as follows: +Then use the arrow keys to deselect `Update`, but leave `Delete` selected. It should look as follows: ::: output-block ```text @@ -826,12 +826,12 @@ The Holochain Playground in particular is helpful because it creates visual repr From oldest to newest, in the newly created source chains, the records are: 1. `DNA`, recording the hash of the DNA to be used to validate all subsequent source chain actions, -2. `AgentValidationPkg`, providing proof that this participant is allowed to participate in this hApp ([see more](https://www.holochain.org/how-does-it-work/) in Holochain: How does it work?), +2. `AgentValidationPkg`, providing proof that this participant is allowed to participate in this hApp (see more in [Holochain: How does it work?](https://www.holochain.org/how-does-it-work/)), 3. A `Create` action which records the author's `AgentID`, which is their public key and serves as their ID in the network and its graph database. As agents begin writing posts, comments, and links to the DHT, you'll see the following records appear: -4. `InitComplete`, indicating that all coordinator zomes have had a chance to do initial setup, then +4. `InitComplete`, indicating that all coordinator zomes have had a chance to do initial setup (which may include writing actions between action 3 and this action), then 5. Whatever actions the agent takes after that. The two application UI windows let you interact with the application and see what is working, what is not working, and how data propagates when we take particular actions. @@ -858,7 +858,7 @@ CommentsForPost.svelte EditPost.svelte The next step is to edit the UI files in the text editor or integrated development environment of your choice to add scaffolded components and build a fully featured UI. To integrate all of these generated UI elements, you'll need to add them to `App.svelte` file located in the `ui/src/` folder, or to some other `.svelte` file that eventually gets included in `App.svelte`. -If you don't yet have path commands for opening files in your preferred IDE, there are instructions for [VSCode/VSCodium](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line), [Sublime Text](https://www.sublimetext.com/docs/command_line.html#setup) and [WebStorm](https://www.jetbrains.com/help/webstorm/working-with-the-ide-features-from-command-line.html#5d6e8844). Going forward in this tutorial, we are going to use the `code` command when we mean for you to open files in your IDE, but you should substitute a different command (ex: `subl`, `vim`, `emacs` etc.) for `code` if you are using a different editor. +If you don't yet have path commands for opening files in your preferred IDE, there are instructions for [VSCode/VSCodium](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line), [Sublime Text](https://www.sublimetext.com/docs/command_line.html#setup) and [WebStorm](https://www.jetbrains.com/help/webstorm/working-with-the-ide-features-from-command-line.html#5d6e8844). Going forward in this tutorial, we are going to use the `code` command when we mean for you to open files in your IDE, but you should substitute a different command (ex: `subl`, `vim`, `emacs`, etc.) for `code` if you are using a different editor. Open the `App.svelte` file with your preferred IDE. @@ -886,13 +886,13 @@ Your `App.svelte` file will have three sections: import { clientContext } from './contexts'; let client: AppAgentClient | undefined; - let loading = true; - $: client, loading; + let loading = true; onMount(async () => { // We pass '' as url because it will dynamically be replaced in launcher environments - client = await AppAgentWebsocket.connect('', 'forum'); + client = await AppAgentWebsocket.connect('https://UNUSED', 'forum'); + loading = false; }); @@ -913,8 +913,6 @@ After importing dependencies, it does some initial setup. This is run when the c Next some variables are instantiated: one to hold the Holochain client that connects to the hApp backend via the conductor, and one to keep track of whether the client is connected yet. (This variable will be used to show a loading spinner while it's still connecting.) -**Take note of the line that starts with `$:`**. This is a special Svelte label that turns regular variables into **reactive variables**. We won't get too deep into Svelte right now, because this is a tutorial about Holochain, but when a reactive variable changes, Svelte will re-render the entire component. This lets you write a template declaratively, enclosing the reactive variable in `{}` braces, and let Svelte handle the updating of the template wherever the variable changes. - Finally, there's an `onMount` handler, which is run when the component is first displayed. The handler currently does one thing: it connects to the hApp backend via the conductor, waits until the connection is established, sets `loading` to false, and adds the resulting client connection to the context so that all components can access it. ### `
` section @@ -950,6 +948,8 @@ import CreateTodo from './todos/todos/CreateTodo.svelte'; This section is a template for the displayable content of the main app component. Using an `{#if}` block to test whether the reactive variable `loading` is true, this section displays a spinner until the backend can be accessed. Once the UI is connected to the backend, it shows some boilerplate text telling you to add something meaningful to the template. +Note that, in Svelte, any time a variable changes, the template is re-rendered with the new value. This is called **reactivity**, and makes your life easier because you don't have to write quite so many event handlers for changes on your data. + ### `