@powerhousedao/academy 3.2.0-dev.5 → 3.2.0-dev.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/02-ConfiguringDrives.md +53 -29
  3. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/images/Screenshot 2025-06-26 at 17.41.14.png +0 -0
  4. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/images/AddDrive.png +0 -0
  5. package/docs/academy/02-MasteryTrack/04-WorkWithData/01-ReadingAndWritingThroughTheAPI.mdx +174 -56
  6. package/docs/academy/02-MasteryTrack/04-WorkWithData/04-analytics-processor.md +89 -1
  7. package/docs/academy/02-MasteryTrack/04-WorkWithData/images/AddNewDriveURL.png +0 -0
  8. package/docs/academy/02-MasteryTrack/04-WorkWithData/images/DocumentID.png +0 -0
  9. package/docs/academy/02-MasteryTrack/04-WorkWithData/images/OnboardingTasks.png +0 -0
  10. package/docs/academy/02-MasteryTrack/04-WorkWithData/images/QueryDocument.png +0 -0
  11. package/docs/academy/02-MasteryTrack/04-WorkWithData/images/QueryDocument2.png +0 -0
  12. package/docs/academy/04-APIReferences/01-ReactHooks.md +0 -5
  13. package/package.json +1 -1
  14. package/src/css/custom.css +7 -1
  15. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{07-DocumentTools → 06-DocumentTools}/00-DocumentToolbar.mdx +0 -0
  16. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{07-DocumentTools → 06-DocumentTools}/01-OperationHistory.md +0 -0
  17. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{07-DocumentTools → 06-DocumentTools}/02-RevisionHistoryTimeline.md +0 -0
  18. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{07-DocumentTools → 06-DocumentTools}/_category_.json +0 -0
  19. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{07-DocumentTools → 06-DocumentTools}/images/DocumentToolbar.png +0 -0
  20. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{07-DocumentTools → 06-DocumentTools}/images/committer-address-popup.png +0 -0
  21. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{07-DocumentTools → 06-DocumentTools}/images/revision-hash-popup.png +0 -0
  22. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{07-DocumentTools → 06-DocumentTools}/images/revision-history-list.png +0 -0
  23. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{07-DocumentTools → 06-DocumentTools}/images/revision-history-timeline.png +0 -0
  24. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{07-DocumentTools → 06-DocumentTools}/images/signature-details-popup.png +0 -0
  25. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{08-Authorization → 07-Authorization}/01-RenownAuthenticationFlow.md +0 -0
  26. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{08-Authorization → 07-Authorization}/02-Authorization.md +0 -0
  27. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{08-Authorization → 07-Authorization}/_category_.json +0 -0
  28. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{08-Authorization → 07-Authorization}/images/ConnectAddress.png +0 -0
  29. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{08-Authorization → 07-Authorization}/images/LoginComplete.png +0 -0
  30. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{08-Authorization → 07-Authorization}/images/OperationsHistory.png +0 -0
  31. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{08-Authorization → 07-Authorization}/images/RenownLogin.png +0 -0
  32. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/{08-Authorization → 07-Authorization}/images/ReturnToConnect.png +0 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## 3.2.0-dev.7 (2025-06-28)
2
+
3
+ ### 🚀 Features
4
+
5
+ - starting to stub out a complete example of the analytics processor ([a84ed2dcf](https://github.com/powerhouse-inc/powerhouse/commit/a84ed2dcf))
6
+
7
+ ### ❤️ Thank You
8
+
9
+ - Benjamin Jordan (@thegoldenmule)
10
+
11
+ ## 3.2.0-dev.6 (2025-06-27)
12
+
13
+ ### 🚀 Features
14
+
15
+ - **connect:** use atom store and provider from state library ([28f646636](https://github.com/powerhouse-inc/powerhouse/commit/28f646636))
16
+ - added drive analytics processor ([#1607](https://github.com/powerhouse-inc/powerhouse/pull/1607))
17
+
18
+ ### 🩹 Fixes
19
+
20
+ - updated document-engineering ver ([3522179d6](https://github.com/powerhouse-inc/powerhouse/commit/3522179d6))
21
+ - updated atoms with header changes ([2b557197a](https://github.com/powerhouse-inc/powerhouse/commit/2b557197a))
22
+
23
+ ### ❤️ Thank You
24
+
25
+ - Benjamin Jordan (@thegoldenmule)
26
+ - Guillermo Puente
27
+ - Guillermo Puente Sandoval
28
+ - ryanwolhuter
29
+
1
30
  ## 3.2.0-dev.5 (2025-06-26)
2
31
 
3
32
  ### 🚀 Features
@@ -1,6 +1,6 @@
1
1
  # Configure a drive
2
2
 
3
- A drive in Powerhouse is a container or a wrapper for documents and data. It's a place where you can organize and store your documents and share them with others. This guide will walk you through the process of configuring and managing drives in your Powerhouse environment.
3
+ A drive in Powerhouse is a container for documents and data. It's a place where you can organize and store your documents and share them with others. This guide walks you through configuring and managing drives in your Powerhouse environment.
4
4
 
5
5
  :::info **Prerequisites**
6
6
 
@@ -14,64 +14,74 @@ Before configuring a drive, ensure you have:
14
14
 
15
15
  ### Local drives
16
16
 
17
- A local drive is a container for local documents and data, hosted on your local machine. Technically a drive is just another document model with a list of the documents inside the drive. When you run connect locally with `ph connect` a local drive is automatically added. You can also create a new local drive by clicking **'add drive'** in connect.
17
+ A local drive is a container for local documents and data, hosted on your local machine. Technically, a drive is itself a document that contains a list of the documents inside it. When you run Connect locally with `ph connect`, a local drive is automatically added. You can also create a new local drive by clicking **'Create New Drive'** in Connect.
18
18
 
19
19
  ### Remote drives vs. reactors
20
20
 
21
- Remote drives in Powerhouse allow you to connect to and work with data stored in external systems or cloud services. These drives act as bridges between Powerhouse contributors and/or other data sources, enabling seamless data synchronization. Drives can exist in 3 category locations.
21
+ Remote drives in Powerhouse allow you to connect to and work with data stored in external systems or cloud services. These drives act as bridges between Powerhouse contributors or other data sources, enabling seamless data synchronization. Drives can exist in three types of locations:
22
22
 
23
23
  - **Local Storage**: For offline or on-device access.
24
24
  - **Cloud Storage**: For centralized, scalable data management.
25
25
  - **Decentralized Storage**: Such as Ceramic or IPFS, enabling distributed and blockchain-based storage options.
26
26
 
27
27
  :::tip **Explainer**
28
- **Powerhouse Reactors** are the nodes in the network that store and synchronise documents & drives , resolve conflicts and rerun operations to verify document event histories.
29
- Reactors can be configured for local storage, centralized cloud storage or on a decentralized storage network.
28
+ **Powerhouse Reactors** are the nodes in the network that store and synchronize documents and drives, resolve conflicts, and rerun operations to verify document event histories.
29
+ Reactors can be configured for local storage, centralized cloud storage, or a decentralized storage network.
30
30
 
31
- A reactor allows you to store multiple documents, but also host **drives** & Drive Explorers with different organisational purposes, users, access rights and more.
31
+ A reactor allows you to store multiple documents and host **drives** and Drive Explorers with different organizational purposes, users, access rights, and more.
32
32
  :::
33
33
 
34
- A drive exists by making use of a reactor and the storagelayer that specific reactor is based on. A reactor is the lower level component that makes synchronisation of documents & drives possible.
34
+ A drive uses a reactor and its underlying storage layer. A reactor is the low-level component that enables the synchronization of documents and drives.
35
35
 
36
36
  ### Drive apps
37
37
 
38
- **Drive Explorers** (also known as Drive Apps) are specialized interfaces that enhance how users interact with document models within a drive. As mentioned previously, technically a drive is just another document, with a list of the documents inside the drive. So it is obvious that you can create a custom editor for your drive-document.
38
+ **Drive Explorers** (also known as Drive Apps) are specialized interfaces that enhance how users interact with documents within a drive. As mentioned, a drive is technically just another document containing a list of other documents. This means you can create a custom editor for your drive document.
39
39
 
40
- These customized editors are called Drive explorers or Drive Apps. They provide custom views, organization tools, and interactive features tailored to specific use cases. For example, a Drive Explorer might present data as a Kanban board, provide aggregated insights, or offer specialized widgets for data processing.
40
+ These customized editors are called Drive Explorers or Drive Apps. They provide custom views, organization tools, and interactive features tailored to specific use cases. For example, a Drive Explorer might present data as a Kanban board, provide aggregated insights, or offer specialized widgets for data processing.
41
41
 
42
42
  To learn more about building and customizing Drive Explorers, check out our [Building a Drive Explorer](/academy/MasteryTrack/BuildingUserExperiences/BuildingADriveExplorer) guide.
43
43
 
44
44
 
45
45
  ## Creating a new drive
46
46
 
47
- ![Create New Drive](./images/CreateNewDrive.png)
47
+ <figure className="image-container">
48
+ <img src={require("./images/CreateDrive.png").default} alt="Create a new drive" />
49
+ <figcaption>The drive management modal after clicking the 'Create New Drive' button.</figcaption>
50
+ </figure>
48
51
 
49
52
  To create a new drive in Powerhouse, follow these steps:
50
- 1. Click on the "**Create New Drive**" button in the Connect interface or in the Connect sidebar on the (+) Icon.
53
+ 1. Click the "**Create New Drive**" button in the Connect interface or the **+** icon in the Connect sidebar.
51
54
  2. In the modal that appears, enter a name for your drive in the "**Drive Name**" field.
52
55
  3. Select the desired Drive App (such as the Generic Drive Explorer, or any other Drive App you've installed).
53
56
  4. Choose the location for your drive: **Local** (only available to you), **Cloud** (available to people in this drive), or **Public** (available to everyone).
54
57
  5. (Optional) Enable the "Make available offline" toggle if you want to keep a local backup of your drive.
55
58
  6. Once all options are set, click the "Create new drive" button to finalize and create your drive.
56
59
 
57
- ## Adding a new remote drive via graphql mutation
60
+ ## Add a new remote drive via GraphQL mutation
58
61
 
59
62
  You can also add a new remote drive to your Connect environment programmatically using GraphQL mutations. This is especially useful for automation, scripting, or integrating with external systems.
60
63
 
61
64
  :::info **Prerequisites**
62
- - Access to the Switchboard or remote reactor (server node) of your Connect instance.
63
- - The GraphQL endpoint for your instance. For example, for the staging environment, use: `https://staging.switchboard.phd/graphql/system` (this is a supergraph gateway).
65
+ - Access to the Switchboard or remote reactor (server node) of your Connect instance. In your local project, you can start your Reactor by running the following command in a different terminal from Connect Studio.
66
+ `bash
67
+ ph reactor
68
+ `
69
+ - The GraphQL endpoint of your instance. For example, for the staging environment, use: `https://staging.switchboard.phd/graphql/system` (this is a supergraph gateway. Read more about [subgraphs and supergraphs here](/academy/MasteryTrack/WorkWithData/WorkingWithSubgraphs).
64
70
  - Appropriate permissions to perform mutations.
65
71
  :::
66
72
 
67
- ### Steps
68
- 1. **Navigate to the GraphQL Playground or use a GraphQL client**
69
- - Open [https://staging.switchboard.phd/graphql/system](https://staging.switchboard.phd/graphql/system) in your browser, or use a tool like [GraphQL Playground](https://www.apollographql.com/docs/apollo-server/testing/graphql-playground/).
73
+ <figure className="image-container">
74
+ <img src={require("./images/CreateNewDrive.png").default} alt="Create a new drive" />
75
+ <figcaption>The GraphQL interface for creating a new drive through a mutation.</figcaption>
76
+ </figure>
70
77
 
71
- 2. **Prepare the Mutation**
78
+ ### 1. **Navigate to the GraphQL Playground or use a GraphQL client**
79
+ - Open [https://switchboard.phd/graphql/system](https://switchboard.phd/graphql/system) in your browser, or use a tool like [GraphQL Playground](https://www.apollographql.com/docs/apollo-server/testing/graphql-playground/).
80
+
81
+ ### 2. **Prepare the Mutation**
72
82
  - Use the following mutation to create a new drive:
73
83
 
74
- ```graphql
84
+ ```graphql title="Create Drive Mutation"
75
85
  mutation Mutation($name: String!, $icon: String, $addDriveId: String, $slug: String) {
76
86
  addDrive(name: $name, icon: $icon, id: $addDriveId, slug: $slug) {
77
87
  icon
@@ -82,8 +92,8 @@ You can also add a new remote drive to your Connect environment programmatically
82
92
  }
83
93
  ```
84
94
 
85
- - Example variables:
86
- ```json
95
+ - These are the example variables, feel free to change these as you like and add a different name or logo for your drive:
96
+ ```json title="Example Variables"
87
97
  {
88
98
  "name": "AcademyTest",
89
99
  "icon": "https://static.thenounproject.com/png/3009860-200.png",
@@ -91,12 +101,12 @@ You can also add a new remote drive to your Connect environment programmatically
91
101
  "slug": null
92
102
  }
93
103
  ```
94
- - You can also provide a custom `id`, `slug`, or `preferredEditor` if needed.
104
+ - You can also provide a custom `id` or `slug` if needed.
95
105
 
96
- 3. **Execute the Mutation**
106
+ ### 3. **Execute the Mutation**
97
107
  - Run the mutation. On success, you will receive a response containing the new drive's `icon`, `id`, `name`, and `slug`:
98
108
 
99
- ```json
109
+ ```json title="Successful Response"
100
110
  {
101
111
  "data": {
102
112
  "addDrive": {
@@ -109,16 +119,30 @@ You can also add a new remote drive to your Connect environment programmatically
109
119
  }
110
120
  ```
111
121
 
112
- 4. **Construct the Drive URL**
122
+ ### 4. **Construct the Drive URL**
113
123
  - Once you have the `id` or `slug`, you can construct the drive URL for Connect:
114
- - Format: `domain/d/driveId` or `domain/d/driveSlug`
115
- - Example: `https://staging.connect.phd/d/6461580b-d317-4596-942d-f6b3d1bfc8fd`
124
+ - Format: `domain/d/<driveId>` or `domain/d/<driveSlug>`
125
+ - Depending on whether you are using a hosted or a local environment, the domain in your URL will change.
126
+ - Example: `https://connect.phd/d/6461580b-d317-4596-942d-f6b3d1bfc8fd`
127
+ - Example: `https://localhost:4001/d/6461580b-d317-4596-942d-f6b3d1bfc8fd`
128
+
129
+ ### 5. **Add the Drive in Connect**
130
+ - Use the constructed URL to add or access the drive in your Connect environment via the 'Add Drive' button.
116
131
 
117
- 5. **Add the Drive in Connect**
118
- - Use the constructed URL to add or access the drive in your Connect environment.
132
+ <figure className="image-container">
133
+ <img src={require("./images/AddDrive.png").default} alt="Create a new drive" />
134
+ <figcaption>The 'Add Drive' button that allows you to enter your constructed Drive URL.</figcaption>
135
+ </figure>
119
136
 
120
137
  ---
121
138
 
122
139
  This approach allows you to automate drive creation and integration with other systems, making it easy to manage drives at scale.
123
140
 
141
+ ## Up next
142
+
143
+ You've now experienced the use of GraphQL to modify or read data captured in Powerhouse for the first time.
144
+ You can now either continue with:
145
+ - User interfaces and [build a custom drive experiences](/academy/MasteryTrack/BuildingUserExperiences/BuildingADriveExplorer)
146
+ - Keep playing with data and the [Switchboard API](/academy/MasteryTrack/WorkWithData/ReadingAndWritingThroughTheAPI)
124
147
 
148
+ Enjoy!
@@ -2,114 +2,232 @@
2
2
 
3
3
  ## Introduction to Switchboard
4
4
 
5
- **Switchboard** is the API interface that allows developers and data engineers to get access to the data, that is being collected through the use of document models in Connect & Fusion.
6
- After structurally capturing the desired data of your formalised business processes the data can be used to build insightful experiences in external websites, drive widgets or create specific reports and dashboard in fusion.
5
+ **Switchboard** is the API interface that allows developers and data engineers to get access to data collected through document models in Connect and Fusion.
6
+ After structurally capturing the desired data from your formalized business processes, it can be used to build insightful experiences in external websites, drive widgets, or create specific reports and dashboards in Fusion.
7
7
 
8
- :::tip Using the state schema of your document
9
- Since your document models have been defined with a GraphQL schema, you can use the same objects and fields in your queries and mutations to retrieve or write data from and to your document models.
8
+ :::tip Using your document's state schema
9
+ Since your document models are defined with a GraphQL schema, you can use the same objects and fields in your queries and mutations to retrieve or write data from and to your documents.
10
10
  :::
11
11
 
12
12
  ## Querying a document with the GraphQL API
13
13
 
14
14
  ### Starting the reactor locally
15
15
 
16
- In this tutorial we'll show how to use a **GraphQL** query to query a document model. We'll **continue on the To-do List example** from our [introduction tutorial](/academy/GetStarted/CreateNewPowerhouseProject) , but the process can be applied to any other document model.
17
- To make our document model available in the Apollo Studio Sandbox we'll need to store it on a remote [Reactor](/academy/Architecture/WorkingWithTheReactor).
16
+ In this tutorial, we'll show how to use a **GraphQL** query to query a document model. We'll continue with the **To-do List example** from our [introduction tutorial](/academy/GetStarted/CreateNewPowerhouseProject), but the process can be applied to any other document model.
17
+ To make our document model available in the Apollo Studio Sandbox, we'll need to store it on a remote [Reactor](/academy/Architecture/WorkingWithTheReactor).
18
18
 
19
19
  :::info What are reactors?
20
- **Powerhouse Reactors** are the nodes in the network that store documents, resolve conflicts and rerun operations to verify document event histories.
21
- Reactors can be configured for local storage, centralized cloud storage or on a decentralized storage network.
20
+ **Powerhouse Reactors** are the nodes in the network that store documents, resolve conflicts, and rerun operations to verify document event histories.
21
+ Reactors can be configured for local storage, centralized cloud storage, or a decentralized storage network.
22
22
  :::
23
23
 
24
- Just like we can run Connect locally in studio mode we can run a remote node or a Reactor locally.
25
- Use the following commands:
24
+ Just as you can run Connect locally in studio mode, you can also run a Reactor locally. Use the following command in the terminal from within your Powerhouse project directory:
26
25
 
27
26
  ```bash
28
27
  ph reactor
29
28
  ```
30
29
 
31
- To start both Connect and a Reactor locally at the same time in a Powerhouse project you can use the following command:
30
+ To start both Connect and a Reactor locally at the same time in a Powerhouse project, you can use the following command:
32
31
  ```bash
33
32
  ph dev
34
33
  ```
35
34
 
36
- It will return a url to access the Reactor.
35
+ This will return a URL to access the Reactor.
37
36
  ```bash
38
37
  [Reactor]: ➜ Reactor: http://localhost:4001/d/powerhouse
39
38
  ```
40
39
 
41
- ### Adding a remote drive or reactor to Connect
40
+ ### Adding a remote drive or Reactor to Connect
42
41
 
43
- If the remote drive or Reactor isn't present yet in connect you can add it by clicking the (+) button in the Connect drive navigation
44
- and using the localhost url to add a new drive with it's underlying reactor. Usually http://localhost:4001/d/powerhouse
42
+ If the remote drive or Reactor isn't present yet in Connect, you can add it by clicking the (+) button in the Connect drive navigation and using the localhost URL to add a new drive with its underlying reactor. Usually, this is http://localhost:4001/d/powerhouse.
45
43
 
46
- Get access to an **organisations drive** instances by adding their drive to your Connect Drive navigation tree view with the help of the correct drive url.
47
- Click the (+) to add a public drive. To add a new drive you'll have to know the correct public URL of the drive.
44
+ Get access to an **organization's drive** instances by adding their drive to your Connect Drive navigation tree view with the help of the correct drive URL.
45
+ Click the (+) to add a public drive. To add a new drive, you'll have to know the correct public URL of the drive. Read more about [configuring drives](/academy/Architecture/WorkingWithTheReactor).
48
46
 
49
- ## Querying the state of a document
47
+ <figure className="image-container">
48
+ <img src={require("./images/AddNewDriveURL.png").default} alt="Add a drive through an URL" />
49
+ <figcaption>The 'Add Drive' button that allows you to enter a Drive URL.</figcaption>
50
+ </figure>
50
51
 
51
- Now that we have our remote reactor and/or drive running we can store our document model on it.
52
- Let's quickly create a new to-do list document to test the process.
52
+ ## Query the state of a document
53
53
 
54
- Add to following todo's to your list:
54
+ Now that we have our remote reactor and/or drive running, we can store our document model on it.
55
+ Let's quickly create a new to-do list document in Connect Studio to test the process. Let's call it **'Powerhouse-onboarding-tasks'**.
56
+
57
+
58
+ Add the following to-dos to your list:
55
59
  - [ ] Sign up for Powerhouse
56
60
  - [ ] Do the work
57
61
  - [ ] Deliver the work
58
62
  - [ ] Send the invoice
59
63
  - [ ] Get paid
60
64
 
61
- Now that we have some data in our document model we can query it through the GraphQL API.
65
+ Below is the operation history of the to-do list document. As you can see, the operations are logged in the order they were executed.
66
+
67
+ <figure className="image-container">
68
+ <img src={require("./images/OnboardingTasks.png").default} alt="Operation history in Connect" />
69
+ <figcaption>The operation history of the to-do list document, showing each change made.</figcaption>
70
+ </figure>
71
+
72
+ Now that we have some data in our document model, we can query it through the GraphQL API.
73
+
74
+ ### Option 1: Query your document via the Switchboard API Button.
75
+
76
+ Whenever you want to start a query from a document within Connect, you can open Switchboard by clicking the Switchboard icon in the top right-hand corner of the document editor interface.
77
+ The Switchboard API button at the top of your document model will get you the complete state of your current document.
78
+ This will prepopulate the Apollo Studio Sandbox with the correct **DocumentID** for your document model.
62
79
 
63
- ### 1. The complete state of the document
80
+ <figure className="image-container">
81
+ <img src={require("./images/SwitchboardButton.png").default} alt="Switchboard button in document editor" />
82
+ <figcaption>The Switchboard button provides a direct link to the GraphQL API for the document.</figcaption>
83
+ </figure>
64
84
 
65
- Whenever you want to start a query from a document within connect you can open up Switchboard by looking for the Switchboard logo in the top right hand corner of the document editor interface.
66
- This will prepopulate the Apollo Studio Sandbox with the correct **DocumentID** for your document model. This feature will not be available for documents stored on local drives.
85
+ ### Option 2: Query your document by document ID
67
86
 
68
- ![Switchboardbutton](./images/SwitchboardButton.png)
87
+ In your Document Toolbar, you will find an icon to visit your operations history. At the top of the toolbar, you will find your document ID.
88
+ Copy this ID to use it in the Switchboard API.
69
89
 
70
- The documentation on the left hand side of the Apollo Sandbox will show you all of the different fields that are available to query.
90
+ <figure className="image-container">
91
+ <img src={require("./images/DocumentID.png").default} alt="Copy the DocumentID" />
92
+ <figcaption>You can copy your Document ID from your operations history.</figcaption>
93
+ </figure>
71
94
 
72
- ![document query](./images/QueryDocumentID.png)
95
+ When you navigate to your Switchboard endpoint (e.g., http://localhost:4001/graphql/system, https://switchboard.phd/graphql/system, or a custom domain), you can use this document ID to query the state of your document.
96
+ The documentation on the left-hand side of the Apollo Sandbox will show you all the different fields that are available to query.
73
97
 
74
- Alternatively we can just use our reactor url and endpoint to figure out the document id.
75
- We can find out what the id of our document is by querying the drive for it's documents.
76
- Since we only have one document in our drive it will return the id of our to-do list document.
98
+ <figure className="image-container">
99
+ <img src={require("./images/QueryDocumentID.png").default} alt="Apollo Studio with document query" />
100
+ <figcaption>The Apollo Studio Sandbox showing the available fields for querying a document.</figcaption>
101
+ </figure>
77
102
 
78
- This example query is structured to request a document by its unique identifier (id).
79
- It extracts common fields such as **id**, **name**, **documentType**, **revision**, **created**, and **lastModified**.
103
+ ### Option 3: Search for your document ID via GraphQL
104
+
105
+ **Alternatively**, we can use our Reactor URL and endpoint to figure out the document ID.
106
+ e.g., http://localhost:4001/graphql/system, https://switchboard.phd/graphql/system or your custom https://switchboard.domain/graphql/system
107
+
108
+ We can find out the ID of our document by querying the drive for its documents.
109
+ Since we only have one document in our drive, this query will return the ID of our to-do list document.
110
+
111
+ ```graphQL title="Document ID Query"
112
+ query Query {
113
+ ToDoList {
114
+ getDocuments {
115
+ id
116
+ name
117
+ documentType
118
+ revision
119
+ created
120
+ lastModified
121
+ }
122
+ }
123
+ }
124
+ ```
80
125
 
81
- In the above example we queried for the content of the operations. Let's compare the results with the document operation history.
82
- Side by side you can see the document content and the operation history.
126
+ This example query is structured to request all documents of type `ToDoList` from the drive.
127
+ It extracts common metadata fields such as **id**, **name**, **documentType**, **revision**, **created**, and **lastModified**.
83
128
 
84
- Below is the operation history of the todo list document. As you can see the operations are logged in the order they were executed.
85
- As you can see there is a 'Delete' operation in the history on revision 5 as we forgot to add 'Send the invoice' to our list.
86
- ![Operation History](./images/OperationHistory.png)
129
+ ### Get the state of the document
87
130
 
88
- Now let's query the content of the document using Apollo Studio Sandbox. The left sidebar shows the schema documentation, where you can explore all available fields and types for your document model.
131
+ Once you've found your document via any of the three options, you'll be able to query its state.
89
132
 
90
- For our To-do List document, let's construct a query that fetches the operations with the help of a nested operations field
133
+ In the previous step, we queried for document metadata. Now let's query for the actual content of the document state.
91
134
 
92
- ```graphql
93
- query {
94
- document(id: "...") {
95
- name
96
- documentType
97
- revision
98
- created
99
- lastModified
100
- ... on TodoList {
101
- operations {
102
- type
103
- id
104
- inputText
135
+ ```graphql title="Get the Document state"
136
+ query getDocument($documentId: PHID!, $driveId: String) {
137
+ ToDoList {
138
+ getDocument(docId: $documentId, driveId: $driveId) {
139
+ id
140
+ created
141
+ lastModified
142
+ name
143
+ revision
144
+ state {
145
+ items { id text checked } stats { total checked unchecked }
105
146
  }
106
147
  }
107
148
  }
108
149
  }
109
150
  ```
110
151
 
111
- This query will return all operations performed on the document, including ADD_TODO_ITEM and DELETE_TODO_ITEM operations, allowing us to see the complete history of changes.
152
+ ```graphql title="Example variables"
153
+ {
154
+ "documentId": "03eb6780-f1d7-438c-84a0-6d93dfb8f6af", // or replace this with your specific doc ID
155
+ "driveId": "powerhouse" // or replace this with your specific driveId
156
+ }
157
+ ```
158
+
159
+ This query will return the current state of the document, including all to-do items and stats.
160
+
161
+ <figure className="image-container">
162
+ <img src={require("./images/OperationsQuery.png").default} alt="Executing a mutation for a to-do item in Apollo Studio" />
163
+ <figcaption>The Apollo Studio Sandbox showing the <code>addTodoItem</code> mutation. You can see the variables passed in and the response from the server.</figcaption>
164
+ </figure>
165
+
166
+
167
+ ## Mutate the state of a document
168
+
169
+ Now that we know how to query the state of a document, we can start to write to it.
170
+
171
+ To perform write operations, we use **GraphQL Mutations**. Mutations are similar to queries, but they are used to create, update, or delete data. For our To-do List, we'll want to add, check, and remove items.
172
+
173
+ ### Adding a new to-do item
174
+
175
+ Let's start by adding a new item to our list. The document model for our to-do list has an `ADD_TODO_ITEM` operation, which translates to an `addTodoItem` mutation in GraphQL.
176
+ To use this mutation, you need to provide the `docId` of the to-do list you want to modify, and the `text` and `id` for the new to-do item. We'll specify these via variables.
177
+
178
+ Here is an example of how to structure the mutation:
179
+
180
+ ```graphql title="example-add-mutation"
181
+ mutation Mutation($docId: PHID, $input: ToDoList_AddTodoItemInput) {
182
+ ToDoList_addTodoItem(docId: $docId, input: $input)
183
+ }
184
+ ```
185
+
186
+ ```graphql title="example-variables"
187
+ {
188
+ "docId": "03eb6780-f1d7-438c-84a0-6d93dfb8f6af",
189
+ "input": {
190
+ "text": "My new to-do from GraphQL",
191
+ "id": "1"
192
+ }
193
+ }
194
+ ```
195
+
196
+ Replace the example `docId` with the actual ID of your document. You can get this ID by querying the drive as we did before.
197
+
198
+ When you execute this mutation in Apollo Studio, it will add the new item to your to-do list. The response will return the number of to-do's on your list.
199
+
200
+ ### Deleting a to-do item
201
+
202
+ To delete an item, you'll need its unique identifier. When you query for the to-do items in your list, each one will have an `id`. You'll use this `id` to specify which item to delete.
203
+
204
+ The document model provides a `DELETE_TODO_ITEM` operation, which corresponds to a `deleteTodoItem` mutation.
205
+
206
+ Here's how you can use it:
207
+ ```graphql title="example-delete-mutation"
208
+ mutation Mutation($docId: PHID, $input: ToDoList_DeleteTodoItemInput) {
209
+ ToDoList_deleteTodoItem(docId: $docId, input: $input)
210
+ }
211
+ ```
212
+
213
+ ```graphql title="example-variables"
214
+ {
215
+ "docId": "03eb6780-f1d7-438c-84a0-6d93dfb8f6af",
216
+ "input": {
217
+ "id": "0.6325811781889789"
218
+ }
219
+ }
220
+ ```
221
+
222
+ Make sure to replace the `docId` and `id` with the appropriate values for your document and the item you wish to delete.
223
+
224
+ After executing this mutation, the specified to-do item will be removed from your list.
225
+
226
+ ### Verifying the changes
227
+
228
+ After performing a write mutation, you can verify that the change was successful in a couple of ways:
112
229
 
113
- ## Writing to a document
230
+ 1. **Query the document state again:** Rerun the `getDocument` query from earlier in this tutorial. You should see the new item in the list or the deleted item removed.
231
+ 2. **Check the Operation History:** The operation history in Connect will show the new `ADD_TODO_ITEM` or `DELETE_TODO_ITEM` operation, along with who performed it and when. This provides a complete audit trail of all changes to the document.
114
232
 
115
- Now that we know how to query the state of a document we can start to write to it.
233
+ This ability to programmatically read from and write to documents via the GraphQL API is a powerful feature of Powerhouse. It unlocks countless possibilities for integrating your structured data into other applications, building automated workflows, and creating rich, data-driven user experiences.
@@ -7,7 +7,7 @@ An Analytics Processor is an object that can track analytics for operations and
7
7
  The `ph-cli` utility can be used to generate the scaffolding for an Analytics Processor.
8
8
 
9
9
  ```
10
- npx @powerhousedao/ph-cli generate --processor-type analytics --document-models ./my-document-models
10
+ ph generate -p MyAnalyticsProcessor --processor-type analytics
11
11
  ```
12
12
 
13
13
  This will generate two files: a class that implements `IProcessor` and a `ProcessorFactory` function that creates an instance of your processor. We can start with the factory.
@@ -340,3 +340,91 @@ export class DriveProcessorProcessor implements IProcessor {
340
340
  async onDisconnect() {}
341
341
  }
342
342
  ```
343
+
344
+ ## Learn by example: Contributor Billing
345
+
346
+ Here we have documented the entire development process for the contributor billing processor.
347
+
348
+ First, we setup the repository locally.
349
+
350
+ ```
351
+ $ git clone git@github.com:powerhouse-inc/contributor-billing.git
352
+ $ cd contributor-billing
353
+ ~/contributor-billing $ pnpm install
354
+ ```
355
+
356
+ Now we can generate an analytics processor, using default settings.
357
+
358
+ ```
359
+ ~/contributor-billing $ ph generate -p LineItemProcessor --processor-type analytics
360
+ ```
361
+
362
+ We can see what was generated:
363
+
364
+ ```
365
+ ~/contributor-billing $ tree processors
366
+ processors
367
+ ├── index.ts
368
+ └── line-item-processor
369
+ └── index.ts
370
+ ```
371
+
372
+ > Note that `processors/index.ts` will only be created if it does not already exist. In this case, you will be responsible for adding the processor to the `processorFactory` function.
373
+
374
+ ### `IProcessorFactory`
375
+
376
+ Let's check out the generated `index.ts` file.
377
+
378
+ ```ts
379
+ /**
380
+ * This is a scaffold file meant for customization.
381
+ * Delete the file and run the code generator again to have it reset
382
+ */
383
+
384
+ import { ProcessorRecord } from "document-drive/processors/types";
385
+ import { LineItemProcessorProcessor } from "./line-item-processor/index.js";
386
+
387
+ export const processorFactory =
388
+ (module: any) =>
389
+ (driveId: string): ProcessorRecord[] => {
390
+ return [
391
+ {
392
+ processor: new LineItemProcessorProcessor(module.analyticsStore),
393
+ filter: {
394
+ branch: ["main"],
395
+ documentId: ["*"],
396
+ scope: ["*"],
397
+ documentType: ["*"],
398
+ },
399
+ },
400
+ ];
401
+ };
402
+ ```
403
+
404
+ This is described in more detail in the [ProcessorFactory](#processorfactory) section, but for our purposes, we only want our processor to run for our document type, so we should change the filter's `documentType`.
405
+
406
+ ```ts
407
+ filter: {
408
+ branch: ["main"],
409
+ documentId: ["*"],
410
+ scope: ["*"],
411
+ documentType: ["powerhouse/billing-statement"],
412
+ },
413
+ ```
414
+
415
+ ### Data Design
416
+
417
+ Before we get into the meat of the processor, we need to design the data we're going to be working with.
418
+
419
+
420
+
421
+ ### `IProcessor`
422
+
423
+ Now we can open up `line-item-processor/index.ts` to add the custom logic we're looking for. This will be in the `onStrands` function.
424
+
425
+ ```ts
426
+
427
+ ```
428
+
429
+
430
+
@@ -27,11 +27,6 @@ Hook names must always start with `use` followed by a capital letter (e.g., `use
27
27
 
28
28
  It's important to note that a function should only be named and treated as a hook if it actually utilizes one or more built-in React hooks. If a function (even if named `useSomething`) doesn't call any built-in hooks, it behaves like a regular JavaScript function, and making it a "hook" offers no specific React advantages.
29
29
 
30
- For more details, see the official documentation and API references of React:
31
- - [Reusing Logic with Custom Hooks (react.dev)](https://react.dev/learn/reusing-logic-with-custom-hooks)
32
- - [Rules of Hooks (react.dev)](https://react.dev/reference/rules/rules-of-hooks)
33
- - [Powerhouse React Hooks API Reference](docs/academy/APIReferences/ReactHooks)
34
-
35
30
  </details>
36
31
 
37
32
  The idea is to make the usage of our hooks feel as simple and familiar as using `useState`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powerhousedao/academy",
3
- "version": "3.2.0-dev.5",
3
+ "version": "3.2.0-dev.7",
4
4
  "homepage": "https://powerhouse.academy",
5
5
  "repository": {
6
6
  "type": "git",
@@ -488,14 +488,20 @@ html[data-theme='dark'] .DocSearch-Hits > *:empty {
488
488
  }
489
489
 
490
490
  .image-container {
491
+ box-sizing: border-box;
491
492
  border: 1px solid var(--ifm-color-emphasis-300);
492
493
  border-radius: var(--ifm-card-border-radius);
493
- padding: 1rem;
494
+ padding: 0.5rem;
494
495
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
495
496
  margin-bottom: 1.5rem;
497
+ max-width: calc(var(--ifm-container-width-xl) - 2rem);
498
+ margin-left: auto;
499
+ margin-right: auto;
496
500
  }
497
501
 
498
502
  .image-container img {
503
+ width: 100%;
504
+ height: auto;
499
505
  border-radius: var(--ifm-card-border-radius);
500
506
  }
501
507