@powerhousedao/academy 0.1.0-dev.0

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 (226) hide show
  1. package/.vscode/settings.json +3 -0
  2. package/CHANGELOG.md +9 -0
  3. package/Dockerfile +31 -0
  4. package/ProcFile +1 -0
  5. package/README.md +43 -0
  6. package/babel.config.js +3 -0
  7. package/blog/BeyondCommunication-ABlueprintForDevelopment.md +88 -0
  8. package/blog/TheChallengeOfChange.md +86 -0
  9. package/blog/images/Iteration.png +0 -0
  10. package/blog/images/RAD.png +0 -0
  11. package/docs/academy/01-GetStarted/00-GetStarted.mdx +181 -0
  12. package/docs/academy/01-GetStarted/01_InstallDemoPackage.md +38 -0
  13. package/docs/academy/01-GetStarted/02-ToDoList/01-CreateNewPowerhouseProject.md +97 -0
  14. package/docs/academy/01-GetStarted/02-ToDoList/02-DefineToDoListDocumentModel.md +86 -0
  15. package/docs/academy/01-GetStarted/02-ToDoList/03-ImplementOperationReducers.md +201 -0
  16. package/docs/academy/01-GetStarted/02-ToDoList/04-BuildToDoListEditor.md +494 -0
  17. package/docs/academy/01-GetStarted/02-ToDoList/_category_.json +8 -0
  18. package/docs/academy/01-GetStarted/02-ToDoList/images/DocumentModelHeader.png +0 -0
  19. package/docs/academy/01-GetStarted/02-ToDoList/images/DocumentModelOperations.png +0 -0
  20. package/docs/academy/01-GetStarted/02-ToDoList/images/OpenDocumentModelEditor.gif +0 -0
  21. package/docs/academy/01-GetStarted/02-ToDoList/images/completeEditor.png +0 -0
  22. package/docs/academy/01-GetStarted/02-ToDoList/images/connectApp.gif +0 -0
  23. package/docs/academy/01-GetStarted/02-ToDoList/images/form.png +0 -0
  24. package/docs/academy/01-GetStarted/02-ToDoList/images/mytodolist.gif +0 -0
  25. package/docs/academy/01-GetStarted/02-ToDoList/images/reducers.png +0 -0
  26. package/docs/academy/01-GetStarted/02-ToDoList/images/vscode.png +0 -0
  27. package/docs/academy/01-GetStarted/styles.module.css +99 -0
  28. package/docs/academy/02-AdvancedTutorial/01-Create/00-BuilderTools.md +234 -0
  29. package/docs/academy/02-AdvancedTutorial/01-Create/01-SetupBuilderEnvironment.md +247 -0
  30. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/04-UtilitiesAndTips.md +79 -0
  31. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/01-SetupBuilderEnvironment.md +216 -0
  32. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/02-CreateNewPowerhouseProject.md +78 -0
  33. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/03-DefineChatroomDocumentModel.md +139 -0
  34. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/04-ImplementOperationReducers.md +364 -0
  35. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/05-ImplementChatroomEditor.md +194 -0
  36. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/06-LaunchALocalReactor.md +15 -0
  37. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/_category_.json +8 -0
  38. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/image-1.png +0 -0
  39. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/image-2.png +0 -0
  40. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/image-3.png +0 -0
  41. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/image-4.png +0 -0
  42. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/image-5.png +0 -0
  43. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/image.png +0 -0
  44. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/images/ChatRoomConnectApp.gif +0 -0
  45. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/images/ChatRoomTest.gif +0 -0
  46. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/images/completeEditor.png +0 -0
  47. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/images/form.png +0 -0
  48. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/images/reducers.png +0 -0
  49. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/Chatroom/images/vscode.png +0 -0
  50. package/docs/academy/02-AdvancedTutorial/01-Create/02-MoreTutorials/_category_.json +8 -0
  51. package/docs/academy/02-AdvancedTutorial/01-Create/02-StandardDocumentModelWorkflow.md +229 -0
  52. package/docs/academy/02-AdvancedTutorial/03-BuildingUserExperiences/01-BuildingBeautifulDocumentEditors.md +109 -0
  53. package/docs/academy/02-AdvancedTutorial/03-BuildingUserExperiences/02-ConfiguringDrives.md +51 -0
  54. package/docs/academy/02-AdvancedTutorial/03-BuildingUserExperiences/03-BuildingADriveExplorer.md +174 -0
  55. package/docs/academy/02-AdvancedTutorial/03-BuildingUserExperiences/07-DocumentTools/01-OperationHistory.md +67 -0
  56. package/docs/academy/02-AdvancedTutorial/03-BuildingUserExperiences/07-DocumentTools/02-RevisionHistoryTimeline.md +132 -0
  57. package/docs/academy/02-AdvancedTutorial/03-BuildingUserExperiences/07-DocumentTools/_category_.json +7 -0
  58. package/docs/academy/02-AdvancedTutorial/03-BuildingUserExperiences/07-DocumentTools/images/committer-address-popup.png +0 -0
  59. package/docs/academy/02-AdvancedTutorial/03-BuildingUserExperiences/07-DocumentTools/images/revision-hash-popup.png +0 -0
  60. package/docs/academy/02-AdvancedTutorial/03-BuildingUserExperiences/07-DocumentTools/images/revision-history-list.png +0 -0
  61. package/docs/academy/02-AdvancedTutorial/03-BuildingUserExperiences/07-DocumentTools/images/signature-details-popup.png +0 -0
  62. package/docs/academy/02-AdvancedTutorial/03-BuildingUserExperiences/_category_.json +8 -0
  63. package/docs/academy/02-AdvancedTutorial/03-BuildingUserExperiences/images/CreateDrive.png +0 -0
  64. package/docs/academy/02-AdvancedTutorial/03-BuildingUserExperiences/images/mytodolist.gif +0 -0
  65. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/01-ReadingAndWritingThroughTheAPI.mdx +121 -0
  66. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/02-GraphQLAtPowerhouse.md +156 -0
  67. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/03-WorkingWithSubgraphs/02-GraphQLAndSubgraphs.mdx +119 -0
  68. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/03-WorkingWithSubgraphs/03-WorkingWithSubgraphs.md +312 -0
  69. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/03-WorkingWithSubgraphs/_category_.json +8 -0
  70. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/04-analytics-processor.md +342 -0
  71. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/05-AnalyticsProcessorTutorial/01-SetupBuilderEnvironment.md +215 -0
  72. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/05-AnalyticsProcessorTutorial/02-CreateNewPowerhouseProject.md +55 -0
  73. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/05-AnalyticsProcessorTutorial/03-GenerateAnAnalyticsProcessor.md +173 -0
  74. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/05-AnalyticsProcessorTutorial/04-UpdateAnalyticsProcessor.md +223 -0
  75. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/05-AnalyticsProcessorTutorial/_category_.json +8 -0
  76. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/05-AnalyticsProcessorTutorial/images/Create-SPV.gif +0 -0
  77. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/05-AnalyticsProcessorTutorial/images/Create-a-new-asset.png +0 -0
  78. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/05-AnalyticsProcessorTutorial/images/Create-a-transaction.gif +0 -0
  79. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/05-AnalyticsProcessorTutorial/images/Transaction-table.png +0 -0
  80. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/05-AnalyticsProcessorTutorial/images/create-a-new-RWA-document.gif +0 -0
  81. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/05-AnalyticsProcessorTutorial/images/granularity.png +0 -0
  82. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/GraphQL References/QueryingADocumentWithGraphQL.md +244 -0
  83. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/GraphQL References/rwa-reports/listener-raw.png +0 -0
  84. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/GraphQL References/rwa-reports/raw-reports1.png +0 -0
  85. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/GraphQL References/rwa-reports/raw-reports2.png +0 -0
  86. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/GraphQL References/rwa-reports/rwaRegister.png +0 -0
  87. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/apse.png +0 -0
  88. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/best-practices.md +60 -0
  89. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/filter.png +0 -0
  90. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/filteroptions.png +0 -0
  91. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/graphql/index.md +166 -0
  92. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/graphql/integration.md +75 -0
  93. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/dbs.png +0 -0
  94. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/high-level.jpg +0 -0
  95. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/indexeddb.png +0 -0
  96. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/libs-core.jpg +0 -0
  97. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/libs.jpg +0 -0
  98. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/lod.jpg +0 -0
  99. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/logo.png +0 -0
  100. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/navbar.png +0 -0
  101. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/overview-1.jpg +0 -0
  102. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/overview-2.jpg +0 -0
  103. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/overview-3.jpg +0 -0
  104. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/overview-4.jpg +0 -0
  105. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/overview-5.jpg +0 -0
  106. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/overview-6.jpg +0 -0
  107. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/paths-1.jpg +0 -0
  108. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/images/paths-2.jpg +0 -0
  109. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/intro.md +149 -0
  110. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/typescript/benchmarks.md +27 -0
  111. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/typescript/browser.md +77 -0
  112. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/typescript/compatibility.md +14 -0
  113. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/typescript/index.md +230 -0
  114. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/typescript/memory.md +72 -0
  115. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/typescript/pg.md +63 -0
  116. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/typescript/schema.md +14 -0
  117. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/typescript/utilities.md +102 -0
  118. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/use-cases/index.md +7 -0
  119. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/use-cases/maker.md +652 -0
  120. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/06-Analytics Engine/use-cases/processors.md +3 -0
  121. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/_category_.json +8 -0
  122. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/images/OperationHistory.png +0 -0
  123. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/images/OperationsQuery.png +0 -0
  124. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/images/QueryDocumentID.png +0 -0
  125. package/docs/academy/02-AdvancedTutorial/04-WorkWithData/images/SwitchboardButton.png +0 -0
  126. package/docs/academy/02-AdvancedTutorial/05-Launch/00-IntegrateInAFront-End +3 -0
  127. package/docs/academy/02-AdvancedTutorial/05-Launch/01-IntroducingFusion +18 -0
  128. package/docs/academy/02-AdvancedTutorial/05-Launch/02-IntroductionToPackages.md +79 -0
  129. package/docs/academy/02-AdvancedTutorial/05-Launch/02-PublishYourProject.md +230 -0
  130. package/docs/academy/02-AdvancedTutorial/05-Launch/03-RunOnACloudServer.md +279 -0
  131. package/docs/academy/02-AdvancedTutorial/05-Launch/03-SetupEnvironment.md +436 -0
  132. package/docs/academy/02-AdvancedTutorial/05-Launch/04-GraphQLNamespacing +44 -0
  133. package/docs/academy/02-AdvancedTutorial/05-Launch/05-LaunchYourBackend.md +3 -0
  134. package/docs/academy/02-AdvancedTutorial/05-Launch/06-LaunchYourFrontend.md +3 -0
  135. package/docs/academy/02-AdvancedTutorial/05-Launch/_category_.json +8 -0
  136. package/docs/academy/02-AdvancedTutorial/05-Launch/images/SSHConnection.png +0 -0
  137. package/docs/academy/02-AdvancedTutorial/05-Launch/images/homedesign.png +0 -0
  138. package/docs/academy/02-AdvancedTutorial/05-Launch/images/keyconcepts.png +0 -0
  139. package/docs/academy/02-AdvancedTutorial/05-Launch/images/tutorialschema.png +0 -0
  140. package/docs/academy/02-AdvancedTutorial/06-Authorization/Authorization.md +100 -0
  141. package/docs/academy/02-AdvancedTutorial/_category_.json +7 -0
  142. package/docs/academy/03-APIReferences/00-PowerhouseCLI.md +1 -0
  143. package/docs/academy/03-APIReferences/_category_.json +7 -0
  144. package/docs/academy/04-ComponentLibrary/01-PowerhouseDesignSystem.md +94 -0
  145. package/docs/academy/04-ComponentLibrary/02-BuildingWithScalars.md +54 -0
  146. package/docs/academy/04-ComponentLibrary/03-Scalar-Components/01-phid-field.mdx +72 -0
  147. package/docs/academy/04-ComponentLibrary/03-Scalar-Components/02-input-field.mdx +0 -0
  148. package/docs/academy/04-ComponentLibrary/04-Complex-Components/01-sidebar.mdx +36 -0
  149. package/docs/academy/04-ComponentLibrary/05-Layout-Components/01-test-toupdate.mdx +61 -0
  150. package/docs/academy/04-ComponentLibrary/06-Fragments/01-test-toupdate.mdx +61 -0
  151. package/docs/academy/04-ComponentLibrary/_category_.json +8 -0
  152. package/docs/academy/05-Architecture/00-PowerhouseArchitecture.md +50 -0
  153. package/docs/academy/05-Architecture/01-WorkingWithTheReactor.md +48 -0
  154. package/docs/academy/05-Architecture/02-ReferencingMonorepoPackages +65 -0
  155. package/docs/academy/05-Architecture/04-MovingBeyondCRUD +61 -0
  156. package/docs/academy/05-Architecture/05-DocumentModelTheory/01-WhatIsADocumentModel.md +188 -0
  157. package/docs/academy/05-Architecture/05-DocumentModelTheory/02-DAOandDocumentsModelsQ+A.md +177 -0
  158. package/docs/academy/05-Architecture/05-DocumentModelTheory/02-domain-modeling.md +103 -0
  159. package/docs/academy/05-Architecture/05-DocumentModelTheory/03-BenefitsOfDocumentModels.md +95 -0
  160. package/docs/academy/05-Architecture/05-DocumentModelTheory/05-best-practices.md +257 -0
  161. package/docs/academy/05-Architecture/05-DocumentModelTheory/_category_.json +8 -0
  162. package/docs/academy/05-Architecture/05-DocumentModelTheory/three-data-layers.png +0 -0
  163. package/docs/academy/05-Architecture/_category_.json +7 -0
  164. package/docs/academy/05-Architecture/images/image.png +0 -0
  165. package/docs/academy/06-Cookbook.md +905 -0
  166. package/docs/academy/07-Glossary.md +50 -0
  167. package/docs/bookofpowerhouse/01-Overview.md +29 -0
  168. package/docs/bookofpowerhouse/02-GeneralFrameworkAndPhilosophy.md +15 -0
  169. package/docs/bookofpowerhouse/03-PowerhouseSoftwareArchitecture.md +33 -0
  170. package/docs/bookofpowerhouse/04-DevelopmentApproaches.md +36 -0
  171. package/docs/bookofpowerhouse/05-SNOsandANewModelForOSSandPublicGoods.md +73 -0
  172. package/docs/bookofpowerhouse/06-SNOsInActionAndPlatformEconomies.md +17 -0
  173. package/docs/renown/01-intro.md +18 -0
  174. package/docs/renown/02-renown-login-flow.md +60 -0
  175. package/docusaurus +0 -0
  176. package/docusaurus.config.ts +170 -0
  177. package/package.json +50 -0
  178. package/powerhouse-docs@0.0.0 +0 -0
  179. package/sidebars.ts +33 -0
  180. package/src/components/HomepageFeatures/index.tsx +250 -0
  181. package/src/components/HomepageFeatures/styles.module.css +267 -0
  182. package/src/css/custom.css +450 -0
  183. package/src/pages/index.module.css +37 -0
  184. package/src/pages/index.tsx +42 -0
  185. package/src/pages/markdown-page.md +7 -0
  186. package/static/.nojekyll +0 -0
  187. package/static/fonts/FranieBold.otf +0 -0
  188. package/static/fonts/FranieRegular.otf +0 -0
  189. package/static/img/Powerhouse Website Drive.png +0 -0
  190. package/static/img/Powerhouse Website Storage Layer (1).png +0 -0
  191. package/static/img/Powerhouse Website Storage Layer.png +0 -0
  192. package/static/img/Powerhouse-main-light.svg +13 -0
  193. package/static/img/Powerhouse-main.svg +13 -0
  194. package/static/img/Renown Intro Diagram.png +0 -0
  195. package/static/img/Union.svg +3 -0
  196. package/static/img/academy/icons/Advanced.svg +4 -0
  197. package/static/img/academy/icons/Book.svg +5 -0
  198. package/static/img/academy/icons/Cookbook.svg +3 -0
  199. package/static/img/academy/icons/Create.svg +3 -0
  200. package/static/img/academy/icons/Data.svg +3 -0
  201. package/static/img/academy/icons/Editor.svg +3 -0
  202. package/static/img/academy/icons/Flash.svg +3 -0
  203. package/static/img/academy/icons/Launch.svg +3 -0
  204. package/static/img/academy-icon.png +0 -0
  205. package/static/img/connect-icon.png +0 -0
  206. package/static/img/connect.png +0 -0
  207. package/static/img/docusaurus-social-card.jpg +0 -0
  208. package/static/img/docusaurus.png +0 -0
  209. package/static/img/empty-background.png +0 -0
  210. package/static/img/favicon.ico +0 -0
  211. package/static/img/fusion-icon.png +0 -0
  212. package/static/img/fusion.png +0 -0
  213. package/static/img/ph-icon-light.svg +3 -0
  214. package/static/img/powerhouse-layer.png +0 -0
  215. package/static/img/powerhouse-storage-layer.png +0 -0
  216. package/static/img/reactor.png +0 -0
  217. package/static/img/renown-icon.png +0 -0
  218. package/static/img/renown.png +0 -0
  219. package/static/img/switchboard-icon.png +0 -0
  220. package/static/img/switchboard.png +0 -0
  221. package/static/img/undraw_docusaurus_mountain.svg +171 -0
  222. package/static/img/undraw_docusaurus_react.svg +170 -0
  223. package/static/img/undraw_docusaurus_tree.svg +40 -0
  224. package/static/img/video-placeholder.svg +16 -0
  225. package/static.json +7 -0
  226. package/tsconfig.json +7 -0
@@ -0,0 +1,149 @@
1
+ ---
2
+ sidebar_position: 0
3
+ ---
4
+
5
+ # Getting Started
6
+
7
+ ## Introduction
8
+
9
+ Welcome to the Powerhouse Analytics Engine Documentation. This engine is a powerful time-series analytics system, written in Typescript with an optional GraphQL interface on top. It is designed to run _anywhere_. Browsers, server environments, CLI tools, etc.
10
+
11
+ This documentation serves as a guide for Typescript and GraphQL API usage, not library development. For documentation on how to build or contribute to this project, see our [README](https://github.com/powerhouse-inc/analytics-engine/blob/main/README.md).
12
+
13
+ ## Overview
14
+
15
+ ![high-level](./images/high-level.jpg)
16
+
17
+ This system can be broken up into several major systems: **queries**, **engine components** (including filters and aggregation), and **storage**. Each of these systems have detailed documentation, but it is most helpful to start with a holistic understanding of the major pieces of data: series and dimensions.
18
+
19
+ ### Series and Dimensions
20
+
21
+ All metrics are collected and stored using only two objects: **AnalyticsSeries** and **AnalyticsDimension**. To be a successful consumer of this system, It is vital to understand the intent of these two pieces of data.
22
+
23
+ ![1](./images/overview-1.jpg)
24
+
25
+ Typical time-series databases (like [Graphite](https://graphiteapp.org/)) usually store data as `(time, value)` tuples: relating an explicit value to an explicit time. In the Web3 space, we have learned through [real uses cases with MakerDAO](https://fusion.sky.money/), that this isn't quite flexible enough for Web3 constructs.
26
+
27
+ Instead, the time series values in this system are given by a value paired with a _time interval_. That is, values have a start and an end. This allows for interpolation functions across a time interval, like a linear change.
28
+
29
+ Of course, the default is simply a constant function, giving a constant value inside of the time interval.
30
+
31
+ ![4](./images/overview-4.jpg)
32
+
33
+ This means that when we want to query data, we are querying over intervals and can query for either "running totals" or changes (deltas) over an interval.
34
+
35
+ In the example above, querying over different intervals returns different totals and deltas depending on interval. This is another difference with typical time-series databases: deltas as first class. The analytics system takes care of this aggregation for users.
36
+
37
+ ![2](./images/overview-2.jpg)
38
+
39
+ In real use cases, we generally have many data sets running in parallel. In this example, we have two related systems, both inserting data. Some of the intervals overlap, some don't, and we see some gaps in the data as well.
40
+
41
+ ![3](./images/overview-3.jpg)
42
+
43
+ The question is: how do we query and aggregate this related data? We could potentially make multiple queries and do this ourselves, but it would require a good understanding of the implementation details.
44
+
45
+ This is where the **AnalyticsDimension** object comes into play.
46
+
47
+ ![4](./images//overview-5.jpg)
48
+
49
+ While there will be thousands or millions of series objects, there will be far fewer referenced dimension objects. Dimensions allow users to decorate series objects with query and aggregation information. These objects are shared across all the series records.
50
+
51
+ Visually, you can think of series as values running up and down, while dimensions allow for query and aggregation _across_ the different series objects.
52
+
53
+ ![6](./images/overview-6.jpg)
54
+
55
+ ### Structure v Reporting
56
+
57
+ The Series and Dimensions objects give control over how metric data is defined and related. That is, they define the **structure** of data. Three new concepts: Paths, LODs, and granularity, are parameters used to define how the system should _report_ the data.
58
+
59
+ ### Paths
60
+
61
+ Let's start with paths. A `path` is a field on an `AnalyticsDimension` that describes the _specificity of the query_.
62
+
63
+ ![1](./images/paths-1.jpg)
64
+
65
+ In this example, inspired by real MakerDAO metrics, we have a number of series values that have been decorated with a couple of dimensions. Dimensions, as we have discussed, have a name like "budget". They also have this `path` field, which looks like a URI or directory hierarchy: a string made up of smaller strings separated by `/`s.
66
+
67
+ Note that, some series values have been decorated with multiple dimensions, some with a single dimension, and some have not been decorated with either.
68
+
69
+ It's clear enough that when we request budget data for a specific MIP dimension, like the purple one (`/atlas/mip40/MIP40c3SP61`), we should be getting totals and deltas across only the purple series objects.
70
+
71
+ But what if we want to query across everything related to `mip40`?
72
+
73
+ ![2](./images/paths-2.jpg)
74
+
75
+ This is the beauty of dimension paths. All we need to do is use a `path` to describe the _specificity_ of the query. In this case, we use `/atlas/mip40`, which will match all dimensions that start with `/atlas/mip40`, which in turn matches all series values related to to those dimensions.
76
+
77
+ ### LODs
78
+
79
+ `LOD` is short for "level of detail", and it is not a field found on either the series or dimension objects. It is a parameter used in queries only, to determine how results are aggregated across dimensions.
80
+
81
+ Let's look at our example again.
82
+
83
+ ![a](./images/paths-2.jpg)
84
+
85
+ Here we have asked for a report on the `budget` metric, with path `/atlast/mip40`. The path determines the specificity of the query, and LOD determines how to aggregate results.
86
+
87
+ ![lod](./images/lod.jpg)
88
+
89
+ An LOD of `0` will group all results together in a single value. An LOD of `1` will group results by the first part of the path, in this case: `/atlas`. And so on for an LOD of 2 or 3. This means that increasing the LOD will increase the number of values retieved as the system needs to aggregate with higher specificity.
90
+
91
+ An LOD greater than the number of parts of the path (in this case, 4 or more) will append a `/*` for each additional path part to the end of the grouped results but will provide the same results as the highest level of detail.
92
+
93
+ ### Granularity
94
+
95
+ While LODs allow you to aggregate series data across dimensions, _granularity_ refers to how data is aggregated over time. It determines the time span each data point or record covers. Choosing the right granularity is crucial for meaningful analysis, as it affects the interpretation and insights that can be drawn from the data.
96
+
97
+ #### Available Options
98
+
99
+ The analytics engine supports various granularity options, each suitable for different types of analysis:
100
+
101
+ 1. `total`: Provides a cumulative view of data over the entire time frame available in the dataset. Best used for overall summaries and long-term analysis.
102
+
103
+ 2. `annual`: Aggregates data on a yearly basis. Ideal for year-over-year comparisons and annual trend analysis.
104
+
105
+ 3. `semiAnnual` : Breaks down data into six-month periods. Useful for understanding bi-annual trends and patterns.
106
+
107
+ 4. `quarterly`: Divides data into quarters, offering insights into seasonal trends or quarter-over-quarter performance.
108
+
109
+ 5. `monthly` : Monthly granularity is useful for a more detailed view of trends and patterns, particularly useful for operational planning and monitoring.
110
+
111
+ 6. `weekly` : Provides weekly data aggregation, which is helpful for short-term performance tracking and operational adjustments.
112
+ daily: Offers a day-to-day breakdown, ideal for detailed analysis of daily operations or events.
113
+
114
+ 7. `hourly`: The most granular level, providing insights into hourly fluctuations. Useful in scenarios where short-term data spikes or dips are significant.
115
+
116
+ #### How Granularity Affects Query Results
117
+
118
+ - Data Volume: Higher granularity (like hourly or daily) results in a larger volume of data points, providing more detailed insights but potentially leading to more complex analysis. Lower granularity (like annual or total) simplifies the data into fewer, broader data points.
119
+
120
+ - Trend Analysis: Finer granularity helps in identifying short-term trends and anomalies, whereas coarser granularity is better for long-term trend analysis and strategic planning.
121
+ Performance Impact: Queries with finer granularity might be more resource-intensive and take longer to execute due to the larger number of data points processed.
122
+
123
+ - Contextual Relevance: The choice of granularity should match the context of the analysis. For instance, financial planning might prefer annual or quarterly granularity, while operational monitoring might require daily or hourly data.
124
+
125
+ - Comparative Analysis: Different granularity levels can be used for comparative analysis, such as comparing detailed daily data (through daily granularity) against broader monthly trends (using monthly granularity) to understand day-to-day variations within the context of a monthly overview.
126
+
127
+ In summary, the choice of granularity in your query significantly influences the scope, detail, and utility of the analytics results. It is important to align the granularity with the specific analytical objectives and the nature of the data being analyzed to ensure that the insights derived are both relevant and actionable.
128
+
129
+ ## Cheatsheet
130
+
131
+ These are high-level definitions of major terms you will need to know.
132
+
133
+ * **AnalyticsSeries** - The individual metric values, comprised of `(value, start, end)`. There should be one of these for every change in value.
134
+
135
+ * **AnalyticsDimension** - Shared objects that decorate series objects with `name` and `path` information. Used to relate metrics to one another.
136
+
137
+ * **Path** - Composable, `/`-delimited string field on dimension that is used to _determine specificity_ during queries.
138
+
139
+ * **LOD** - A number that, when paired with `path`, determines how to aggregate values across dimensions.
140
+
141
+ * **Granularity** - Determines how to aggregate values over time, like "monthly" or "yearly".
142
+
143
+ ## Next Steps
144
+
145
+ Next steps depend on use case.
146
+
147
+ * For developers looking to **input data**, or **query data with Typescript**, see the [Typescript](./typescript/) docs.
148
+ * For developers interested in **querying data with GraphQL**, see the [GraphQL](./graphql/) documentation. Data cannot be input through GraphQL.
149
+ * For developers interested in **contributing to this project**, see the developer documentation [on GitHub](https://github.com/powerhouse-inc/analytics-engine).
@@ -0,0 +1,27 @@
1
+ ---
2
+ sidebar_position: 102
3
+ ---
4
+
5
+ # Benchmarks
6
+
7
+ Due to the performance-sensitive nature of metrics collection, we include a [suite of benchmarks](https://github.com/powerhouse-inc/analytics-engine/tree/main/benchmarks) that compare the various analytics store implementations. These are run every publish and stored in the associated [GitHub action history](https://github.com/powerhouse-inc/analytics-engine/actions/runs/12123429624/job/33798972072).
8
+
9
+ We also include results from major releases [here](https://github.com/powerhouse-inc/analytics-engine/tree/main/benchmarks/results).
10
+
11
+ In summary, we have found that the `MemoryAnalyticsStore` and `PostgresAnalyticsStore` implementations are very close in performance, with the Postgres implementation slightly faster in most applications.
12
+
13
+ ## Query-list
14
+
15
+ In [this benchmark](https://github.com/powerhouse-inc/analytics-engine/blob/main/benchmarks/results/query-list/), we ran the most frequent 600+ real-world queries against matching tables of around 200k records.
16
+
17
+ We found that, on average, the `MemoryAnalyticsStore` implementation took about `1.36x` the time it took `PostgresAnalyticsStore`. Full results [here](https://github.com/powerhouse-inc/analytics-engine/blob/main/benchmarks/results/query-list/pglite.txt).
18
+
19
+ ## WASM
20
+
21
+ In [this benchmark](https://github.com/powerhouse-inc/analytics-engine/blob/main/benchmarks/results/wasm/), we analyze the startup and insert time for the `MemoryAnalyticsStore` implementation.
22
+
23
+ | Operation | Ops per Sec | Average Time |
24
+ | ------------ | ----------- | ------------ |
25
+ | Init | 3 | 323.00 ms |
26
+ | 100 Inserts | 478 | 2.08 ms |
27
+ | 200k Inserts | 0 | 4448.10 ms |
@@ -0,0 +1,77 @@
1
+ ---
2
+ sidebar_position: 2
3
+ ---
4
+
5
+ # Browser Store
6
+
7
+ The `BrowserAnalyticsStore` is an `IAnalyticsStore` implementation that sits on top of [`MemoryAnalyticsStore`](#memory) but adds an `IndexedDB` plugin for persistence.
8
+
9
+ <aside class="notice">
10
+ See the <a href="#compatibility">Compatibility</a> section for details on which stores are intended to be used in different execution environments.
11
+ </aside>
12
+
13
+ ## Construction
14
+
15
+ A default implementation of the `BrowserAnalyticsStore` may be created with no arguments, or options are provided for specialized needs.
16
+
17
+ ```typescript
18
+ // creates a database named "analytics"
19
+ const store = new BrowserAnalyticsStore();
20
+ ```
21
+
22
+ > Create with a specific database name.
23
+
24
+ ```typescript
25
+ const store = new BrowserAnalyticsStore({ databaseName: "analytics" });
26
+ ```
27
+
28
+ > It may also be created with optional contructor arguments that may be helpful for debugging or metrics collection.
29
+
30
+ ```typescript
31
+ const store = new BrowserAnalyticsStore({
32
+ databaseName: "analytics",
33
+
34
+ queryLogger: defaultQueryLogger("browser"),
35
+ resultsLogger: defaultResultsLogger("browser"),
36
+ profiler: new PassthroughAnalyticsProfiler(),
37
+ });
38
+ ```
39
+
40
+ For more details on these optional constructor parameters, see the [Utilities](#utilities) section.
41
+
42
+ Since the constructor options argument extends the `MemoryAnalyticsStore` options argument, see the [`MemoryAnalyticsStore`](#memory) documentation for further details on other optional parameters.
43
+
44
+ ## Initialization
45
+
46
+ Similar to the [`MemoryAnalyticsStore`](#memory), this implementation requires an asynchronous initialization step.
47
+
48
+ > Note that this method is not available on the `IAnalyticsStore` interface, but only on the concrete type.
49
+
50
+ ```typescript
51
+ // create the store
52
+ const store = new BrowserAnalyticsStore();
53
+
54
+ // initialize it
55
+ await store.init();
56
+ ```
57
+
58
+ ## Persistence
59
+
60
+ The `databaseName` constructor argument namespaces the database. This allows users to create multiple stores, if needed, which will not conflict with each other. You can use your browser's developer tools to see these databases, usually through the "Storage" tab.
61
+
62
+ <aside class="notice">
63
+ While manipulating the data manually is not recommended, this allows you to easily delete and recreate databases if needed.
64
+ </aside>
65
+
66
+ ![dev-tools](../images/indexeddb.png)
67
+
68
+ The store interface is intended to be immutable, meaning that it does not provide a general method of wiping a DB. However, an IDB database may be deleted via the standard [IDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API).
69
+
70
+ ```typescript
71
+ // creates the database
72
+ const store = new BrowserAnalyticsStore({ databaseName: "my-analytics" });
73
+ await store.init();
74
+
75
+ // use the browser API to delete the database
76
+ window.indexedDB.deleteDatabase("my-analytics");
77
+ ```
@@ -0,0 +1,14 @@
1
+ ---
2
+ sidebar_position: 101
3
+ ---
4
+
5
+ # Compatibility
6
+
7
+ This guide is intended for making high level decisions about which storage systems to use in which contexts. These stores have not been tested across thousands of browser or serverside runtime versions.
8
+
9
+ | Store | Browser | Node | Bun |
10
+ | ------------------------ | ------- | ---- | --- |
11
+ | `MemoryAnalyticsStore` | X | X | X |
12
+ | `BrowserAnalyticsStore` | X | | |
13
+ | `KnexAnalyticsStore` | X | X | X |
14
+ | `PostgresAnalyticsStore` | | X | X |
@@ -0,0 +1,230 @@
1
+ ---
2
+ sidebar_position: 2
3
+ ---
4
+
5
+ # Typescript API
6
+
7
+ ## Overview
8
+
9
+ The analytics system is broken into several modules, allowing developers to deploy across many environments, for a diverse set of use cases.
10
+
11
+ ![libs](../images/libs.jpg)
12
+
13
+ The `core` library contains common data types and abstractions used throughout. The job of the core library is to link together query, storage, and aggregation logic.
14
+
15
+ ![libs](../images/libs-core.jpg)
16
+
17
+ The `knex`, `pg`, and `browser` libraries contain various storage implementations. Finally, the `graphql` library contains types, resolvers, and data types for a GraphQL API on top.
18
+
19
+ ## Querying Data
20
+
21
+ The entry point for data queries in Typescript is the `AnalyticsQueryEngine`. This wraps an `IAnalyticsStore` implementation, which will be discussed in detail later.
22
+
23
+ In this example, we create a simple in-memory storage engine, compatible with all platforms.
24
+
25
+ ```typescript
26
+ import { AnalyticsQueryEngine } from "@powerhousedao/analytics-core";
27
+ import { MemoryAnalyticsStore } from "@powerhousedao/analytics-memory";
28
+
29
+ const engine = new AnalyticsQueryEngine(new MemoryAnalyticsStore());
30
+ ```
31
+
32
+ ### AnalyticsQuery
33
+
34
+ Queries use the engine's `execute` function, taking an `AnalyticsQuery` parameter:
35
+
36
+ ```typescript
37
+ type AnalyticsQuery = {
38
+ start: DateTime | null;
39
+ end: DateTime | null;
40
+ metrics: string[];
41
+ currency: AnalyticsPath;
42
+ select: Record<string, AnalyticsPath[]>;
43
+ granularity: AnalyticsGranularity;
44
+ lod: Record<string, number | null>;
45
+ };
46
+ ```
47
+
48
+ Each field plays a specific role in determining what data is returned by the analytics engine. Here's a clear and concise description of each:
49
+
50
+ - `start`: This is the starting date and time of the series, using Luxon types. See the [note about times](#a-note-about-times) for more information.
51
+
52
+ - `end`: This is the ending date and time of the series, using Luxon types. See the [note about times](#a-note-about-times) for more information.
53
+
54
+ - `metrics`: Specifies the particular metrics being queried (e.g., `"budget"`). Each element will refer to the `name` field on the related [`AnalyticsDimension` objects](../intro.md#series-and-dimensions).
55
+
56
+ - `currency`: A path reference to the currency to match (e.g. - `"usd"`).
57
+
58
+ - `select`: This object is a map from metric name to a list of paths (e.g. - `{ budget: ["/atlas"] }`). These paths are used for matching via the [`AnalyticsDimension` objects](../intro.md#series-and-dimensions).
59
+
60
+ - `granularity`: This field denotes the aggregation period for the data (e.g., `"monthly"`). A full list of options is available [here](../intro.md#granularity).
61
+
62
+ - `lod`: A map from metric name to the level of detail parameter (e.g. - `3`), described in detail [here](../intro.md#lods).
63
+
64
+ This query structure allows users to extract detailed and summarized analytics data. A full example will look like:
65
+
66
+ ```typescript
67
+ const results = await engine.execute({
68
+ start: DateTime.fromIso("2020-01-01T00:00:00.000Z"),
69
+ end: "2100-01-01T00:00:00.000Z",
70
+ currency: AnalyticsPath.fromArray(["DAI"]),
71
+ metrics: ["Forecast"],
72
+ select: {
73
+ report: [AnalyticsPath.fromArray(["atlas", "EcosystemActor", "50", "2023", "11"])],
74
+ },
75
+ granularity: 0,
76
+ lod: {},
77
+ });
78
+ ```
79
+
80
+ This will return an array of `GroupedPeriodResult`.
81
+
82
+ ### GroupedPeriodResult
83
+
84
+ This object is an aggregate. It represents a combined group of metrics over a time period.
85
+
86
+ ```typescript
87
+ type GroupedPeriodResult = {
88
+ period: string;
89
+ start: DateTime;
90
+ end: DateTime;
91
+ rows: Array<{
92
+ dimensions: Record<string, AnalyticsDimension>;
93
+ metric: string;
94
+ unit: string | null;
95
+ value: number;
96
+ sum: number;
97
+ }>;
98
+ };
99
+ ```
100
+
101
+ - `period`: Within each series, this field denotes the aggregation period for the data (e.g., `"monthly"`), with a short description of which month, year, quarter, etc.
102
+
103
+ - `start`: This is the starting date and time of the series, using Luxon types. See the [note about times](#a-note-about-times) for more information.
104
+
105
+ - `end`: This is the ending date and time of the series, using Luxon types. See the [note about times](#a-note-about-times) for more information.
106
+
107
+ - `rows`: Represents the individual records or entries in the data series. Each row corresponds to a unique combination of dimensions for the specified period.
108
+
109
+ - `metric`: Within each row, this field specifies the particular metric being measured (e.g., `"budget"`).
110
+
111
+ - `unit`: This indicates the unit of measurement for the metric, such as quantities, currency (e.g., `"DAI"`), or percentages.
112
+
113
+ - `dimensions`: A nested array that provides context for the metric by breaking it down into finer categories or segments, such as `"project"` or `"category"`. Each dimension can contain:
114
+ - `name`: The identifier or key for the dimension.
115
+ - `path`: A structured representation of the dimension's hierarchy or location within a dataset.
116
+ - `label`: A human-readable label for the dimension, which can be used for display purposes.
117
+ - `description`: A brief explanation of the dimension to give users an understanding of what it represents.
118
+ - `icon`: A graphical representation or icon associated with the dimension for easier identification in user interfaces.
119
+
120
+ - `value`: The actual numerical value of the metric for each row within the specified period.
121
+
122
+ - `sum`: A total or aggregated value of the metric over the entire period, providing a summarized figure.
123
+
124
+ ### A Note about Times
125
+
126
+ Time is a bit of a sore subject in JavaScript, and we wrestled a bit with how to attack this problem.
127
+
128
+ First, we started with the builtin `Date` type. Unfortunately, `Date` objects are local-time objects. That means that `new Date('2024-12-25')` might mean one time on this machine and another time on someone elses. While `Date` objects _can_ be created using UTC (`new Date('2024-012-25T14:46:22.001Z')`), the resulting `Date` object is still in local time. While `toISO()` does exist, which will output a UTC timestamp, there is no way to tell whether or not the `Date` _was created_ with a UTC timestamp and actually creating the time object the user thought they were creating. Imagining calling the `Date` constructor and ending up with a time different than the one you thought you passed in. Eek.
129
+
130
+ We then considered strings, but those suffer from a load of other problems and they are only really going to be runtime checked.
131
+
132
+ As this is a time-series analytics system, times are rather important to get right, so we thought we'd stick to a data type that has time, date, and timezone information all in one object. Enter the [`luxon`](https://moment.github.io/luxon/#/) library. The luxon library had exactly the data object we were looking for. It is difficult (but not impossible) to create a luxon `DateTime` object with a timezone you weren't intending to use.
133
+
134
+ This is why our analytics API uses these luxon types as inputs and outputs to the system: to make it hard to screw up.
135
+
136
+ ## Inserting Data
137
+
138
+ The `IAnalyticsStore` interface is the primary entry point for inserting and deleting data. Multiple storage implementations are provided, but for simplicity we can get up and running quickly with the [`MemoryAnalyticsStore`](#memory).
139
+
140
+ ```typescript
141
+ import { MemoryAnalyticsStore } from "@powerhousedao/analytics-engine-memory";
142
+
143
+ const store = new MemoryAnalyticsStore();
144
+ ```
145
+
146
+ Data can be added using the `addSeriesValue` method.
147
+
148
+ ```typescript
149
+ import { DateTime } from "luxon";
150
+ import { AnalyticsPath } from "@powerhousedao/analytics-engine-core";
151
+
152
+ const source = AnalyticsPath.fromString("example/insert");
153
+ await store.addSeriesValue([
154
+ {
155
+ start: DateTime.utc(2021, 1, 1),
156
+ source,
157
+ value: 10000,
158
+ unit: "DAI",
159
+ metric: "budget",
160
+ dimensions: {
161
+ budget: AnalyticsPath.fromString("atlas/legacy/core-units/PE-001"),
162
+ category: AnalyticsPath.fromString(
163
+ "atlas/headcount/CompensationAndBenefits/FrontEndEngineering"
164
+ ),
165
+ project: source,
166
+ },
167
+ },
168
+ ]);
169
+ ```
170
+
171
+ ## Subscribing to Data Changes
172
+
173
+ The `IAnalyticsStore` also provides an API for subscribing to data changes. This is achieved by subscribing to an `AnalyticsPath`.
174
+
175
+ ```typescript
176
+ const store = new MemoryAnalyticsStore();
177
+
178
+ // subscribe
179
+ const unsub = store.subscribeToSource(AnalyticsPath.fromString("atlas/"), (source) => {
180
+ console.log('Atlas data was changed!');
181
+
182
+ // decide whether or not to requery
183
+ });
184
+
185
+ // elided
186
+
187
+ // remove your subscription
188
+ unsub();
189
+ ```
190
+
191
+ The subscription API provides many of the same guarantees regarding pathing that the rest of the analytics system does.
192
+
193
+ ```typescript
194
+ store.subscribeToSource(AnalyticsPath.fromString("atlas/"), handler);
195
+
196
+ // this will trigger the handler
197
+ await store.addSeriesValue({ source: AnalyticsPath.fromString("atlas/foo"), ... });
198
+
199
+ // this will trigger the handler
200
+ await store.addSeriesValue({ source: AnalyticsPath.fromString("atlas/foo/bar"), ... });
201
+
202
+ // this will NOT trigger the handler
203
+ await store.addSeriesValue({ source: AnalyticsPath.fromString("rwa/foo"), ... });
204
+ ```
205
+
206
+ Wildcards can also be used at sub-levels of the path.
207
+
208
+ ```typescript
209
+ store.subscribeToSource(AnalyticsPath.fromString("atlas/*/test"), handler);
210
+
211
+ // this will trigger the handler
212
+ await store.addSeriesValue({ source: AnalyticsPath.fromString("atlas/foo/test"), ... });
213
+
214
+ // this will trigger the handler
215
+ await store.addSeriesValue({ source: AnalyticsPath.fromString("atlas/another-thing/test"), ... });
216
+
217
+ // this will trigger the handler
218
+ await store.addSeriesValue({ source: AnalyticsPath.fromString("atlas/foo/test/a/b/c"), ... });
219
+
220
+ // this will NOT trigger the handler
221
+ await store.addSeriesValue({ source: AnalyticsPath.fromString("rwa/foo/test"), ... });
222
+ ```
223
+
224
+ ## Store Implementations
225
+
226
+ Multiple storage implementations are provided, each with comprehensive documentation. See the corresponding docs for:
227
+
228
+ - [MemoryAnalyticsStore](#memory)
229
+ - [BrowserAnalyticsStore](#browser)
230
+ - [PostgresAnalyticsStore](#postgres)
@@ -0,0 +1,72 @@
1
+ ---
2
+ sidebar_position: 1
3
+ ---
4
+
5
+ # Memory Store
6
+
7
+ The `MemoryAnalyticsStore` is an `IAnalyticsStore` implementation that uses a an in-memory database as its storage mechanism. Under the hood, we load a WASM build of Postgres, called [PGlite](https://pglite.dev/).
8
+
9
+ <aside class="notice">
10
+ See the <a href="#compatibility">Compatibility</a> section for details on which stores are intended to be used in different execution environments.
11
+ </aside>
12
+
13
+ ## Construction
14
+
15
+ The `MemoryAnalyticsStore` is simple to create.
16
+
17
+ > Create with no arguments.
18
+
19
+ ```typescript
20
+ const store = new MemoryAnalyticsStore();
21
+ ```
22
+
23
+ > The `MemoryAnalyticsStore` may also be created with optional contructor arguments that may be helpful for debugging or metrics collection.
24
+
25
+ ```typescript
26
+ const store = new MemoryAnalyticsStore({
27
+ queryLogger: querydefaultQueryLogger("memory"),
28
+ resultsLogger: defaultResultsLogger("memory"),
29
+ profiler: new PassthroughAnalyticsProfiler(),
30
+ });
31
+ ```
32
+
33
+ For more details on these optional constructor parameters, see the [Utilities](#utilities) section.
34
+
35
+ > Additionally, both `knex` and `pglite` objects may be passed in. This is helpful in contexts where multiple objects are sharing the same database.
36
+
37
+ ```typescript
38
+ // knex must be created with these options
39
+ const knex = knexFactory({ client: "pg", useNullAsDefault: true });
40
+
41
+ // create your own Pglite instance and pass it in
42
+ // See (https://github.com/electric-sql/pglite/blob/main/packages/pglite/src/interface.ts) for full list of options.
43
+ const pgLiteFactory = () => PGlite.create({
44
+ debug: 3,
45
+ relaxedDurability: false,
46
+ });
47
+
48
+ const store = new MemoryAnalyticsStore({
49
+ knex,
50
+ pgLiteFactory,
51
+ })
52
+ ```
53
+
54
+ ## Initialization
55
+
56
+ While easy to use, the `MemoryAnalyticsStore` requires an asynchronous initialization step. This is for two reasons.
57
+
58
+ In cases where the `MemoryAnalyticsStore` was not provided a `PGlite` instance, it needs time to download and initialize the WASM build.
59
+
60
+ Additionally, it also needs to initialize the database schema of the in-memory database. This is distinct from the <a href="#postgres">Postgres implementation</a>, which assumes a fully-initialized Postgres database already exists. The initialization is idempotent, so tables already created will not be recreated.
61
+
62
+ The full SQL query used can be found in the [`MemoryAnalyticsStore` source](https://github.com/powerhouse-inc/analytics-engine/blob/main/browser/src/MemoryAnalyticsStore.ts).
63
+
64
+ > Note that this method is not available on the `IAnalyticsStore` interface, but only on the `MemoryAnalyticsStore` type.
65
+
66
+ ```typescript
67
+ // create the store
68
+ const store = new MemoryAnalyticsStore();
69
+
70
+ // initialize it
71
+ await store.init();
72
+ ```
@@ -0,0 +1,63 @@
1
+ ---
2
+ sidebar_position: 3
3
+ ---
4
+
5
+ # Postgres Store
6
+
7
+ The `PostgresAnalyticsStore` is an `IAnalyticsStore` implementation that leverages a Postgres database. It requires some APIs that do not run in a browser, and is intended for server-side applications.
8
+
9
+ <aside class="notice">
10
+ See the <a href="#compatibility">Compatibility</a> section for details on which stores are intended to be used in different execution environments.
11
+ </aside>
12
+
13
+ ## Construction
14
+
15
+ The `PostgresAnalyticsStore` uses the [`pg`](https://www.npmjs.com/package/pg) package and requires Postgres connection information.
16
+
17
+ By providing a PG connection string, the store will automatically create a `pg` instance, internally.
18
+
19
+ A docker-compose file is provided [here](https://github.com/powerhouse-inc/analytics-engine/blob/main/pg/docker-compose.test.yml) that will spin up an instance quickly. Note that it cannot be copy/pasted but must be run in the checked out repository to access the correct initialization scripts. See the [developer documentation](https://github.com/powerhouse-inc/analytics-engine/tree/main?tab=readme-ov-file#pg) for more information.
20
+
21
+ > Create with only a connection string.
22
+
23
+ ```typescript
24
+ // connects to a local postgres instance, configured by the provided docker-compose file
25
+ const store = new PostgresAnalyticsStore({
26
+ connectionString: "postgresql://postgres:password@localhost:5555/analytics",
27
+ });
28
+ ```
29
+
30
+ > Instead, create with a `knex` object.
31
+
32
+ ```typescript
33
+ import knexFactory from "knex";
34
+
35
+ const knex = knexFactory({
36
+ client: "pg",
37
+ connection: "...",
38
+ });
39
+
40
+ const store = new PostgresAnalyticsStore({
41
+ knex,
42
+ });
43
+ ```
44
+
45
+ > The `PostgresAnalyticsStore` may also be created with optional contructor arguments that may be helpful for debugging or metrics collection.
46
+
47
+ ```typescript
48
+ const store = new PostgresAnalyticsStore({
49
+ queryLogger: querydefaultQueryLogger("memory"),
50
+ resultsLogger: defaultResultsLogger("memory"),
51
+ profiler: new PassthroughAnalyticsProfiler(),
52
+ });
53
+ ```
54
+
55
+ For more details on these optional constructor parameters, see the [Utilities](#utilities) section.
56
+
57
+ ## Raw Queries
58
+
59
+ Though there is no method on `IAnalyticsStore` for running arbitrary queries, the `PostgresAnalyticsStore` implementation provides a `raw(sql: string)` method. This is used only in development, testing, and [benchmarking](https://github.com/powerhouse-inc/analytics-engine/blob/main/benchmarks/src/wasm.ts) situations and is not intended for production use cases.
60
+
61
+ ```typescript
62
+ const results = store.raw(`select distinct unit from "AnalyticsSeries"`);
63
+ ```
@@ -0,0 +1,14 @@
1
+ # Database Schema
2
+
3
+ ![untitled](../images/dbs.png)
4
+ *Database table structures for the analytics engine.*
5
+
6
+ Analytics information is stored in three database tables:
7
+
8
+ - `AnalyticsSeries`: This table stores the raw data over a period with its metric, value, unit, function and parameters.
9
+ - `AnalyticsDimension`: This table stores all available dimensions for each series.
10
+ - `AnalyticsSeries_AnalyticsDimension`: Many to many lookup table, storing relationships between series and dimensions.
11
+
12
+ The `browser` package automatically creates this schema in the PGLite instance.
13
+
14
+ The `postgres` package, on the other hand, [contains an init script](https://github.com/powerhouse-inc/analytics-engine/blob/main/pg/test/scripts/initdb.sh) that can be used to create the correct schema in your database.