@powerhousedao/academy 5.1.0-dev.0 → 5.1.0-dev.10

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 (75) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/blog/BeyondCommunication-ABlueprintForDevelopment.md +2 -1
  3. package/blog/TheChallengeOfChange.md +1 -0
  4. package/docs/academy/01-GetStarted/00-ExploreDemoPackage.mdx +24 -27
  5. package/docs/academy/01-GetStarted/01-CreateNewPowerhouseProject.md +118 -9
  6. package/docs/academy/01-GetStarted/02-DefineToDoListDocumentModel.md +110 -28
  7. package/docs/academy/01-GetStarted/03-ImplementOperationReducers.md +191 -145
  8. package/docs/academy/01-GetStarted/04-WriteDocumentModelTests.md +378 -0
  9. package/docs/academy/01-GetStarted/05-BuildToDoListEditor.md +560 -0
  10. package/docs/academy/01-GetStarted/_04-BuildToDoListEditor +1 -1
  11. package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/03-BuilderTools.md +2 -2
  12. package/docs/academy/{01-GetStarted → 02-MasteryTrack/01-BuilderEnvironment}/05-VetraStudio.md +48 -6
  13. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/02-SpecifyTheStateSchema.md +75 -44
  14. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/03-SpecifyDocumentOperations.md +28 -22
  15. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/04-UseTheDocumentModelGenerator.md +28 -31
  16. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/05-ImplementDocumentReducers.md +211 -206
  17. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/06-ImplementDocumentModelTests.md +176 -62
  18. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/07-ExampleToDoListRepository.md +21 -0
  19. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/01-BuildingDocumentEditors.md +309 -319
  20. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/00-DocumentToolbar.mdx +4 -0
  21. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/01-OperationHistory.md +4 -0
  22. package/docs/academy/02-MasteryTrack/05-Launch/04-ConfigureEnvironment.md +1 -1
  23. package/docs/academy/03-ExampleUsecases/Chatroom/02-CreateNewPowerhouseProject.md +111 -35
  24. package/docs/academy/03-ExampleUsecases/Chatroom/03-DefineChatroomDocumentModel.md +255 -76
  25. package/docs/academy/03-ExampleUsecases/Chatroom/04-ImplementOperationReducers.md +281 -160
  26. package/docs/academy/03-ExampleUsecases/Chatroom/05-ImplementChatroomEditor.md +188 -35
  27. package/docs/academy/03-ExampleUsecases/Chatroom/06-LaunchALocalReactor.md +95 -7
  28. package/docs/academy/03-ExampleUsecases/Chatroom/_category_.json +1 -1
  29. package/docs/academy/03-ExampleUsecases/TodoList/00-GetTheStarterCode.md +24 -0
  30. package/docs/academy/03-ExampleUsecases/TodoList/01-GenerateTodoListDocumentModel.md +211 -0
  31. package/docs/academy/03-ExampleUsecases/TodoList/02-ImplementTodoListDocumentModelReducerOperationHandlers.md +171 -0
  32. package/docs/academy/03-ExampleUsecases/TodoList/03-AddTestsForTodoListActions.md +462 -0
  33. package/docs/academy/03-ExampleUsecases/TodoList/04-GenerateTodoListDocumentEditor.md +45 -0
  34. package/docs/academy/03-ExampleUsecases/TodoList/05-ImplementTodoListDocumentEditorUIComponents.md +422 -0
  35. package/docs/academy/03-ExampleUsecases/TodoList/06-GenerateTodoDriveExplorer.md +61 -0
  36. package/docs/academy/03-ExampleUsecases/TodoList/07-AddSharedComponentForShowingTodoListStats.md +384 -0
  37. package/docs/academy/03-ExampleUsecases/TodoList/_category_.json +8 -0
  38. package/docs/academy/03-ExampleUsecases/VetraPackageLibrary/VetraPackageLibrary.md +7 -0
  39. package/docs/academy/03-ExampleUsecases/VetraPackageLibrary/_category_.json +9 -0
  40. package/docs/academy/04-APIReferences/00-PowerhouseCLI.md +6 -2
  41. package/docs/academy/04-APIReferences/01-ReactHooks.md +2 -2
  42. package/docs/academy/04-APIReferences/06-VetraRemoteDrive.md +160 -0
  43. package/docs/academy/04-APIReferences/renown-sdk/00-Overview.md +316 -0
  44. package/docs/academy/04-APIReferences/renown-sdk/01-Authentication.md +672 -0
  45. package/docs/academy/04-APIReferences/renown-sdk/02-APIReference.md +957 -0
  46. package/docs/academy/04-APIReferences/renown-sdk/_category_.json +8 -0
  47. package/docs/academy/05-Architecture/00-PowerhouseArchitecture.md +7 -39
  48. package/docs/academy/06-ComponentLibrary/00-DocumentEngineering.md +72 -24
  49. package/docs/academy/08-Glossary.md +7 -0
  50. package/docs/academy/10-TodoListTutorial/02-ImplementTodoListDocumentModelReducerOperationHandlers.md +171 -0
  51. package/docs/academy/10-TodoListTutorial/03-AddTestsForTodoListActions.md +462 -0
  52. package/docs/academy/10-TodoListTutorial/05-ImplementTodoListDocumentEditorUIComponents.md +422 -0
  53. package/docs/academy/10-TodoListTutorial/07-AddSharedComponentForShowingTodoListStats.md +370 -0
  54. package/docusaurus.config.ts +28 -3
  55. package/package.json +1 -1
  56. package/sidebars.ts +49 -12
  57. package/src/css/custom.css +26 -18
  58. package/static/img/Vetra-logo-dark.svg +11 -0
  59. package/static/img/vetra-logo-light.svg +11 -0
  60. package/docs/academy/00-EthereumArgentinaHackathon.md +0 -207
  61. package/docs/academy/01-GetStarted/04-BuildToDoListEditor.md +0 -218
  62. package/docs/academy/01-GetStarted/06-ReactorMCP.md +0 -58
  63. package/docs/academy/05-Architecture/02-ReferencingMonorepoPackages +0 -65
  64. package/docs/academy/05-Architecture/04-MovingBeyondCRUD +0 -61
  65. /package/docs/academy/{01-GetStarted → 02-MasteryTrack/01-BuilderEnvironment}/images/Modules.png +0 -0
  66. /package/docs/academy/{01-GetStarted → 02-MasteryTrack/01-BuilderEnvironment}/images/VetraStudioDrive.png +0 -0
  67. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/{02-RevisionHistoryTimeline → 02-RevisionHistoryTimeline/360/237/232/247"} +0 -0
  68. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{01-WhatIsADocumentModel → 360/237/232/247 /01-WhatIsADocumentModel"} +0 -0
  69. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{02-DAOandDocumentsModelsQ+A → 360/237/232/247 /02-DAOandDocumentsModelsQ+A"} +0 -0
  70. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{02-domain-modeling → 360/237/232/247 /02-domain-modeling"} +0 -0
  71. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{03-BenefitsOfDocumentModels → 360/237/232/247 /03-BenefitsOfDocumentModels"} +0 -0
  72. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{04-UtilitiesAndTips → 360/237/232/247 /04-UtilitiesAndTips"} +0 -0
  73. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{05-best-practices → 360/237/232/247 /05-best-practices"} +0 -0
  74. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{_category_.json → 360/237/232/247 /_category_.json"} +0 -0
  75. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{three-data-layers.png → 360/237/232/247 /three-data-layers.png"} +0 -0
@@ -1,6 +1,48 @@
1
- # Implement the document model
1
+ # Implement the document model reducers
2
2
 
3
- In this section, we will implement and test the operation reducers for the **To-do List** document model. For this, you have to export the document model specification from the Connect application and import it into your Powerhouse project directory.
3
+ :::tip Tutorial Repository
4
+ 📦 **Reference Code**: [step-3-implement-reducer-operation-handlers](https://github.com/powerhouse-inc/todo-tutorial/tree/step-3-implement-reducer-operation-handlers)
5
+
6
+ This step focuses on implementing the reducer logic for add, update, and delete operations.
7
+ :::
8
+
9
+ <details>
10
+ <summary>📖 How to use this tutorial</summary>
11
+
12
+ ### Compare your reducer implementation
13
+
14
+ After implementing your reducers:
15
+
16
+ ```bash
17
+ # Compare your reducers with the reference
18
+ git diff tutorial/step-3-implement-reducer-operation-handlers -- document-models/todo-list/src/reducers/
19
+
20
+ # View the reference reducer implementation
21
+ git show tutorial/step-3-implement-reducer-operation-handlers:document-models/todo-list/src/reducers/todos.ts
22
+ ```
23
+
24
+ ### Visual comparison with GitHub Desktop
25
+
26
+ After committing your work, compare visually:
27
+ 1. **Branch** menu → **"Compare to Branch..."**
28
+ 2. Select `tutorial/step-3-implement-reducer-operation-handlers`
29
+ 3. Review differences in the visual interface
30
+
31
+ ### If you get stuck
32
+
33
+ View or reset to a specific step:
34
+
35
+ ```bash
36
+ # View the reducer code
37
+ git show tutorial/step-3-implement-reducer-operation-handlers:document-models/todo-list/src/reducers/todos.ts
38
+
39
+ # Reset to this step (WARNING: loses your changes)
40
+ git reset --hard tutorial/step-3-implement-reducer-operation-handlers
41
+ ```
42
+
43
+ </details>
44
+
45
+ In this section, we will implement the operation reducers for the **To-do List** document model. For this, you need to export the document model specification from Connect and import it into your Powerhouse project directory.
4
46
 
5
47
  To export the document model specification, follow the steps in the [Define ToDoList Document Model](/academy/GetStarted/DefineToDoListDocumentModel) section.
6
48
 
@@ -22,180 +64,184 @@ Either step will import the document model specification into your Powerhouse pr
22
64
 
23
65
  ![vscode image](./images/vscode.png)
24
66
 
25
- ## In your project directory
67
+ ## Generate the document model code
26
68
 
27
69
  The next steps will take place in the VSCode editor. Make sure to have it open and the terminal window inside VSCode open as well.
28
70
 
29
- To write the operation reducers of the **To-do List** document model, you need to generate the document model code from the document model specification file you have exported into the Powerhouse project directory.
71
+ To write the operation reducers of the **To-do List** document model, you need to generate the document model code from the document model specification file you have exported.
30
72
 
31
- To do this, run the following command in the terminal:
73
+ Run the following command in the terminal:
32
74
 
33
75
  ```bash
34
- ph generate ToDoList.phdm.zip
76
+ ph generate TodoList.phd
35
77
  ```
36
78
 
37
- Now you can navigate to `/document-models/to-do-list/src/reducers/to-do-list.ts` and start writing the operation reducers.
79
+ ## Explore the generated reducer file
80
+
81
+ Navigate to `/document-models/todo-list/src/reducers/todos.ts` and open it. You should see scaffolding code that needs to be filled for the three operations you specified:
38
82
 
39
- Open the `to-do-list.ts` file and you should see the code that needs to be filled for the three operations you have specified earlier. The image below shows the code that needs to be filled:
83
+ ```typescript
84
+ import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
85
+
86
+ export const todoListTodosOperations: TodoListTodosOperations = {
87
+ addTodoItemOperation(state, action) {
88
+ // TODO: Implement "addTodoItemOperation" reducer
89
+ throw new Error('Reducer "addTodoItemOperation" not yet implemented');
90
+ },
91
+ updateTodoItemOperation(state, action) {
92
+ // TODO: Implement "updateTodoItemOperation" reducer
93
+ throw new Error('Reducer "updateTodoItemOperation" not yet implemented');
94
+ },
95
+ deleteTodoItemOperation(state, action) {
96
+ // TODO: Implement "deleteTodoItemOperation" reducer
97
+ throw new Error('Reducer "deleteTodoItemOperation" not yet implemented');
98
+ },
99
+ };
100
+ ```
40
101
 
41
- ![to-do-list ts file](./images/reducers.png)
102
+ ## Implement the operation reducers
42
103
 
43
- ## Write the operation reducers
104
+ Let's implement each reducer one by one.
44
105
 
45
- 1. Copy and paste the code below into the `to-do-list.ts` file in the `reducers` folder.
46
- 2. Save the file.
106
+ ### Step 1: Add the import
107
+
108
+ First, add the `generateId` import at the top of the file:
47
109
 
48
- <details>
49
- <summary>Operation Reducers</summary>
50
110
  ```typescript
51
- import { ToDoListToDoListOperations } from '../../gen/to-do-list/operations.js';
52
-
53
- // REMARKS: This is our main reducer object that implements all operations defined in the schema.
54
- // The ToDoListToDoListOperations type is auto-generated from our SDL and ensures type safety.
55
- export const reducer: ToDoListToDoListOperations = {
56
- // REMARKS: The addTodoItemOperation adds a new item to our todolist.
57
- // - state: The current document state that we can modify
58
- // - action: Contains the operation type and input data from the client
59
- // - dispatch: Function to trigger additional operations (not used here)
60
- addTodoItemOperation(state, action, dispatch) {
61
- // REMARKS: While this looks like we're directly mutating state, Powerhouse
62
- // handles immutability behind the scenes, creating a new state object.
63
- state.items.push({
64
- id: action.input.id, // Using the client-provided ID
65
- text: action.input.text, // Setting the todo text from input
66
- checked: false, // New items always start unchecked
67
- });
68
- },
69
-
70
- // REMARKS: The updateTodoItemOperation modifies an existing todo item.
71
- // It handles partial updates, allowing only specific fields to be updated.
72
- updateTodoItemOperation(state, action, dispatch) {
73
- // REMARKS: First find the item we want to update by its ID
74
- const item = state.items.find(item => item.id === action.input.id);
75
-
76
- // REMARKS: Proper error handling if item doesn't exist
77
- if (!item) {
78
- throw new Error(`Item with id ${action.input.id} not found`);
79
- }
80
-
81
- // REMARKS: We only update fields that were included in the input
82
- // This allows for partial updates (only update what was provided)
83
- if (action.input.text) {
84
- item.text = action.input.text;
85
- }
86
- if (typeof action.input.checked === 'boolean') {
87
- item.checked = action.input.checked;
88
- }
89
-
90
- },
91
-
92
- // REMARKS: The deleteTodoItemOperation removes an item from the list.
93
- // This showcases functional programming with array filters for immutable updates.
94
- deleteTodoItemOperation(state, action, dispatch) {
95
- // REMARKS: Create a new array containing only items that don't match the ID
96
- // This is a common pattern for immutable array updates in JavaScript
97
- state.items = state.items.filter(item => item.id !== action.input.id);
98
- },
111
+ // added-line
112
+ import { generateId } from "document-model/core";
113
+ import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
114
+ ```
115
+
116
+ ### Step 2: Implement addTodoItemOperation
117
+
118
+ Replace the boilerplate `addTodoItemOperation` with the actual implementation:
119
+
120
+ ```typescript
121
+ export const todoListTodosOperations: TodoListTodosOperations = {
122
+ // removed-start
123
+ addTodoItemOperation(state, action) {
124
+ // TODO: Implement "addTodoItemOperation" reducer
125
+ throw new Error('Reducer "addTodoItemOperation" not yet implemented');
126
+ },
127
+ // removed-end
128
+ // added-start
129
+ addTodoItemOperation(state, action) {
130
+ const id = generateId();
131
+ state.items.push({ ...action.input, id, checked: false });
132
+ },
133
+ // added-end
134
+ updateTodoItemOperation(state, action) {
135
+ // ...
136
+ },
137
+ deleteTodoItemOperation(state, action) {
138
+ // ...
139
+ },
99
140
  };
141
+ ```
100
142
 
101
- ````
102
- </details>
143
+ **What's happening here:**
144
+ - We generate a unique ID using `generateId()` from `document-model/core`
145
+ - We push a new item to the `items` array with the input text, new ID, and `checked: false`
146
+ - Under the hood, Powerhouse uses Immer.js, so this "mutation" is actually immutable
147
+
148
+ ### Step 3: Implement updateTodoItemOperation
149
+
150
+ Replace the boilerplate `updateTodoItemOperation`:
103
151
 
104
- ## Write the operation reducers tests
152
+ ```typescript
153
+ // removed-start
154
+ updateTodoItemOperation(state, action) {
155
+ // TODO: Implement "updateTodoItemOperation" reducer
156
+ throw new Error('Reducer "updateTodoItemOperation" not yet implemented');
157
+ },
158
+ // removed-end
159
+ // added-start
160
+ updateTodoItemOperation(state, action) {
161
+ const item = state.items.find((item) => item.id === action.input.id);
162
+ if (!item) return;
163
+ item.text = action.input.text ?? item.text;
164
+ item.checked = action.input.checked ?? item.checked;
165
+ },
166
+ // added-end
167
+ ```
105
168
 
106
- In order to make sure the operation reducers are working as expected, you need to write tests for them.
169
+ **What's happening here:**
170
+ - We find the item by its ID
171
+ - We return early if the item is not found
172
+ - We use nullish coalescing (`??`) to only update fields that are provided
107
173
 
108
- Navigate to `/document-models/to-do-list/src/reducers/tests/to-do-list.test.ts` and copy and paste the code below into the file. Save the file.
174
+ ### Step 4: Implement deleteTodoItemOperation
109
175
 
110
- Here are the tests for the three operations implemented in the reducers file. This test file creates an empty ToDoList document model, then adds a todo item, updates it and deletes it.
176
+ Replace the boilerplate `deleteTodoItemOperation`:
177
+
178
+ ```typescript
179
+ // removed-start
180
+ deleteTodoItemOperation(state, action) {
181
+ // TODO: Implement "deleteTodoItemOperation" reducer
182
+ throw new Error('Reducer "deleteTodoItemOperation" not yet implemented');
183
+ },
184
+ // removed-end
185
+ // added-start
186
+ deleteTodoItemOperation(state, action) {
187
+ state.items = state.items.filter((item) => item.id !== action.input.id);
188
+ },
189
+ // added-end
190
+ ```
191
+
192
+ **What's happening here:**
193
+ - We filter out the item with the matching ID
194
+ - This creates a new array without the deleted item
195
+
196
+ ## Complete reducer file
197
+
198
+ Here's the complete implementation:
111
199
 
112
200
  <details>
113
- <summary>Operation Reducers Tests</summary>
201
+ <summary>Complete todos.ts</summary>
202
+
114
203
  ```typescript
115
- import utils from '../../gen/utils.js';
116
- import { reducer } from '../../gen/reducer.js';
117
- import * as creators from '../../gen/creators.js';
118
- import { ToDoListDocument } from '../../gen/types.js';
119
-
120
- // REMARKS:
121
- // These tests demonstrate the event sourcing principles of our document model.
122
- // Each operation is recorded in the document's operations list and affects the state.
123
-
124
- describe('Todolist Operations', () => {
125
- let document: ToDoListDocument;
126
-
127
- beforeEach(() => {
128
- // REMARKS: We start with a fresh, empty document for each test
129
- document = utils.createDocument();
130
- });
131
-
132
- it('should handle addTodoItem operation', () => {
133
- // REMARKS: We create an input object matching our AddTodoItemInput schema
134
- const input = { id: '1', text: 'Buy milk' };
135
-
136
- // REMARKS: We apply the operation to get a new document state
137
- // Note how we use the creators to generate the operation action
138
- const updatedDocument = reducer(document, creators.addTodoItem(input));
139
-
140
- // REMARKS: We verify that:
141
- // 1. The operation was recorded in the document's operation history
142
- // 2. The state was updated according to our reducer implementation
143
- expect(updatedDocument.operations.global).toHaveLength(1);
144
- expect(updatedDocument.operations.global[0].type).toBe('ADD_TODO_ITEM');
145
- expect(updatedDocument.state.global.items).toHaveLength(1);
146
- expect(updatedDocument.state.global.items[0].text).toBe('Buy milk');
147
- });
148
-
149
- it('should handle updateTodoItem operation', () => {
150
- // REMARKS: For update, we first need to add an item, then update it
151
- // This demonstrates the sequential application of operations
152
- const addInput = { id: '1', text: 'Buy milk' };
153
- const updateInput = { id: '1', text: 'Buy bread' };
154
-
155
- // REMARKS: Operations are applied in sequence, building up document state
156
- const createdDocument = reducer(document, creators.addTodoItem(addInput));
157
- const updatedDocument = reducer(createdDocument, creators.updateTodoItem(updateInput));
158
-
159
- // REMARKS: Now we have 2 operations in history, and the state reflects both
160
- expect(updatedDocument.operations.global).toHaveLength(2);
161
- expect(updatedDocument.state.global.items[0].text).toBe('Buy bread');
162
- });
163
-
164
- it('should handle deleteTodoItem operation', () => {
165
- // REMARKS: Similar pattern - add an item, then delete it
166
- const addInput = { id: '1', text: 'Buy milk' };
167
- const deleteInput = { id: '1' };
168
-
169
- const createdDocument = reducer(document, creators.addTodoItem(addInput));
170
- const updatedDocument = reducer(createdDocument, creators.deleteTodoItem(deleteInput));
171
-
172
- // REMARKS: After deletion, we still have 2 operations in history,
173
- // but the items array is now empty again in the final state
174
- expect(updatedDocument.operations.global).toHaveLength(2);
175
- expect(updatedDocument.state.global.items).toHaveLength(0);
176
- });
177
- });
178
- ````
204
+ import { generateId } from "document-model/core";
205
+ import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
206
+
207
+ export const todoListTodosOperations: TodoListTodosOperations = {
208
+ addTodoItemOperation(state, action) {
209
+ const id = generateId();
210
+ state.items.push({ ...action.input, id, checked: false });
211
+ },
212
+
213
+ updateTodoItemOperation(state, action) {
214
+ const item = state.items.find((item) => item.id === action.input.id);
215
+ if (!item) return;
216
+ item.text = action.input.text ?? item.text;
217
+ item.checked = action.input.checked ?? item.checked;
218
+ },
219
+
220
+ deleteTodoItemOperation(state, action) {
221
+ state.items = state.items.filter((item) => item.id !== action.input.id);
222
+ },
223
+ };
224
+ ```
179
225
 
180
226
  </details>
181
227
 
182
- Now you can run the tests to make sure the operation reducers are working as expected.
228
+ :::tip Check your work
229
+
230
+ To make sure everything works as expected:
183
231
 
184
232
  ```bash
185
- pnpm run test
186
- ```
233
+ # Check types compile correctly
234
+ pnpm tsc
187
235
 
188
- Output should be as follows:
236
+ # Check linting passes
237
+ pnpm lint
189
238
 
190
- ```bash
191
- Test Files 2 passed (2)
192
- Tests 5 passed (5)
193
- Start at 12:04:57
194
- Duration 417ms (transform 79ms, setup 0ms, collect 174ms, tests 12ms, environment 0ms, prepare 158ms)
239
+ # Compare with reference implementation
240
+ git diff tutorial/step-3-implement-reducer-operation-handlers -- document-models/todo-list/src/reducers/
195
241
  ```
196
242
 
197
- If you got the same output, you have successfully implemented the operation reducers and tests for the **To-do List** document model. Congratulations, you've successfully set up the backbone for a simple **To-do List** document.
243
+ :::
198
244
 
199
- ## Up next: To-do list editor
245
+ ## Up next: Writing tests
200
246
 
201
- In the next chapter of this introduction track you will learn how to implement an editor for your document model so you can see a simple user interface for the **To-do List** document model in action.
247
+ In the next chapter, you'll write comprehensive tests to verify your reducer implementations work correctly.