@powerhousedao/academy 3.3.0-dev.0 → 3.3.0-dev.2

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 3.3.0-dev.2 (2025-07-05)
2
+
3
+ ### 🩹 Fixes
4
+
5
+ - **academy:** graphql at powerhouse update ([fea4eae24](https://github.com/powerhouse-inc/powerhouse/commit/fea4eae24))
6
+
7
+ ### ❤️ Thank You
8
+
9
+ - Callme-T
10
+
11
+ ## 3.3.0-dev.1 (2025-07-04)
12
+
13
+ This was a version bump only for @powerhousedao/academy to align it with other projects, there were no code changes.
14
+
1
15
  ## 3.3.0-dev.0 (2025-07-02)
2
16
 
3
17
  ### 🚀 Features
@@ -98,7 +98,7 @@ import BrowserOnly from '@docusaurus/BrowserOnly';
98
98
  </h3>
99
99
  </div>
100
100
  <div className={styles.cardContent}>
101
- <a href="/academy/MasteryTrack/WorkWithData/ReadingAndWritingThroughTheAPI" className="path-button">Read & write through the API</a>
101
+ <a href="/academy/MasteryTrack/WorkWithData/UsingTheAPI" className="path-button">Read & write through the API</a>
102
102
  <a href="/academy/MasteryTrack/WorkWithData/WorkingWithSubgraphs" className="path-button">Create your own subgraph</a>
103
103
  <a href="/academy/MasteryTrack/WorkWithData/Analytics-Engine/intro" className="path-button">Use the analytics engine</a>
104
104
  </div>
@@ -66,7 +66,7 @@ You can also add a new remote drive to your Connect environment programmatically
66
66
  `bash
67
67
  ph reactor
68
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).
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/UsingSubgraphs).
70
70
  - Appropriate permissions to perform mutations.
71
71
  :::
72
72
 
@@ -143,6 +143,6 @@ This approach allows you to automate drive creation and integration with other s
143
143
  You've now experienced the use of GraphQL to modify or read data captured in Powerhouse for the first time.
144
144
  You can now either continue with:
145
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)
146
+ - Keep playing with data and the [Switchboard API](/academy/MasteryTrack/WorkWithData/UsingTheAPI)
147
147
 
148
148
  Enjoy!
@@ -1,9 +1,10 @@
1
1
  # GraphQL at Powerhouse
2
2
 
3
- In this section, we will cover **the core concepts of GraphQL with examples applied to the Powerhouse ecosystem**. More specifically, GraphQL is used as:
4
- - The **schema definition language (SDL)** for defining our document models and thereby self-documenting the API to the data model. It allows developers to define the structure and relationships of data in a strongly-typed format.
5
- - As the **query language in subgraphs**, which allow different services to expose and query structured data dynamically. Jump to the section [GraphQL and Subgraphs](/academy/MasteryTrack/WorkWithData/WorkingWithSubgraphs/GraphQLAndSubgraphs) to learn more about this.
3
+ In this section, we will cover **the core concepts of GraphQL with examples applied to the Powerhouse ecosystem**. GraphQL plays a fundamental role in defining document model data schemas, handling data access patterns, and enabling event-driven workflows within the Powerhouse ecosystem.
6
4
 
5
+ More specifically, GraphQL is used as:
6
+ - The **schema definition language (SDL)** for defining our document models and thereby self-documenting the API to the data model. It allows developers to define the structure and relationships of data in a strongly-typed format.
7
+ - As the **query language in subgraphs**, which allow different services to expose and query structured data dynamically.
7
8
 
8
9
  ### Why GraphQL?
9
10
 
@@ -152,5 +153,132 @@ When dealing with lists of data, GraphQL employs a pattern that includes:
152
153
  ```
153
154
 
154
155
  ---
156
+
157
+ ## GraphQL Subgraphs in Powerhouse
158
+
159
+ Powerhouse structures its data into **subgraphs**, which are modular GraphQL services that connect to the Reactor (Powerhouse's core data infrastructure) or Operational Data Stores fueled by data from processors. Each subgraph has its own SDL, ensuring modularity and flexibility while working within the ecosystem.
160
+
161
+ ### Fetching data from the Reactor
162
+
163
+ Powerhouse uses GraphQL to expose system-level data, such as drives, users, and operational records through the **System Subgraph**, which allows querying of drives, stored files and folders.
164
+
165
+ ### Operational data stores
166
+
167
+ Custom subgraphs can be created to store and retrieve operational data in real time. For example, a subgraph can track file uploads and expose this data via GraphQL queries:
168
+
169
+ ```graphql title="File Schema Example"
170
+ type File {
171
+ id: ID!
172
+ name: String!
173
+ size: Int!
174
+ createdAt: DateTime!
175
+ }
176
+
177
+ type Query {
178
+ getFile(id: ID!): File
179
+ }
180
+ ```
181
+
182
+ This schema ensures that every File entity has an ID, name, size, and timestamp, providing a structured approach to file management data.
183
+
184
+ ---
185
+
186
+ ## CQRS Architecture with GraphQL
187
+
188
+ Powerhouse uses **CQRS (Command Query Responsibility Segregation)** to separate write operations (commands) from read operations (queries). This improves system scalability and flexibility:
189
+
190
+ - **GraphQL Queries** handle read operations, retrieving structured data efficiently
191
+ - **GraphQL Mutations** handle write operations, modifying the state in a controlled manner
192
+
193
+ Powerhouse's subgraphs act as the read layer, while processors handle write operations into operational data stores. This prevents conflicts between querying and modifying data.
194
+
195
+ | Layer | Role | GraphQL Usage | Implementation |
196
+ | --- | --- | --- | --- |
197
+ | Write Model (Commands) | Handles state changes (adding, modifying, deleting) | GraphQL Mutations | Processor |
198
+ | Read Model (Queries) | Optimized for fetching/reading/retrieving data | GraphQL Queries | Subgraph |
199
+
200
+ ### Read and write separation
201
+
202
+ **Read Model (Query)**
203
+ - Optimized for data retrieval
204
+ - Structured using GraphQL Queries
205
+ - Aggregates and exposes data via a subgraph
206
+ - Pulls data from Operational Data Stores, Analytics Stores, and Reactor
207
+ - Subgraphs do not directly modify the data—they only expose pre-processed information
208
+
209
+ ```graphql title="Example Query Operation"
210
+ query {
211
+ getFile(id: "123") {
212
+ name
213
+ size
214
+ createdAt
215
+ }
216
+ }
217
+ ```
218
+
219
+ **Write Model (Mutation)**
220
+ - Handles state changes (adding, modifying, deleting)
221
+ - Structured using GraphQL Mutations
222
+ - Writes data to Operational Data Stores
223
+
224
+ ```graphql title="Example Mutation Operation"
225
+ mutation {
226
+ createFile(name: "document.pdf", size: 1024) {
227
+ id
228
+ name
229
+ createdAt
230
+ }
231
+ }
232
+ ```
233
+
234
+ ---
235
+
236
+ ## GraphQL and Event-Driven Architecture
237
+
238
+ Event-Driven Architecture (EDA) enables asynchronous processing where events trigger actions. Powerhouse uses GraphQL to expose real-time event data from its Reactor and Operational Data Stores.
239
+
240
+ ### How GraphQL fits into EDA
241
+
242
+ - **Real-Time Data Exposure** – Subgraphs fetch event-based data updates
243
+ - **Event Subscription Mechanism** – Powerhouse is working towards integrating GraphQL Subscriptions for real-time updates
244
+ - **Efficient Decoupling** – Events are stored in an operational datastore, and GraphQL queries retrieve structured results
245
+
246
+ ### Example: Powerhouse's event flow
247
+
248
+ 1. Processor detects an event (e.g., file upload)
249
+ 2. Writes event data to the Operational Data Store
250
+ 3. Subgraph exposes the updated data via GraphQL
251
+
252
+ ---
253
+
254
+ ## GraphQL Subscriptions
255
+
256
+ Although Powerhouse currently uses queries and mutations, **GraphQL Subscriptions** could allow real-time streaming of event-based data in future implementations:
257
+
258
+ ```graphql title="Example Future Subscription"
259
+ subscription {
260
+ fileUploaded {
261
+ id
262
+ name
263
+ size
264
+ createdAt
265
+ }
266
+ }
267
+ ```
268
+
269
+ This would enable clients to listen for new file uploads without polling, providing a more efficient real-time experience.
270
+
271
+ ---
272
+
155
273
  ## Summary
156
- GraphQL offers a streamlined and efficient approach to data retrieval, particularly useful when you need granular control over your API interactions. By defining a robust schema, using precise fields and arguments, and leveraging introspection, GraphQL minimizes unnecessary data transfers. If you want to learn more about GraphQL, there is the following link to the official documentation: [Introduction to GraphQL](https://graphql.org/learn/).
274
+
275
+ GraphQL offers a streamlined and efficient approach to data retrieval, particularly useful when you need granular control over your API interactions. In the Powerhouse ecosystem, GraphQL serves multiple critical functions:
276
+
277
+ - **Schema Definition**: Defines document models and self-documents APIs
278
+ - **Subgraph Architecture**: Enables modular, scalable data services
279
+ - **CQRS Implementation**: Separates read and write operations for better performance
280
+ - **Event-Driven Integration**: Supports real-time data exposure and future subscription capabilities
281
+
282
+ By defining robust schemas, using precise fields and arguments, leveraging introspection, and implementing subgraphs with CQRS principles, GraphQL minimizes unnecessary data transfers while maximizing flexibility and scalability in the Powerhouse platform.
283
+
284
+ For more information about GraphQL fundamentals, visit the [Introduction to GraphQL](https://graphql.org/learn/) documentation.
@@ -1,9 +1,10 @@
1
- # Read and write through the API
1
+ # Using the API
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 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.
5
+ **Switchboard** is the API interface that enables developers and data engineers to access data captured through document models in Connect and Fusion.
6
+
7
+ Once you've structured and captured data from your business processes, Switchboard allows you to leverage that data to build insightful experiences in external websites, create interactive drive widgets, or generate detailed reports and dashboards in Fusion.
7
8
 
8
9
  :::tip Using your document's state schema
9
10
  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.
@@ -39,10 +40,10 @@ This will return a URL to access the Reactor.
39
40
 
40
41
  ### Adding a remote drive or Reactor to Connect
41
42
 
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.
43
+ If the remote drive or Reactor isn't present yet in Connect, you can add it by clicking the (+) 'Create New Drive' 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.
43
44
 
44
45
  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).
46
+ Click the (+) 'Create New Drive' 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).
46
47
 
47
48
  <figure className="image-container">
48
49
  <img src={require("./images/AddNewDriveURL.png").default} alt="Add a drive through an URL" />
@@ -92,7 +93,7 @@ Copy this ID to use it in the Switchboard API.
92
93
  <figcaption>You can copy your Document ID from your operations history.</figcaption>
93
94
  </figure>
94
95
 
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
+ When you navigate to your Switchboard endpoint by adding **`/graphql/system`** to the end of your URL. (e.g., http://localhost:4001/graphql/system, https://switchboard.phd/graphql/system, or add it to a custom domain), you can use this document ID to query the state of your document.
96
97
  The documentation on the left-hand side of the Apollo Sandbox will show you all the different fields that are available to query.
97
98
 
98
99
  <figure className="image-container">
@@ -128,7 +129,7 @@ It extracts common metadata fields such as **id**, **name**, **documentType**, *
128
129
 
129
130
  ### Get the state of the document
130
131
 
131
- Once you've found your document via any of the three options, you'll be able to query its state.
132
+ Once you've found your document via any of the three options above, you'll be able to query its state.
132
133
 
133
134
  In the previous step, we queried for document metadata. Now let's query for the actual content of the document state.
134
135
 
@@ -230,4 +231,7 @@ After performing a write mutation, you can verify that the change was successful
230
231
  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
232
  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.
232
233
 
234
+
235
+ ### Summary
236
+
233
237
  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.
@@ -0,0 +1,649 @@
1
+ # Using Subgraphs
2
+
3
+ This tutorial will demonstrate how to create and customize a subgraph using our To-do List project as an example.
4
+ Let's start with the basics and gradually add more complex features and functionality.
5
+
6
+ ## What is a subgraph?
7
+
8
+ A subgraph in Powerhouse is a **GraphQL-based modular data component** that extends the functionality of your document models. While document models handle the core state and operations, subgraphs can:
9
+ 1. Connect to external APIs or databases
10
+ 2. Add custom queries and mutations
11
+ 3. Automate interactions between different document models
12
+ 4. Provide additional backend functionality
13
+
14
+ ### Subgraphs can retrieve data from
15
+
16
+ - **The Reactor** – The core Powerhouse data system or network node.
17
+ - **Operational Data Stores** – Structured data storage for operational processes, offering real-time updates, for querying structured data.
18
+ - **Analytics Stores** – Aggregated historical data, useful for insights, reporting and business intelligence.
19
+
20
+ ### Subgraphs consist of
21
+
22
+ - **A schema** – Which defines the GraphQL Queries and Mutations.
23
+ - **Resolvers** – Which handle data fetching and logic.
24
+ - **Context Fields** – Additional metadata that helps in resolving data efficiently.
25
+
26
+ #### Additionally, context fields allow resolvers to access extra information, such as:
27
+ - **User authentication** (e.g., checking if a user is an admin).
28
+ - **External data sources** (e.g., analytics).
29
+
30
+
31
+
32
+ ```typescript title="Example of a context field"
33
+ context: {
34
+ admin: async (session) => {
35
+ const admins = await operationalStore.get("admins");
36
+ return admins.includes(session.user);
37
+ }
38
+ }
39
+ ```
40
+
41
+ ## 1. How to generate a subgraph
42
+
43
+ Lets start by generating a new subgraph. For our tutorial we will create a new subgraph within our To-do List project.
44
+ Open your project and start your terminal.
45
+ The Powerhouse toolkit provides a command-line utility to create new subgraphs easily.
46
+
47
+ ```bash title="Run the following command to generate a new subgraph"
48
+ ph generate --subgraph <to-do-list-subgraph>
49
+ ```
50
+
51
+ ```bash title="Expected Output"
52
+ Loaded templates: node_modules/@powerhousedao/codegen/dist/codegen/.hygen/templates
53
+ FORCED: ./subgraphs/to-do-list-subgraph/index.ts
54
+ skipped: ./subgraphs/index.ts
55
+ inject: ./subgraphs/index.ts
56
+ ```
57
+
58
+ ### What happened?
59
+ 1. A new subgraph was created in `./subgraphs/to-do-list-subgraph/`
60
+ 2. The subgraph was automatically registered in your project's registry
61
+ 3. Basic boilerplate code was generated with an example query
62
+
63
+ If we now run `ph reactor` we will see the new subgraph being registered during the startup of the Reactor.
64
+ > Registered /todolist subgraph.
65
+
66
+ Alternatively, when you are running a local reactor with `ph reactor` a series of subgraphs will automatically get registered, amongst those one for the available document models in your Powerhouse project.
67
+
68
+ ```
69
+ Initializing Subgraph Manager...
70
+ > Registered /graphql/auth subgraph.
71
+ > Registered /graphql/system subgraph.
72
+ > Registered /graphql/analytics subgraph.
73
+ > Registered /d/:drive subgraph.
74
+ > Updating router
75
+ > Registered /graphql supergraph
76
+ > Registered /graphql/to-do-list subgraph.
77
+ > Updating router
78
+ > Registered /graphql supergraph
79
+ ➜ Reactor: http://localhost:4001/d/powerhouse
80
+ ```
81
+
82
+ ## 2. Building a To-do List Subgraph
83
+
84
+ Now that we've generated our subgraph, let's build a complete To-do List subgraph that extends the functionality of our To-do List document model. This subgraph will provide additional querying capabilities and demonstrate how subgraphs work with document models.
85
+
86
+ ### 2.1 Understanding the To-do List Document Model
87
+
88
+ Before building our subgraph, let's recall the structure of our To-do List document model from the [DocumentModelCreation tutorial](/academy/MasteryTrack/DocumentModelCreation/SpecifyTheStateSchema):
89
+
90
+ ```graphql
91
+ type ToDoListState {
92
+ items: [ToDoItem!]!
93
+ stats: ToDoListStats!
94
+ }
95
+
96
+ type ToDoItem {
97
+ id: ID!
98
+ text: String!
99
+ checked: Boolean!
100
+ }
101
+
102
+ type ToDoListStats {
103
+ total: Int!
104
+ checked: Int!
105
+ unchecked: Int
106
+ }
107
+ ```
108
+
109
+ The document model has these operations:
110
+ - `ADD_TODO_ITEM`: Adds a new to-do item
111
+ - `UPDATE_TODO_ITEM`: Updates an existing to-do item
112
+ - `DELETE_TODO_ITEM`: Deletes a to-do item
113
+
114
+ ### 2.2 Define the Subgraph Schema
115
+
116
+ Now let's create a subgraph that provides enhanced querying capabilities for our To-do List documents.
117
+
118
+ **Step 1: Define the schema in `subgraphs/to-do-list/schema.ts`:**
119
+
120
+ ```typescript
121
+ export const typeDefs = `
122
+ type Query {
123
+ todoList: TodoListSummary
124
+ todoItems(checked: Boolean): [TodoItem!]!
125
+ todoItemsCount(checked: Boolean): Int!
126
+ }
127
+
128
+ type TodoListSummary {
129
+ total: Int!
130
+ checked: Int!
131
+ unchecked: Int!
132
+ }
133
+
134
+ type TodoItem {
135
+ id: ID!
136
+ text: String!
137
+ checked: Boolean!
138
+ }
139
+ `;
140
+ ```
141
+
142
+ **Step 2: Create resolvers in `subgraphs/to-do-list/resolvers.ts`:**
143
+
144
+ ```typescript
145
+ // subgraphs/to-do-list/resolvers.ts
146
+ // subgraphs/to-do-list/resolvers.ts
147
+ interface SubgraphInstance {
148
+ operationalStore: any;
149
+ }
150
+
151
+ export const createResolvers = (subgraphInstance: SubgraphInstance) => ({
152
+ Query: {
153
+ todoList: async () => {
154
+ const items = await subgraphInstance.operationalStore.getAll("todo_items");
155
+ const total = items.length;
156
+ const checked = items.filter((item: any) => item.checked).length;
157
+ const unchecked = total - checked;
158
+
159
+ return {
160
+ total,
161
+ checked,
162
+ unchecked
163
+ };
164
+ },
165
+
166
+ todoItems: async (parent: any, { checked }: any) => {
167
+ let query = subgraphInstance.operationalStore.select("*").from("todo_items");
168
+
169
+ if (checked !== undefined) {
170
+ query = query.where("checked", checked);
171
+ }
172
+
173
+ const items = await query.orderBy("created_at", "asc");
174
+ return items;
175
+ },
176
+
177
+ todoItemsCount: async (parent: any, { checked }: any) => {
178
+ let query = subgraphInstance.operationalStore.count("* as count").from("todo_items");
179
+
180
+ if (checked !== undefined) {
181
+ query = query.where("checked", checked);
182
+ }
183
+
184
+ const result = await query.first();
185
+ return result?.count || 0;
186
+ }
187
+ }
188
+ });
189
+ ```
190
+
191
+ **Step 3: Implement the main class in `subgraphs/to-do-list/index.ts`:**
192
+
193
+ ```typescript
194
+ // subgraphs/to-do-list/index.ts
195
+ import { typeDefs } from './schema.js';
196
+ import { createResolvers } from './resolvers.js';
197
+
198
+ export default class ToDoListSubgraph {
199
+ path = '/to-do-list';
200
+
201
+ typeDefs = typeDefs;
202
+ resolvers: any;
203
+ operationalStore: any;
204
+
205
+ constructor() {
206
+ this.resolvers = createResolvers(this);
207
+ }
208
+
209
+ async onSetup() {
210
+ await this.createOperationalTables();
211
+ }
212
+
213
+ async createOperationalTables() {
214
+ await this.operationalStore.schema.createTableIfNotExists(
215
+ "todo_items",
216
+ (table: any) => {
217
+ table.string("id").primary();
218
+ table.string("text").notNullable();
219
+ table.boolean("checked").defaultTo(false);
220
+ table.timestamp("created_at").defaultTo(this.operationalStore.fn.now());
221
+ table.timestamp("updated_at").defaultTo(this.operationalStore.fn.now());
222
+ }
223
+ );
224
+ }
225
+
226
+ async process(event: any) {
227
+ // Handle To-do List document operations
228
+ if (event.type === "ADD_TODO_ITEM") {
229
+ await this.operationalStore.insert("todo_items", {
230
+ id: event.input.id,
231
+ text: event.input.text,
232
+ checked: false,
233
+ created_at: new Date(),
234
+ updated_at: new Date()
235
+ });
236
+
237
+ console.log(`Added todo item: ${event.input.text}`);
238
+ }
239
+
240
+ if (event.type === "UPDATE_TODO_ITEM") {
241
+ const updateData: any = {
242
+ updated_at: new Date()
243
+ };
244
+
245
+ // Only update fields that were provided
246
+ if (event.input.text !== undefined) {
247
+ updateData.text = event.input.text;
248
+ }
249
+ if (event.input.checked !== undefined) {
250
+ updateData.checked = event.input.checked;
251
+ }
252
+
253
+ await this.operationalStore.update("todo_items")
254
+ .where("id", event.input.id)
255
+ .update(updateData);
256
+
257
+ console.log(`Updated todo item: ${event.input.id}`);
258
+ }
259
+
260
+ if (event.type === "DELETE_TODO_ITEM") {
261
+ await this.operationalStore.delete("todo_items")
262
+ .where("id", event.input.id);
263
+
264
+ console.log(`Deleted todo item: ${event.input.id}`);
265
+ }
266
+ }
267
+ }
268
+ ```
269
+
270
+ **What this schema provides:**
271
+ - `todoList`: Returns statistics about all to-do items (total, checked, unchecked counts)
272
+ - `todoItems`: Returns a list of to-do items, optionally filtered by checked status
273
+ - `todoItemsCount`: Returns just the count of items, optionally filtered by checked status
274
+
275
+ ### 2.3 Understanding the Implementation
276
+
277
+ **What this multi-file approach provides:**
278
+
279
+ 1. **Schema separation** (`schema.ts`): Clean GraphQL type definitions
280
+ 2. **Resolver isolation** (`resolvers.ts`): Business logic separated from structure
281
+ 3. **Main orchestration** (`index.ts`): Combines everything and handles lifecycle methods
282
+
283
+ **Key features implemented:**
284
+ - A `todo_items` operational table to store individual to-do items
285
+ - Fields that match our document model structure
286
+ - Timestamps for tracking when items were created and updated
287
+ - Resolvers that fetch and filter todo items from the operational store
288
+ - Event processing to keep the subgraph data synchronized with document model changes
289
+
290
+ ### 2.4 Connect to Document Model Events (Processor Integration)
291
+
292
+ To make our subgraph truly useful, we need to connect it to the actual To-do List document model events. This ensures that when users interact with To-do List documents through Connect, the subgraph data stays synchronized.
293
+
294
+ Add this processor integration to your subgraph:
295
+
296
+ ```typescript
297
+ async process(event) {
298
+ // Handle To-do List document operations
299
+ if (event.type === "ADD_TODO_ITEM") {
300
+ await this.operationalStore.insert("todo_items", {
301
+ id: event.input.id,
302
+ text: event.input.text,
303
+ checked: false,
304
+ created_at: new Date(),
305
+ updated_at: new Date()
306
+ });
307
+
308
+ console.log(`Added todo item: ${event.input.text}`);
309
+ }
310
+
311
+ if (event.type === "UPDATE_TODO_ITEM") {
312
+ const updateData = {
313
+ updated_at: new Date()
314
+ };
315
+
316
+ // Only update fields that were provided
317
+ if (event.input.text !== undefined) {
318
+ updateData.text = event.input.text;
319
+ }
320
+ if (event.input.checked !== undefined) {
321
+ updateData.checked = event.input.checked;
322
+ }
323
+
324
+ await this.operationalStore.update("todo_items")
325
+ .where("id", event.input.id)
326
+ .update(updateData);
327
+
328
+ console.log(`Updated todo item: ${event.input.id}`);
329
+ }
330
+
331
+ if (event.type === "DELETE_TODO_ITEM") {
332
+ await this.operationalStore.delete("todo_items")
333
+ .where("id", event.input.id);
334
+
335
+ console.log(`Deleted todo item: ${event.input.id}`);
336
+ }
337
+ }
338
+ ```
339
+
340
+ **What this processor does:**
341
+ - Listens for document model operations (`ADD_TODO_ITEM`, `UPDATE_TODO_ITEM`, `DELETE_TODO_ITEM`)
342
+ - Updates the operational store in real-time when these operations occur
343
+ - Provides console logging for debugging
344
+ - Maintains data consistency between the document model and the subgraph
345
+
346
+ ### 2.5 Summary of What We've Built
347
+
348
+ - **Added two main queries**: `todoList` for statistics and `todoItems` for item lists
349
+ - **Created an operational table** `todo_items` to store the todo items with proper schema
350
+ - **Added resolvers** to fetch and filter todo items from the operational store
351
+ - **Implemented event processing** to keep the subgraph data synchronized with document model changes
352
+ - **The todoItems query accepts an optional checked parameter** to filter items by their completion status
353
+ - **The todoList query returns the full statistics** including total, checked, and unchecked counts
354
+
355
+ ## 3. Testing the To-do List Subgraph
356
+
357
+ ### 3.1. Start the reactor
358
+ To activate the subgraph, run:
359
+
360
+ ```bash
361
+ ph reactor
362
+ ```
363
+ Or, for full system startup:
364
+
365
+ ```bash title="Start the Reactor & Connect in Studio or Locally"
366
+ ph dev
367
+ ```
368
+
369
+ You should see the subgraph being registered in the console output:
370
+ ```
371
+ > Registered /graphql/to-do-list subgraph.
372
+ ```
373
+
374
+ ### 3.2. Create some test data
375
+ Before testing queries, let's create some To-do List documents with test data:
376
+
377
+ 1. Open Connect at `http://localhost:3001`
378
+ 2. Add the 'remote' drive that is running locally via the (+) 'Add Drive' button. Add 'http://localhost:4001/d/powerhouse'
379
+ 3. Create a new To-do List document
380
+ 4. Add some test items:
381
+ - "Learn about subgraphs" (leave unchecked)
382
+ - "Build a To-do List subgraph" (mark as checked)
383
+ - "Test the subgraph" (leave unchecked)
384
+
385
+ ### 3.3. Access GraphQL playground
386
+ Open your browser and go to:
387
+
388
+ ```bash
389
+ http://localhost:4001/graphql/to-do-list
390
+ ```
391
+
392
+ ### 3.4. Test the queries
393
+
394
+ **Query 1: Get To-do List statistics**
395
+ ```graphql
396
+ query {
397
+ todoList {
398
+ total
399
+ checked
400
+ unchecked
401
+ }
402
+ }
403
+ ```
404
+
405
+ **Query 2: Get all to-do items**
406
+ ```graphql
407
+ query {
408
+ todoItems {
409
+ id
410
+ text
411
+ checked
412
+ }
413
+ }
414
+ ```
415
+
416
+ **Query 3: Get only unchecked items**
417
+ ```graphql
418
+ query {
419
+ todoItems(checked: false) {
420
+ id
421
+ text
422
+ checked
423
+ }
424
+ }
425
+ ```
426
+
427
+ **Query 4: Get count of completed items**
428
+ ```graphql
429
+ query {
430
+ todoItemsCount(checked: true)
431
+ }
432
+ ```
433
+
434
+ ### 3.5. Expected responses
435
+
436
+ **For the statistics query:**
437
+ ```json
438
+ {
439
+ "data": {
440
+ "todoList": {
441
+ "total": 3,
442
+ "checked": 1,
443
+ "unchecked": 2
444
+ }
445
+ }
446
+ }
447
+ ```
448
+
449
+ **For the items query:**
450
+ ```json
451
+ {
452
+ "data": {
453
+ "todoItems": [
454
+ {
455
+ "id": "item-1",
456
+ "text": "Learn about subgraphs",
457
+ "checked": false
458
+ },
459
+ {
460
+ "id": "item-2",
461
+ "text": "Build a To-do List subgraph",
462
+ "checked": true
463
+ },
464
+ {
465
+ "id": "item-3",
466
+ "text": "Test the subgraph",
467
+ "checked": false
468
+ }
469
+ ]
470
+ }
471
+ }
472
+ ```
473
+
474
+ ### 3.6. Test real-time updates
475
+
476
+ To verify that your subgraph stays synchronized with document changes:
477
+
478
+ 1. Keep the GraphQL playground open
479
+ 2. In another tab, open your To-do List document in Connect
480
+ 3. Add a new item or check/uncheck an existing item
481
+ 4. Return to the GraphQL playground and re-run your queries
482
+ 5. You should see the updated data immediately
483
+
484
+ This demonstrates the real-time synchronization between the document model and the subgraph through event processing.
485
+
486
+ ## 4. Working with the supergraph or gateway
487
+
488
+ A supergraph is a GraphQL schema that combines multiple underlying GraphQL APIs, known as subgraphs, into a single, unified graph. This architecture allows different teams to work independently on their respective services (subgraphs) while providing a single entry point for clients or users to query all available data
489
+
490
+ ### 4.1 Key concepts
491
+
492
+ * **Subgraph:** An independent GraphQL service with its own schema. Each subgraph typically represents a specific domain or microservice within a larger system.
493
+ * **Gateway/Router:** A server that sits in front of the subgraphs. It receives client queries, consults the supergraph schema, and routes parts of the query to the relevant subgraphs. It then stitches the results back together before sending the final response to the client.
494
+
495
+ ### 4.2 Benefits of using a supergraph
496
+
497
+ * **Federated Architecture:** Enables a microservices-based approach where different teams can own and operate their services independently.
498
+ * **Scalability:** Individual subgraphs can be scaled independently based on their specific needs.
499
+ * **Improved Developer Experience:** Clients interact with a single, consistent GraphQL API, simplifying data fetching and reducing the need to manage multiple endpoints.
500
+ * **Schema Evolution:** Subgraphs can evolve their schemas independently, and the supergraph can be updated without breaking existing clients, as long as breaking changes are managed carefully.
501
+ * **Clear Separation of Concerns:** Each subgraph focuses on a specific domain, leading to more maintainable and understandable codebases.
502
+
503
+
504
+ ### 4.3 Use the Powerhouse supergraph
505
+
506
+ The Powerhouse supergraph for any given remote drive or reactor can be found under `http://localhost:4001/graphql`. The gateway / supergraph available on `/graphql` combines all the subgraphs, except for the drive subgraph (which is accessible via `/d/:driveId`). To get to the endpoint open your localhost by starting the reactor and adding `graphql` to the end of the url. The following commands explain how you can test & try the supergraph.
507
+
508
+ - Start the reactor:
509
+
510
+ ```bash
511
+ ph reactor
512
+ ```
513
+
514
+ - Open the GraphQL editor in your browser:
515
+
516
+ ```
517
+ http://localhost:4001/graphql
518
+ ```
519
+
520
+ The supergraph allows to both query & mutate data from the same endpoint.
521
+
522
+ **Example: Using the supergraph with To-do List documents**
523
+
524
+ 1. Create a todo document in the `powerhouse` drive using the `ToDoList_createDocument` mutation:
525
+ ```graphql
526
+ mutation {
527
+ ToDoList_createDocument(
528
+ input: {
529
+ documentId: "my-todo-list"
530
+ name: "My Test To-do List"
531
+ }
532
+ ) {
533
+ id
534
+ name
535
+ }
536
+ }
537
+ ```
538
+
539
+ 2. Add some items to your to-do list using the `ToDoList_addTodoItem` mutation:
540
+ ```graphql
541
+ mutation {
542
+ ToDoList_addTodoItem(
543
+ docId: "my-todo-list"
544
+ input: {
545
+ id: "item-1"
546
+ text: "Learn about supergraphs"
547
+ }
548
+ )
549
+ }
550
+ ```
551
+
552
+ 3. Query the document state using the `GetDocument` query:
553
+ ```graphql
554
+ query {
555
+ ToDoList {
556
+ getDocument(docId: "my-todo-list") {
557
+ id
558
+ name
559
+ state {
560
+ items {
561
+ id
562
+ text
563
+ checked
564
+ }
565
+ stats {
566
+ total
567
+ checked
568
+ unchecked
569
+ }
570
+ }
571
+ }
572
+ }
573
+ }
574
+ ```
575
+
576
+ 4. Now query the same data through your subgraph (which should be included in the supergraph):
577
+ ```graphql
578
+ query {
579
+ todoList {
580
+ total
581
+ checked
582
+ unchecked
583
+ }
584
+ todoItems {
585
+ id
586
+ text
587
+ checked
588
+ }
589
+ }
590
+ ```
591
+
592
+ This demonstrates how the supergraph provides a unified interface to both your document models and your custom subgraphs, allowing you to query and mutate data from the same endpoint.
593
+
594
+ ## 5. Summary
595
+
596
+ Congratulations! You've successfully built a complete To-do List subgraph that demonstrates the power of extending document models with custom GraphQL functionality. Let's recap what you've accomplished:
597
+
598
+ ### What you built:
599
+ - **A custom GraphQL schema** that provides enhanced querying capabilities for To-do List documents
600
+ - **An operational data store** that efficiently stores and retrieves to-do items
601
+ - **Real-time event processing** that keeps your subgraph synchronized with document model changes
602
+ - **Advanced query capabilities** including filtering and counting operations
603
+ - **Integration with the supergraph** for unified API access
604
+
605
+ ### Key concepts learned:
606
+ - **Subgraphs extend document models** with additional querying and data processing capabilities
607
+ - **Operational data stores** provide efficient storage for subgraph data
608
+ - **Event processing** enables real-time synchronization between document models and subgraphs
609
+ - **The supergraph** unifies multiple subgraphs into a single GraphQL endpoint
610
+
611
+ ### Next steps:
612
+ - Explore adding **mutations** to your subgraph for more complex operations
613
+ - Implement **data aggregation** for analytics and reporting
614
+ - Connect to **external APIs** for enhanced functionality
615
+ - Build **processors** that automate workflows between different document models
616
+
617
+ This tutorial has provided you with a solid foundation for building sophisticated data processing and querying capabilities in the Powerhouse ecosystem.
618
+
619
+ ## Subgraphs are particularly useful for
620
+
621
+ 1. **Cross-Document Interactions**: For example, connecting a To-do List with an Invoice document model:
622
+ - When an invoice-related task is marked complete, update the invoice status
623
+ - When an invoice is paid, automatically check off related tasks
624
+
625
+ 2. **External Integrations**:
626
+ - Sync tasks with external project management tools
627
+ - Connect with notification systems
628
+ - Integrate with analytics platforms
629
+
630
+ 3. **Custom Business Logic**:
631
+ - Implement complex task prioritization
632
+ - Add automated task assignments
633
+ - Create custom reporting functionality
634
+
635
+ ### Prebuilt subgraphs
636
+
637
+ Some subgraphs (e.g., System Subgraph, Drive Subgraph) already exist.
638
+ To integrate with them, register them via the Reactor API.
639
+
640
+ ### Future enhancements
641
+
642
+ Bridge Processors and Subgraphs – Currently, there's a gap in how processors and subgraphs interact. Powerhouse might improve this in future updates.
643
+
644
+
645
+
646
+
647
+
648
+
649
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powerhousedao/academy",
3
- "version": "3.3.0-dev.0",
3
+ "version": "3.3.0-dev.2",
4
4
  "homepage": "https://powerhouse.academy",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,7 +25,7 @@ const FeatureList: FeatureItem[] = [
25
25
  {
26
26
  title: "Switchboard",
27
27
  imageSrc: require("@site/static/img/switchboard.png").default,
28
- docPath: "/docs/academy/MasteryTrack/WorkWithData/ReadingAndWritingThroughTheAPI",
28
+ docPath: "/docs/academy/MasteryTrack/WorkWithData/UsingTheAPI",
29
29
  description: <>Get access to the open API interface with Switchboard</>,
30
30
  },
31
31
  {
@@ -200,7 +200,7 @@ export default function HomepageFeatures() {
200
200
  <h3 className={styles.cardTitle}>Work with Data</h3>
201
201
  </div>
202
202
  <div className={styles.cardContent}>
203
- <a href="//docs/academy/MasteryTrack/WorkWithData/ReadingAndWritingThroughTheAPI" className={styles.pathButton}>Reading & Writing through the API</a>
203
+ <a href="//docs/academy/MasteryTrack/WorkWithData/UsingTheAPI" className={styles.pathButton}>Reading & Writing through the API</a>
204
204
  <a href="/docs/academy/MasteryTrack/WorkWithData/WorkingWithSubgraphs" className={styles.pathButton}>Create your own Subgraph</a>
205
205
  <a href="/docs/academy/WorkWithData/Analytics Engine/intro" className={styles.pathButton}>Using the Analytics Engine</a>
206
206
  </div>
@@ -1,119 +0,0 @@
1
- # GraphQL and subgraphs
2
-
3
- GraphQL plays a fundamental role in defining document model data schemas, handling data access patterns, and enabling event-driven workflows within the Powerhouse ecosystem.
4
- This document provides an intro to graphQL and how it is used at Powerhouse when dealing with subgraphs
5
-
6
- More specifically, GraphQL is used as:
7
- - The **schema definition language (SDL)** for defining our document models and thereby self-documenting the API to the data model. It allows developers to define the structure and relationships of data in a strongly-typed format.
8
- - As the **query language in subgraphs**, which allow different services to expose and query structured data dynamically.
9
-
10
-
11
- ## Powerhouse's use of GraphQL subgraphs
12
- Powerhouse structures its data into subgraphs, which are modular GraphQL services that connect to the Reactor, Powerhouse's core data infrastructure, or Operational Data Stores fueled by data from a processor.
13
-
14
- ### Fetching data from the Reactor
15
-
16
- Powerhouse uses GraphQL to expose system-level data, such as drives, users, and operational records.
17
- Example: The **System Subgraph** allows querying of drives, stored files and folders.
18
-
19
- ### Operational data stores
20
-
21
- Custom subgraphs can be created to store and retrieve operational data in real time.
22
- Example: A subgraph can track file uploads and expose this data via GraphQL queries. ????
23
-
24
- ??
25
-
26
- ```graphql
27
- type File {
28
- id: ID!
29
- name: String!
30
- size: Int!
31
- createdAt: DateTime!
32
- }
33
-
34
- type Query {
35
- getFile(id: ID!): File
36
- }
37
- ```
38
- This schema ensures that every File entity has an ID, name, size, and timestamp.
39
-
40
- ??
41
-
42
- In Powerhouse, each subgraph has its own SDL, ensuring modularity and flexibility while working within the ecosystem.
43
-
44
- ## CQRS breakdown
45
-
46
- Powerhouse uses CQRS to separate write operations (commands) from read operations (queries).
47
- This improves system scalability and flexibility.
48
- - GraphQL Queries handle read operations, retrieving structured data efficiently.
49
- - GraphQL Mutations handle write operations, modifying the state in a controlled manner.
50
-
51
- Powerhouse's subgraphs act as the read layer, while processors handle write operations into operational data stores. This prevents conflicts between querying and modifying data.
52
-
53
- | Layer | Role | GraphQL Usage | Implementation |
54
- | --- | --- | --- | --- |
55
- | Write Model (Commands) | Handles state changes (adding, modifying, deleting) | GraphQL Mutations | Processor |
56
- | Read Model (Queries) | Optimized for fetching/reading/retrieving data | GraphQL Queries | Subgraph |
57
-
58
- ### Read and write separation
59
- **Read Model (Query)**
60
-
61
- - Optimized for data retrieval
62
- - Structured using GraphQL Queries
63
- - Aggregates and exposes data via a subgraph
64
- - Pulls data from Operational Data Stores, Analytics Stores, and Reactor
65
- - Subgraphs do not directly modify the data—they only expose pre-processed information
66
-
67
-
68
-
69
- ```graphql title="Example of a Powerhouse Contributor schema in GraphQL"
70
- query {
71
- getFile(id: "123") {
72
- name
73
- size
74
- }
75
- }
76
- ```
77
-
78
- **Write Model (Mutation)**
79
- - Handles state changes (adding, modifying, deleting)
80
- - Structured using GraphQL Mutations
81
- - Writes data to Operational Data Stores
82
-
83
- ```graphql title="Example of a Powerhouse Contributor schema in GraphQL"
84
- mutation {
85
- createFile(name: "document.pdf", size: 1024) {
86
- id
87
- name
88
- }
89
- }
90
- ```
91
-
92
- ### GraphQL and event-driven architecture (EDA)
93
- Event-Driven Architecture (EDA) enables asynchronous processing where events trigger actions. Powerhouse uses GraphQL to expose real-time event data from its Reactor and Operational Data Stores.
94
-
95
- How GraphQL Fits into EDA
96
- - **Real-Time Data Exposure** – Subgraphs fetch event-based data updates.
97
- - **Event Subscription Mechanism** – Powerhouse is working towards integrating GraphQL Subscriptions for real-time updates.
98
- - **Efficient Decoupling** – Events are stored in an operational datastore, and GraphQL queries retrieve structured results.
99
-
100
- #### Example: Powerhouse's event flow
101
- 1. Processor detects an event (e.g., file upload).
102
- 2. Writes event data to the Operational Data Store.
103
- 3. Subgraph exposes the updated data via GraphQL.
104
-
105
-
106
- ## GraphQL subscriptions
107
- Although Powerhouse currently uses queries and mutations, GraphQL Subscriptions could allow real-time streaming of event-based data.
108
-
109
- #### Example (future implementation):
110
-
111
- ```graphql
112
- subscription {
113
- fileUploaded {
114
- id
115
- name
116
- }
117
- }
118
- ```
119
- This would enable clients to listen for new file uploads without polling.
@@ -1,312 +0,0 @@
1
- # Working with subgraphs
2
-
3
- This tutorial will demonstrate how to create and customize a subgraph using our To-do List project as an example.
4
- Let's start with the basics and gradually add more complex features and functionality.
5
-
6
- ## What is a subgraph?
7
-
8
- A subgraph in Powerhouse is a **GraphQL-based modular data component** that extends the functionality of your document models. While document models handle the core state and operations, subgraphs can:
9
- 1. Connect to external APIs or databases
10
- 2. Add custom queries and mutations
11
- 3. Automate interactions between different document models
12
- 4. Provide additional backend functionality
13
-
14
- ### Subgraphs can retrieve data from
15
-
16
- - **The Reactor** – The core Powerhouse data system or network node.
17
- - **Operational Data Stores** – Structured data storage for operational processes, offering real-time updates, for querying structured data.
18
- - **Analytics Stores** – Aggregated historical data, useful for insights, reporting and business intelligence.
19
-
20
- ### Subgraphs consist of
21
-
22
- - **A schema** – Which defines the GraphQL Queries and Mutations.
23
- - **Resolvers** – Which handle data fetching and logic.
24
- - **Context Fields** – Additional metadata that helps in resolving data efficiently.
25
-
26
- #### Additionally, context fields allow resolvers to access extra information, such as:
27
- - **User authentication** (e.g., checking if a user is an admin).
28
- - **External data sources** (e.g., analytics).
29
-
30
-
31
-
32
- ```typescript title="Example of a context field"
33
- context: {
34
- admin: async (session) => {
35
- const admins = await operationalStore.get("admins");
36
- return admins.includes(session.user);
37
- }
38
- }
39
- ```
40
-
41
- ## 1. How to generate a subgraph
42
-
43
- Lets start by generating a new subgraph. For our tutorial we will create a new subgraph within our To-do List project.
44
- Open your project and start your terminal.
45
- The Powerhouse toolkit provides a command-line utility to create new subgraphs easily.
46
-
47
- ```bash title="Run the following command to generate a new subgraph"
48
- ph generate --subgraph <to-do-list-subgraph>
49
- ```
50
-
51
- ```bash title="Expected Output"
52
- Loaded templates: node_modules/@powerhousedao/codegen/dist/codegen/.hygen/templates
53
- FORCED: ./subgraphs/to-do-list-subgraph/index.ts
54
- skipped: ./subgraphs/index.ts
55
- inject: ./subgraphs/index.ts
56
- ```
57
-
58
- ### What happened?
59
- 1. A new subgraph was created in `./subgraphs/to-do-list-subgraph/`
60
- 2. The subgraph was automatically registered in your project's registry
61
- 3. Basic boilerplate code was generated with an example query
62
-
63
- If we now run 'phreactor' we will see the new subgraph being registered during the startup of the Reactor.
64
- > Registered /todolist subgraph.
65
-
66
- ## 2. Customizing your subgraph with a schema
67
-
68
- Now that we've generated our subgraph, let's open it and define the schema inside the `index.ts` file.
69
-
70
- ### 2.1 Define the schema
71
-
72
- Here we define the schema (typeDefs) which defines the structure of your queries and mutations.
73
- For educational purposes we will define a simple query that mimics the functionality of the todoList interface (or editor):
74
- - Returns the total number of todo's
75
- - The number of todo's that are checked
76
- - The number of todo's that are not checked
77
-
78
-
79
-
80
- ```graphql
81
- type Query {
82
- fileIds: [String]
83
- }
84
- ```
85
-
86
- ### What happened?
87
-
88
- - Added two queries: todoList and todoItems
89
- - Created an operational table todo_items to store the todo items
90
- - Added resolvers to fetch and filter todo items
91
- - Removed the example code
92
- - The todoItems query accepts an optional checked parameter to filter items by their status
93
- - The todoList query returns the full list with its statistics
94
-
95
-
96
- ### 2.2 Implement the resolver for the subgraph's schema
97
- Resolvers define how data is retrieved or modified.
98
- If you query for a specific value you can retrieve the value from either the reactor itself or an operational datastore.
99
- We'll look into this in more detail in the next section.
100
-
101
- ```js
102
- resolvers: {
103
- Query: {
104
- fileIds: async () => {
105
- return ["file1", "file2", "file3"];
106
- }
107
- }
108
- }
109
- ```
110
-
111
- ### 2.3 Add operational data storage (optional)
112
- If you need to persist data, initialize an operational datastore inside onSetup():
113
-
114
- ```typescript title="Adding an operational datastore"
115
- async onSetup() {
116
- await this.createOperationalTables();
117
- }
118
-
119
- async createOperationalTables() {
120
- await this.operationalStore.schema.createTableIfNotExists(
121
- "fileIds",
122
- (table) => {
123
- table.string("id").primary();
124
- }
125
- );
126
- }
127
- ```
128
-
129
- ### 2.4 Fetching from an operational store
130
- If your subgraph interacts with an Operational Data Store, modify the resolver:
131
-
132
- ```typescript title="Example of a resolver that fetches data from an operational store"
133
- resolvers: {
134
- Query: {
135
- fileIds: async (_, __, { operationalStore }) => {
136
- return await operationalStore.getAll("fileIds");
137
- }
138
- }
139
- }
140
- ```
141
-
142
- ### 2.5 Connecting to a processor (optional, but recommended)
143
-
144
- #### Why connect a processor?
145
- Subgraphs alone are limited. A subgraph only queries data, but doesn't generate or store it.
146
- To make subgraphs useful, connect them with processors that update the data dynamically.
147
- **A processor listens to system events and updates the operational store in real-time.**
148
-
149
- Making use of a processor allows for:
150
- - **Live updates** instead of static data.
151
- - **Scalable architecture** through event-driven data changes.
152
- - **Seamless integration** with other Powerhouse components.
153
-
154
- Inside your processor, you can listen for new files, which in turn update the datastore:
155
-
156
- ```typescript title="Example: Creating a Simple Processor"
157
- async process(event) {
158
- if (event.type === "ADD_FILE") {
159
- await this.operationalStore.insert("fileIds", { id: event.fileId });
160
- }
161
- }
162
- ```
163
-
164
- Then, modify your subgraph resolver to return real-time data:
165
-
166
- ```js
167
- resolvers: {
168
- Query: {
169
- fileIds: async (_, __, { operationalStore }) => {
170
- return await operationalStore.getAll("fileIds");
171
- }
172
- }
173
- }
174
- ```
175
-
176
- ## 3. Testing the subgraph
177
-
178
- ### 3.1. Start the reactor
179
- To activate the subgraph, run:
180
-
181
- ```bash
182
- ph reactor
183
- ```
184
- Or, for full system startup:
185
-
186
- ```bash title="Start the Reactor & Connect in Studio or Locally
187
- ph dev
188
- ```
189
-
190
- ### 3.2. Access GraphQL playground
191
- Open your browser and go to:
192
-
193
- ```bash
194
- http://localhost:4001/<subgraph-name>
195
- ```
196
- Example:
197
-
198
- ```bash
199
- http://localhost:4001/test-subgraph
200
- ```
201
-
202
- ### 3.3. Run a query
203
-
204
- ```graphql
205
- query {
206
- fileIds
207
- }
208
- ```
209
-
210
- ### 3.4. Expected response
211
- If everything works, you should see:
212
-
213
- ```json
214
- {
215
- "data": {
216
- "fileIds": ["file1", "file2", "file3"]
217
- }
218
- }
219
- ```
220
-
221
- ## 4. Working with the supergraph or gateway
222
-
223
- A supergraph is a GraphQL schema that combines multiple underlying GraphQL APIs, known as subgraphs, into a single, unified graph. This architecture allows different teams to work independently on their respective services (subgraphs) while providing a single entry point for clients or users to query all available data
224
-
225
- ### 4.1 Key concepts
226
-
227
- * **Subgraph:** An independent GraphQL service with its own schema. Each subgraph typically represents a specific domain or microservice within a larger system.
228
- * **Gateway/Router:** A server that sits in front of the subgraphs. It receives client queries, consults the supergraph schema, and routes parts of the query to the relevant subgraphs. It then stitches the results back together before sending the final response to the client.
229
-
230
- ### 4.2 Benefits of using a supergraph
231
-
232
- * **Federated Architecture:** Enables a microservices-based approach where different teams can own and operate their services independently.
233
- * **Scalability:** Individual subgraphs can be scaled independently based on their specific needs.
234
- * **Improved Developer Experience:** Clients interact with a single, consistent GraphQL API, simplifying data fetching and reducing the need to manage multiple endpoints.
235
- * **Schema Evolution:** Subgraphs can evolve their schemas independently, and the supergraph can be updated without breaking existing clients, as long as breaking changes are managed carefully.
236
- * **Clear Separation of Concerns:** Each subgraph focuses on a specific domain, leading to more maintainable and understandable codebases.
237
-
238
-
239
- ### 4.3 Use the Powerhouse supergraph
240
-
241
- The Powerhouse supergraph for any given remote drive or reactor can be found under `http://localhost:4001/graphql`. The gateway / supergraph available on `/graphql` combines all the subgraphs, except for the drive subgraph (which is accessible via `/d/:driveId`). To get to the endpoint open your localhost by starting the reactor and adding `graphql` to the end of the url. The following commands explain how you can test & try the supergraph.
242
-
243
- - Start the reactor:
244
-
245
- ```bash
246
- ph reactor
247
- ```
248
-
249
- - Open the GraphQL editor in your browser:
250
-
251
- ```
252
- http://localhost:4001/graphql
253
- ```
254
-
255
- The supergraph allows to both query & mutate data from the same endpoint.
256
-
257
- - Create a todo document in the `powerhouse` drive using the `ToDo_createDocument` mutation.
258
- ![ToDo_createDocument](https://i.ibb.co/GQTZr7Wk/Screenshot-2025-05-01-at-1-22-23-PM.png)
259
-
260
- - Get the document state using the `GetDocument` query.
261
- ![GetDocument](https://i.ibb.co/v47cj4Q4/Screenshot-2025-05-01-at-1-22-41-PM.png)
262
-
263
- - In a different terminal, start connect:
264
-
265
- ```bash
266
- ph connect
267
- ```
268
-
269
- - Open Connect and add the `powerhouse` drive:
270
-
271
- ```
272
- http://localhost:4001/d/powerhouse
273
- ```
274
-
275
- - You should now see the todo document you've created earlier. Edit the todo document with the document editor and add a few tasks that you can query later.
276
-
277
- - Go back to the GraphQL explorer and use the `GetDocument` query again — you should see the updated state.
278
-
279
- This is a quick example of how the supegraph can be used.
280
-
281
-
282
- ## Subgraphs are particularly useful for
283
-
284
- 1. **Cross-Document Interactions**: For example, connecting a To-do List with an Invoice document model:
285
- - When an invoice-related task is marked complete, update the invoice status
286
- - When an invoice is paid, automatically check off related tasks
287
-
288
- 2. **External Integrations**:
289
- - Sync tasks with external project management tools
290
- - Connect with notification systems
291
- - Integrate with analytics platforms
292
-
293
- 3. **Custom Business Logic**:
294
- - Implement complex task prioritization
295
- - Add automated task assignments
296
- - Create custom reporting functionality
297
-
298
- ### Prebuilt subgraphs
299
-
300
- Some subgraphs (e.g., System Subgraph, Drive Subgraph) already exist.
301
- To integrate with them, register them via the Reactor API.
302
-
303
- ### Future enhancements
304
-
305
- Bridge Processors and Subgraphs – Currently, there's a gap in how processors and subgraphs interact. Powerhouse might improve this in future updates.
306
-
307
-
308
-
309
-
310
-
311
-
312
-
@@ -1,8 +0,0 @@
1
- {
2
- "label": "Working With Subgraphs",
3
- "position": 4,
4
- "link": {
5
- "type": "generated-index",
6
- "description": "Learn how to work with graphQL, subgraphs, and processors in Powerhouse."
7
- }
8
- }