ecoportal-api-graphql 1.3.5 → 1.3.9

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 (499) hide show
  1. checksums.yaml +4 -4
  2. data/.ai-assistance/bridge/CLAUDE.md +338 -0
  3. data/.ai-assistance/bridge/archive/.gitkeep +0 -0
  4. data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.inbox.md +29 -0
  5. data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.outbox.md +18 -0
  6. data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.inbox.md +42 -0
  7. data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.outbox.md +115 -0
  8. data/.ai-assistance/bridge/context/gemini-review-prompt.txt +48 -0
  9. data/.ai-assistance/bridge/context/gemini-review-response.md +104 -0
  10. data/.ai-assistance/bridge/context/project.md +42 -0
  11. data/.ai-assistance/bridge/inbox/.gitkeep +0 -0
  12. data/.ai-assistance/bridge/outbox/.gitkeep +0 -0
  13. data/.ai-assistance/bridge/outbox/request-for-standards-discovery.md +48 -0
  14. data/.ai-assistance/bridge/queue/.gitkeep +1 -0
  15. data/.ai-assistance/capabilities/CLAUDE.md +27 -0
  16. data/.ai-assistance/capabilities/assumptions-log.md +80 -0
  17. data/.ai-assistance/capabilities/code.md +47 -0
  18. data/.ai-assistance/capabilities/connectors.md +37 -0
  19. data/.ai-assistance/capabilities/cowork.md +55 -0
  20. data/.ai-assistance/code/OVERVIEW.md +155 -0
  21. data/.ai-assistance/code/data_fields.md +242 -0
  22. data/.ai-assistance/code/dependencies.md +151 -0
  23. data/.ai-assistance/code/diff_as_input.md +234 -0
  24. data/.ai-assistance/code/diff_service_deep_dive.md +192 -0
  25. data/.ai-assistance/code/ecoPortal_architecture/00_overview_and_index.md +55 -0
  26. data/.ai-assistance/code/ecoPortal_architecture/01_terminology_dictionary.md +181 -0
  27. data/.ai-assistance/code/ecoPortal_architecture/02_data_model.md +192 -0
  28. data/.ai-assistance/code/ecoPortal_architecture/03_api_layers.md +147 -0
  29. data/.ai-assistance/code/ecoPortal_architecture/04_graphql_queries_mutations.md +277 -0
  30. data/.ai-assistance/code/ecoPortal_architecture/05_page_workflows.md +200 -0
  31. data/.ai-assistance/code/ecoPortal_architecture/06_search_and_filters.md +228 -0
  32. data/.ai-assistance/code/ecoPortal_architecture/07_data_fields.md +197 -0
  33. data/.ai-assistance/code/ecoPortal_architecture/08_stages_sections.md +243 -0
  34. data/.ai-assistance/code/ecoPortal_architecture/09_people_contractors_locations.md +196 -0
  35. data/.ai-assistance/code/ecoPortal_architecture/10_forces_workflow_builder.md +132 -0
  36. data/.ai-assistance/code/ecoPortal_architecture/11_integration_gems.md +187 -0
  37. data/.ai-assistance/code/ecoPortal_architecture/12_ai_documentation_sources_gaps.md +236 -0
  38. data/.ai-assistance/code/ecoPortal_architecture/13_ai_infrastructure.md +183 -0
  39. data/.ai-assistance/code/ecoportal_schema_reference.md +240 -0
  40. data/.ai-assistance/code/graphql_domain_knowledge.md +230 -0
  41. data/.ai-assistance/code/refactoring/datafield-readwrite-shape-asymmetry.md +71 -0
  42. data/.ai-assistance/code/refactoring/opportunities.md +251 -0
  43. data/.ai-assistance/code/schema_analysis.md +321 -0
  44. data/.ai-assistance/code/search_filters.md +868 -0
  45. data/.ai-assistance/code/spec_coverage.md +73 -0
  46. data/.ai-assistance/code/workflow-command-guide.md +438 -0
  47. data/.ai-assistance/code/workflow-space.md +353 -0
  48. data/.ai-assistance/conventions/CLAUDE.md +30 -0
  49. data/.ai-assistance/conventions/code-working-tree-protocol.md +199 -0
  50. data/.ai-assistance/conventions/gitignore-rules.md +42 -0
  51. data/.ai-assistance/conventions/permission-guidance.md +120 -0
  52. data/.ai-assistance/integrations/README.md +70 -0
  53. data/.ai-assistance/integrations/gitkraken-mcp.md +107 -0
  54. data/.ai-assistance/integrations/gitlab-mcp.md +123 -0
  55. data/.ai-assistance/integrations/local-git.md +60 -0
  56. data/.ai-assistance/local_paths.example.md +17 -0
  57. data/.ai-assistance/projects/TODO.md +97 -0
  58. data/.ai-assistance/projects/api-v2-to-graphql-migration/DECISIONS.md +168 -0
  59. data/.ai-assistance/projects/api-v2-to-graphql-migration/INTENT.md +60 -0
  60. data/.ai-assistance/projects/api-v2-to-graphql-migration/TODO.md +267 -0
  61. data/.ai-assistance/projects/api-v2-to-graphql-migration/UPSTREAM.md +53 -0
  62. data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/csv-template-pipeline-design.md +102 -0
  63. data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/cutover-usecase-gap-audit.md +139 -0
  64. data/.ai-assistance/projects/dynamic-model-generation/INTENT.md +93 -0
  65. data/.ai-assistance/projects/eco-helpers-compat/INTENT.md +244 -0
  66. data/.ai-assistance/projects/eco-helpers-compat/MIGRATION_GUIDE.md +266 -0
  67. data/.ai-assistance/projects/eco-helpers-compat/TODO.md +86 -0
  68. data/.ai-assistance/projects/ecoportal-api-v2-doublemodel-review/INTENT.md +101 -0
  69. data/.ai-assistance/projects/graphql-agent/GAP_ANALYSIS.md +177 -0
  70. data/.ai-assistance/projects/ooze-graphql-native-migration/DECISIONS.md +161 -0
  71. data/.ai-assistance/projects/ooze-graphql-native-migration/INTENT.md +125 -0
  72. data/.ai-assistance/projects/ooze-graphql-native-migration/RISKS.md +126 -0
  73. data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +256 -0
  74. data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-06-30-cutover-workflow-deep-review.md +122 -0
  75. data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-07-01-forces-via-workflow-commands-miss-rca.md +148 -0
  76. data/.ai-assistance/projects/page-model/DECISIONS.md +245 -0
  77. data/.ai-assistance/projects/page-model/TODO.md +190 -0
  78. data/.ai-assistance/projects/search-filter-builder/INTENT.md +107 -0
  79. data/.ai-assistance/projects/search-filter-builder/TODO.md +131 -0
  80. data/.ai-assistance/projects/template-maintenance/DESIGN.md +134 -0
  81. data/.ai-assistance/projects/workflow-space/TODO.md +213 -0
  82. data/.ai-assistance/reinstall-claude-desktop-windows.md +136 -0
  83. data/.ai-assistance/scripts/CLAUDE.md +150 -0
  84. data/.ai-assistance/scripts/bridge-init.sh +86 -0
  85. data/.ai-assistance/scripts/bridge-status.sh +44 -0
  86. data/.ai-assistance/scripts/capabilities-check.ts +104 -0
  87. data/.ai-assistance/scripts/check-outbox.sh +43 -0
  88. data/.ai-assistance/scripts/dep_graph.rb +91 -0
  89. data/.ai-assistance/scripts/lock-acquire.sh +103 -0
  90. data/.ai-assistance/scripts/lock-multi.sh +124 -0
  91. data/.ai-assistance/scripts/lock-queue.sh +94 -0
  92. data/.ai-assistance/scripts/setup-mcps.test.ts +188 -0
  93. data/.ai-assistance/scripts/setup-mcps.ts +234 -0
  94. data/.ai-assistance/scripts/task-complete.ts +74 -0
  95. data/.ai-assistance/scripts/task-create.ts +75 -0
  96. data/.ai-assistance/scripts/task-read.ts +125 -0
  97. data/.ai-assistance/scripts/token-logger.js +220 -0
  98. data/.ai-assistance/scripts/token-report.ts +158 -0
  99. data/.ai-assistance/scripts/token-session-start.js +66 -0
  100. data/.ai-assistance/skills/ai-instructions/SKILL.md +48 -0
  101. data/.ai-assistance/skills/code-specs/SKILL.md +69 -0
  102. data/.ai-assistance/skills/corporate-policies/SKILL.md +201 -0
  103. data/.ai-assistance/skills/dep-graph/SKILL.md +139 -0
  104. data/.ai-assistance/skills/ep-ai-manager/SKILL.md +417 -0
  105. data/.ai-assistance/skills/gemini-assist/SKILL.md +63 -0
  106. data/.ai-assistance/skills/gemini-assist/gemini-mcp-server.js +205 -0
  107. data/.ai-assistance/skills/gemini-assist/gemini_ask.py +1 -0
  108. data/.ai-assistance/skills/gemini-assist/gemini_ask.rb +240 -0
  109. data/.ai-assistance/skills/gemini-assist/prompts/cycle_end_review.txt +25 -0
  110. data/.ai-assistance/skills/graphql-schema-analysis/SKILL.md +261 -0
  111. data/.ai-assistance/skills/project-cycle/SKILL.md +177 -0
  112. data/.ai-assistance/skills/refactor/SKILL.md +62 -0
  113. data/.ai-assistance/skills/rubocop/SKILL.md +93 -0
  114. data/.ai-assistance/skills/ruby-scripting/SKILL.md +215 -0
  115. data/.ai-assistance/skills/spec-generation/SKILL.md +72 -0
  116. data/.ai-assistance/standards-version.json +21 -0
  117. data/.ai-assistance/token-budget.json +32 -0
  118. data/.ai-assistance/version.json +39 -0
  119. data/.claude/settings.json +146 -0
  120. data/.env.example +18 -0
  121. data/.gitattributes +15 -0
  122. data/.gitignore +13 -0
  123. data/.rubocop.yml +121 -97
  124. data/CHANGELOG.md +673 -477
  125. data/CLAUDE.md +232 -0
  126. data/Gemfile +30 -6
  127. data/Rakefile +90 -38
  128. data/docs/worklog.md +574 -0
  129. data/ecoportal-api-graphql.gemspec +40 -40
  130. data/lib/ecoportal/api/common/graphql/CLAUDE.md +36 -0
  131. data/lib/ecoportal/api/common/graphql/client.rb +1 -1
  132. data/lib/ecoportal/api/common/graphql/http_client.rb +35 -3
  133. data/lib/ecoportal/api/common/graphql/model/CLAUDE.md +28 -0
  134. data/lib/ecoportal/api/common/graphql/model/as_input.rb +8 -5
  135. data/lib/ecoportal/api/common/graphql/model/diffable/classic_diff_service.rb +3 -1
  136. data/lib/ecoportal/api/common/graphql/model/diffable/diff_service.rb +31 -23
  137. data/lib/ecoportal/api/common/graphql/model/diffable/hash_diff_nesting.rb +54 -1
  138. data/lib/ecoportal/api/graphql/CLAUDE.md +37 -0
  139. data/lib/ecoportal/api/graphql/base/CLAUDE.md +50 -0
  140. data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +17 -0
  141. data/lib/ecoportal/api/graphql/base/delta_result.rb +16 -0
  142. data/lib/ecoportal/api/graphql/base/force/binding.rb +19 -0
  143. data/lib/ecoportal/api/graphql/base/force/binding_collection.rb +62 -0
  144. data/lib/ecoportal/api/graphql/base/force/collection.rb +47 -0
  145. data/lib/ecoportal/api/graphql/base/force.rb +65 -0
  146. data/lib/ecoportal/api/graphql/base/kickstand/job.rb +17 -0
  147. data/lib/ecoportal/api/graphql/base/kickstand/workflow.rb +18 -0
  148. data/lib/ecoportal/api/graphql/base/kickstand.rb +13 -0
  149. data/lib/ecoportal/api/graphql/base/page/basic.rb +38 -0
  150. data/lib/ecoportal/api/graphql/base/page/data_field/actions_list.rb +9 -0
  151. data/lib/ecoportal/api/graphql/base/page/data_field/ai_summary.rb +18 -0
  152. data/lib/ecoportal/api/graphql/base/page/data_field/checklist.rb +29 -0
  153. data/lib/ecoportal/api/graphql/base/page/data_field/collection.rb +112 -0
  154. data/lib/ecoportal/api/graphql/base/page/data_field/contractor_entities.rb +28 -0
  155. data/lib/ecoportal/api/graphql/base/page/data_field/cross_reference.rb +54 -0
  156. data/lib/ecoportal/api/graphql/base/page/data_field/date_field.rb +23 -0
  157. data/lib/ecoportal/api/graphql/base/page/data_field/file_field.rb +25 -0
  158. data/lib/ecoportal/api/graphql/base/page/data_field/gauge.rb +19 -0
  159. data/lib/ecoportal/api/graphql/base/page/data_field/geo.rb +24 -0
  160. data/lib/ecoportal/api/graphql/base/page/data_field/image_gallery.rb +24 -0
  161. data/lib/ecoportal/api/graphql/base/page/data_field/law.rb +8 -0
  162. data/lib/ecoportal/api/graphql/base/page/data_field/mailbox.rb +9 -0
  163. data/lib/ecoportal/api/graphql/base/page/data_field/number.rb +20 -0
  164. data/lib/ecoportal/api/graphql/base/page/data_field/people.rb +35 -0
  165. data/lib/ecoportal/api/graphql/base/page/data_field/plain_text.rb +17 -0
  166. data/lib/ecoportal/api/graphql/base/page/data_field/rich_text.rb +26 -0
  167. data/lib/ecoportal/api/graphql/base/page/data_field/select.rb +41 -0
  168. data/lib/ecoportal/api/graphql/base/page/data_field/signature.rb +9 -0
  169. data/lib/ecoportal/api/graphql/base/page/data_field/smart_fill.rb +17 -0
  170. data/lib/ecoportal/api/graphql/base/page/data_field/table.rb +9 -0
  171. data/lib/ecoportal/api/graphql/base/page/data_field/tag_field.rb +21 -0
  172. data/lib/ecoportal/api/graphql/base/page/data_field.rb +137 -12
  173. data/lib/ecoportal/api/graphql/base/page/phased/stage.rb +68 -14
  174. data/lib/ecoportal/api/graphql/base/page/phased.rb +1 -0
  175. data/lib/ecoportal/api/graphql/base/page/section.rb +36 -0
  176. data/lib/ecoportal/api/graphql/base/page/section_collection.rb +79 -0
  177. data/lib/ecoportal/api/graphql/base/page.rb +2 -0
  178. data/lib/ecoportal/api/graphql/base/pages_workflow/action_type_selection.rb +17 -0
  179. data/lib/ecoportal/api/graphql/base/pages_workflow/callback_type.rb +28 -0
  180. data/lib/ecoportal/api/graphql/base/pages_workflow/command_change.rb +17 -0
  181. data/lib/ecoportal/api/graphql/base/pages_workflow/command_change_message.rb +15 -0
  182. data/lib/ecoportal/api/graphql/base/pages_workflow/command_es_change.rb +17 -0
  183. data/lib/ecoportal/api/graphql/base/pages_workflow/command_interface.rb +36 -0
  184. data/lib/ecoportal/api/graphql/base/pages_workflow/email_config.rb +18 -0
  185. data/lib/ecoportal/api/graphql/base/pages_workflow/escalation_level.rb +19 -0
  186. data/lib/ecoportal/api/graphql/base/pages_workflow/in_system_config.rb +16 -0
  187. data/lib/ecoportal/api/graphql/base/pages_workflow/mailbox_field_selection.rb +17 -0
  188. data/lib/ecoportal/api/graphql/base/pages_workflow/operation_interface.rb +39 -0
  189. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/assign_to.rb +27 -0
  190. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/create_page.rb +21 -0
  191. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/send_notification.rb +30 -0
  192. data/lib/ecoportal/api/graphql/base/pages_workflow/people_field_selection.rb +17 -0
  193. data/lib/ecoportal/api/graphql/base/pages_workflow/recipient_config.rb +34 -0
  194. data/lib/ecoportal/api/graphql/base/pages_workflow/register_field.rb +17 -0
  195. data/lib/ecoportal/api/graphql/base/pages_workflow/task_config_selection.rb +17 -0
  196. data/lib/ecoportal/api/graphql/base/pages_workflow/time_delay_config.rb +16 -0
  197. data/lib/ecoportal/api/graphql/base/pages_workflow/trigger_interface.rb +26 -0
  198. data/lib/ecoportal/api/graphql/base/pages_workflow/triggers/conditional_logic.rb +17 -0
  199. data/lib/ecoportal/api/graphql/base/pages_workflow/user_selection.rb +16 -0
  200. data/lib/ecoportal/api/graphql/base/pages_workflow.rb +35 -0
  201. data/lib/ecoportal/api/graphql/base/preset_view.rb +17 -0
  202. data/lib/ecoportal/api/graphql/base/preview_page.rb +23 -0
  203. data/lib/ecoportal/api/graphql/base/register.rb +18 -0
  204. data/lib/ecoportal/api/graphql/base.rb +11 -0
  205. data/lib/ecoportal/api/graphql/builder/CLAUDE.md +65 -0
  206. data/lib/ecoportal/api/graphql/builder/kickstand.rb +73 -0
  207. data/lib/ecoportal/api/graphql/builder/page.rb +210 -41
  208. data/lib/ecoportal/api/graphql/builder/register/preset_view.rb +84 -0
  209. data/lib/ecoportal/api/graphql/builder/register.rb +27 -19
  210. data/lib/ecoportal/api/graphql/builder/template.rb +80 -0
  211. data/lib/ecoportal/api/graphql/builder.rb +2 -0
  212. data/lib/ecoportal/api/graphql/compat/filter_translator.rb +107 -0
  213. data/lib/ecoportal/api/graphql/compat/page_reference.rb +23 -0
  214. data/lib/ecoportal/api/graphql/compat/pages.rb +212 -0
  215. data/lib/ecoportal/api/graphql/compat/registers.rb +84 -0
  216. data/lib/ecoportal/api/graphql/compat/response.rb +35 -0
  217. data/lib/ecoportal/api/graphql/compat/search_results.rb +33 -0
  218. data/lib/ecoportal/api/graphql/compat/stage_collection.rb +70 -0
  219. data/lib/ecoportal/api/graphql/compat/stage_view.rb +76 -0
  220. data/lib/ecoportal/api/graphql/compat.rb +17 -0
  221. data/lib/ecoportal/api/graphql/concerns/data_field_access.rb +71 -0
  222. data/lib/ecoportal/api/graphql/concerns/deprecation.rb +20 -0
  223. data/lib/ecoportal/api/graphql/concerns/fragment_definitions.rb +21 -28
  224. data/lib/ecoportal/api/graphql/concerns/page_compat.rb +51 -0
  225. data/lib/ecoportal/api/graphql/concerns/snake_camel_access.rb +60 -0
  226. data/lib/ecoportal/api/graphql/concerns.rb +4 -0
  227. data/lib/ecoportal/api/graphql/connection/page.rb +11 -0
  228. data/lib/ecoportal/api/graphql/connection/pages_workflow_command.rb +13 -0
  229. data/lib/ecoportal/api/graphql/connection/preset_view.rb +11 -0
  230. data/lib/ecoportal/api/graphql/connection/preview_page.rb +11 -0
  231. data/lib/ecoportal/api/graphql/connection.rb +4 -0
  232. data/lib/ecoportal/api/graphql/file_upload/client.rb +181 -0
  233. data/lib/ecoportal/api/graphql/file_upload.rb +10 -0
  234. data/lib/ecoportal/api/graphql/fragment/action.rb +1 -1
  235. data/lib/ecoportal/api/graphql/fragment/action_category.rb +1 -1
  236. data/lib/ecoportal/api/graphql/fragment/contractor_entity.rb +1 -1
  237. data/lib/ecoportal/api/graphql/fragment/force.rb +30 -0
  238. data/lib/ecoportal/api/graphql/fragment/location_draft.rb +2 -2
  239. data/lib/ecoportal/api/graphql/fragment/location_node.rb +1 -1
  240. data/lib/ecoportal/api/graphql/fragment/locations_error.rb +1 -1
  241. data/lib/ecoportal/api/graphql/fragment/page.rb +85 -0
  242. data/lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb +395 -0
  243. data/lib/ecoportal/api/graphql/fragment/pages.rb +15 -0
  244. data/lib/ecoportal/api/graphql/fragment/pages_workflow.rb +172 -0
  245. data/lib/ecoportal/api/graphql/fragment/pagination.rb +1 -1
  246. data/lib/ecoportal/api/graphql/fragment.rb +37 -27
  247. data/lib/ecoportal/api/graphql/input/contractor_entity/update.rb +25 -0
  248. data/lib/ecoportal/api/graphql/input/delta_input.rb +16 -0
  249. data/lib/ecoportal/api/graphql/input/page/archive.rb +14 -0
  250. data/lib/ecoportal/api/graphql/input/page/build_from_template.rb +13 -0
  251. data/lib/ecoportal/api/graphql/input/page/create_draft.rb +13 -0
  252. data/lib/ecoportal/api/graphql/input/page/create_from_template.rb +18 -0
  253. data/lib/ecoportal/api/graphql/input/page/delete_draft.rb +13 -0
  254. data/lib/ecoportal/api/graphql/input/page/publish_draft.rb +13 -0
  255. data/lib/ecoportal/api/graphql/input/page/review_task.rb +14 -0
  256. data/lib/ecoportal/api/graphql/input/page/unarchive.rb +14 -0
  257. data/lib/ecoportal/api/graphql/input/page/update.rb +140 -0
  258. data/lib/ecoportal/api/graphql/input/page.rb +26 -0
  259. data/lib/ecoportal/api/graphql/input/preset_view/create.rb +18 -0
  260. data/lib/ecoportal/api/graphql/input/preset_view/permission.rb +16 -0
  261. data/lib/ecoportal/api/graphql/input/preset_view/update.rb +16 -0
  262. data/lib/ecoportal/api/graphql/input/preset_view.rb +14 -0
  263. data/lib/ecoportal/api/graphql/input/register/create.rb +18 -0
  264. data/lib/ecoportal/api/graphql/input/register/update.rb +15 -0
  265. data/lib/ecoportal/api/graphql/input/register.rb +13 -0
  266. data/lib/ecoportal/api/graphql/input/search_conf/ai_generator.rb +234 -0
  267. data/lib/ecoportal/api/graphql/input/search_conf.rb +367 -0
  268. data/lib/ecoportal/api/graphql/input/variable_binding.rb +20 -0
  269. data/lib/ecoportal/api/graphql/input/workflow_command/add_action_tag.rb +18 -0
  270. data/lib/ecoportal/api/graphql/input/workflow_command/add_binding.rb +18 -0
  271. data/lib/ecoportal/api/graphql/input/workflow_command/add_comment_tagging_user_group.rb +18 -0
  272. data/lib/ecoportal/api/graphql/input/workflow_command/add_default_direct_strategy_user.rb +18 -0
  273. data/lib/ecoportal/api/graphql/input/workflow_command/add_default_strategy.rb +18 -0
  274. data/lib/ecoportal/api/graphql/input/workflow_command/add_direct_strategy_user.rb +18 -0
  275. data/lib/ecoportal/api/graphql/input/workflow_command/add_field.rb +18 -0
  276. data/lib/ecoportal/api/graphql/input/workflow_command/add_force.rb +18 -0
  277. data/lib/ecoportal/api/graphql/input/workflow_command/add_gauge_field_stop.rb +19 -0
  278. data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_field_config.rb +23 -0
  279. data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_helper.rb +18 -0
  280. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation.rb +18 -0
  281. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_direct_strategy_user.rb +18 -0
  282. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_strategy.rb +18 -0
  283. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_action_type.rb +18 -0
  284. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_filter.rb +18 -0
  285. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_people_field.rb +18 -0
  286. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_task_config.rb +18 -0
  287. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_user.rb +18 -0
  288. data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback.rb +23 -0
  289. data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback_action.rb +18 -0
  290. data/lib/ecoportal/api/graphql/input/workflow_command/add_section.rb +18 -0
  291. data/lib/ecoportal/api/graphql/input/workflow_command/add_select_field_option.rb +19 -0
  292. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage.rb +18 -0
  293. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_section.rb +18 -0
  294. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_tag.rb +18 -0
  295. data/lib/ecoportal/api/graphql/input/workflow_command/add_strategy.rb +18 -0
  296. data/lib/ecoportal/api/graphql/input/workflow_command/add_task.rb +18 -0
  297. data/lib/ecoportal/api/graphql/input/workflow_command/add_task_assignment_user_group.rb +18 -0
  298. data/lib/ecoportal/api/graphql/input/workflow_command/add_workflow_callback.rb +18 -0
  299. data/lib/ecoportal/api/graphql/input/workflow_command/collapse_section.rb +18 -0
  300. data/lib/ecoportal/api/graphql/input/workflow_command/edit_binding.rb +18 -0
  301. data/lib/ecoportal/api/graphql/input/workflow_command/edit_creator_permissions.rb +18 -0
  302. data/lib/ecoportal/api/graphql/input/workflow_command/edit_default_strategy.rb +18 -0
  303. data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +21 -0
  304. data/lib/ecoportal/api/graphql/input/workflow_command/edit_force.rb +18 -0
  305. data/lib/ecoportal/api/graphql/input/workflow_command/edit_gauge_field_stop.rb +19 -0
  306. data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_field_config.rb +19 -0
  307. data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_helper.rb +18 -0
  308. data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation.rb +18 -0
  309. data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation_strategy.rb +18 -0
  310. data/lib/ecoportal/api/graphql/input/workflow_command/edit_page.rb +28 -0
  311. data/lib/ecoportal/api/graphql/input/workflow_command/edit_page_creator_permissions.rb +18 -0
  312. data/lib/ecoportal/api/graphql/input/workflow_command/edit_reminder.rb +18 -0
  313. data/lib/ecoportal/api/graphql/input/workflow_command/edit_required_sign_offs.rb +18 -0
  314. data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_comment_tagging.rb +18 -0
  315. data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_task_assignment.rb +18 -0
  316. data/lib/ecoportal/api/graphql/input/workflow_command/edit_scheduled_callback.rb +22 -0
  317. data/lib/ecoportal/api/graphql/input/workflow_command/edit_section_header.rb +18 -0
  318. data/lib/ecoportal/api/graphql/input/workflow_command/edit_select_field_option.rb +19 -0
  319. data/lib/ecoportal/api/graphql/input/workflow_command/edit_stage.rb +18 -0
  320. data/lib/ecoportal/api/graphql/input/workflow_command/edit_strategy.rb +18 -0
  321. data/lib/ecoportal/api/graphql/input/workflow_command/edit_task_due.rb +18 -0
  322. data/lib/ecoportal/api/graphql/input/workflow_command/edit_trigger.rb +18 -0
  323. data/lib/ecoportal/api/graphql/input/workflow_command/expand_section.rb +18 -0
  324. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/contractor_entities.rb +24 -0
  325. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +23 -0
  326. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/date.rb +20 -0
  327. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/gauge.rb +20 -0
  328. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/image_gallery.rb +20 -0
  329. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/location_field.rb +24 -0
  330. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/people.rb +24 -0
  331. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +20 -0
  332. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/rich_text.rb +20 -0
  333. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/select.rb +20 -0
  334. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/signature.rb +20 -0
  335. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/table.rb +25 -0
  336. data/lib/ecoportal/api/graphql/input/workflow_command/move_field.rb +18 -0
  337. data/lib/ecoportal/api/graphql/input/workflow_command/move_stage.rb +18 -0
  338. data/lib/ecoportal/api/graphql/input/workflow_command/remove_action_tag.rb +18 -0
  339. data/lib/ecoportal/api/graphql/input/workflow_command/remove_binding.rb +18 -0
  340. data/lib/ecoportal/api/graphql/input/workflow_command/remove_callback.rb +18 -0
  341. data/lib/ecoportal/api/graphql/input/workflow_command/remove_comment_tagging_user_group.rb +18 -0
  342. data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_direct_strategy_user.rb +18 -0
  343. data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_strategy.rb +18 -0
  344. data/lib/ecoportal/api/graphql/input/workflow_command/remove_direct_strategy_user.rb +18 -0
  345. data/lib/ecoportal/api/graphql/input/workflow_command/remove_field.rb +18 -0
  346. data/lib/ecoportal/api/graphql/input/workflow_command/remove_force.rb +18 -0
  347. data/lib/ecoportal/api/graphql/input/workflow_command/remove_gauge_field_stop.rb +17 -0
  348. data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_field_config.rb +17 -0
  349. data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_helper.rb +18 -0
  350. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation.rb +18 -0
  351. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_direct_strategy_user.rb +18 -0
  352. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_strategy.rb +18 -0
  353. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_action_type.rb +18 -0
  354. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_filter.rb +18 -0
  355. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_people_field.rb +18 -0
  356. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_task_config.rb +18 -0
  357. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_user.rb +18 -0
  358. data/lib/ecoportal/api/graphql/input/workflow_command/remove_scheduled_callback.rb +18 -0
  359. data/lib/ecoportal/api/graphql/input/workflow_command/remove_section.rb +18 -0
  360. data/lib/ecoportal/api/graphql/input/workflow_command/remove_select_field_option.rb +17 -0
  361. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage.rb +18 -0
  362. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_section.rb +18 -0
  363. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_tag.rb +18 -0
  364. data/lib/ecoportal/api/graphql/input/workflow_command/remove_strategy.rb +18 -0
  365. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task.rb +18 -0
  366. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_assignment_user_group.rb +18 -0
  367. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_due.rb +18 -0
  368. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_priority_level.rb +18 -0
  369. data/lib/ecoportal/api/graphql/input/workflow_command/reorder_forces.rb +18 -0
  370. data/lib/ecoportal/api/graphql/input/workflow_command/reorder_section.rb +18 -0
  371. data/lib/ecoportal/api/graphql/input/workflow_command.rb +251 -0
  372. data/lib/ecoportal/api/graphql/input.rb +8 -0
  373. data/lib/ecoportal/api/graphql/interface/base_page.rb +100 -58
  374. data/lib/ecoportal/api/graphql/interface/location_structure/nodes.rb +27 -28
  375. data/lib/ecoportal/api/graphql/logic/base_model.rb +2 -0
  376. data/lib/ecoportal/api/graphql/logic/base_query.rb +45 -2
  377. data/lib/ecoportal/api/graphql/logic/input.rb +15 -0
  378. data/lib/ecoportal/api/graphql/model/ai_summary_version.rb +10 -0
  379. data/lib/ecoportal/api/graphql/model/organization.rb +65 -55
  380. data/lib/ecoportal/api/graphql/model/page/basic.rb +14 -0
  381. data/lib/ecoportal/api/graphql/model/page/phased.rb +82 -20
  382. data/lib/ecoportal/api/graphql/model/page.rb +1 -0
  383. data/lib/ecoportal/api/graphql/model/page_union.rb +21 -0
  384. data/lib/ecoportal/api/graphql/model/pages_workflow.rb +20 -0
  385. data/lib/ecoportal/api/graphql/model/preset_view.rb +10 -0
  386. data/lib/ecoportal/api/graphql/model/preview_page.rb +10 -0
  387. data/lib/ecoportal/api/graphql/model/register.rb +10 -0
  388. data/lib/ecoportal/api/graphql/model.rb +8 -0
  389. data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +45 -0
  390. data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +40 -0
  391. data/lib/ecoportal/api/graphql/mutation/ai_summary.rb +13 -0
  392. data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_jobs.rb +43 -0
  393. data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_workflows.rb +43 -0
  394. data/lib/ecoportal/api/graphql/mutation/kickstand/fail_job.rb +39 -0
  395. data/lib/ecoportal/api/graphql/mutation/kickstand/fail_workflow.rb +39 -0
  396. data/lib/ecoportal/api/graphql/mutation/kickstand/start_job.rb +39 -0
  397. data/lib/ecoportal/api/graphql/mutation/kickstand/start_workflow.rb +39 -0
  398. data/lib/ecoportal/api/graphql/mutation/kickstand/stop_workflow.rb +39 -0
  399. data/lib/ecoportal/api/graphql/mutation/kickstand.rb +18 -0
  400. data/lib/ecoportal/api/graphql/mutation/location_structure/apply_commands.rb +3 -3
  401. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/add_commands.rb +2 -2
  402. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/create.rb +2 -2
  403. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/drop_bad_commands.rb +3 -3
  404. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/publish.rb +3 -3
  405. data/lib/ecoportal/api/graphql/mutation/page/approve_review_task.rb +40 -0
  406. data/lib/ecoportal/api/graphql/mutation/page/archive.rb +40 -0
  407. data/lib/ecoportal/api/graphql/mutation/page/batch_update_review_task.rb +40 -0
  408. data/lib/ecoportal/api/graphql/mutation/page/build_from_template.rb +50 -0
  409. data/lib/ecoportal/api/graphql/mutation/page/create_draft.rb +40 -0
  410. data/lib/ecoportal/api/graphql/mutation/page/create_from_template.rb +43 -0
  411. data/lib/ecoportal/api/graphql/mutation/page/delete_draft.rb +40 -0
  412. data/lib/ecoportal/api/graphql/mutation/page/execute_force_commands.rb +69 -0
  413. data/lib/ecoportal/api/graphql/mutation/page/execute_workflow_commands.rb +51 -0
  414. data/lib/ecoportal/api/graphql/mutation/page/publish_draft.rb +40 -0
  415. data/lib/ecoportal/api/graphql/mutation/page/reject_review_task.rb +40 -0
  416. data/lib/ecoportal/api/graphql/mutation/page/restart_review_task.rb +40 -0
  417. data/lib/ecoportal/api/graphql/mutation/page/unarchive.rb +40 -0
  418. data/lib/ecoportal/api/graphql/mutation/page/undo_review_task.rb +40 -0
  419. data/lib/ecoportal/api/graphql/mutation/page/update.rb +40 -0
  420. data/lib/ecoportal/api/graphql/mutation/page/update_variable_bindings.rb +44 -0
  421. data/lib/ecoportal/api/graphql/mutation/page.rb +28 -0
  422. data/lib/ecoportal/api/graphql/mutation/preset_view/create.rb +35 -0
  423. data/lib/ecoportal/api/graphql/mutation/preset_view/destroy.rb +35 -0
  424. data/lib/ecoportal/api/graphql/mutation/preset_view/permission.rb +37 -0
  425. data/lib/ecoportal/api/graphql/mutation/preset_view/update.rb +35 -0
  426. data/lib/ecoportal/api/graphql/mutation/preset_view.rb +15 -0
  427. data/lib/ecoportal/api/graphql/mutation/register/create.rb +35 -0
  428. data/lib/ecoportal/api/graphql/mutation/register/destroy.rb +35 -0
  429. data/lib/ecoportal/api/graphql/mutation/register/update.rb +35 -0
  430. data/lib/ecoportal/api/graphql/mutation/register.rb +14 -0
  431. data/lib/ecoportal/api/graphql/mutation/smart_fill/generate.rb +36 -0
  432. data/lib/ecoportal/api/graphql/mutation/smart_fill/submit_feedback.rb +40 -0
  433. data/lib/ecoportal/api/graphql/mutation/smart_fill.rb +13 -0
  434. data/lib/ecoportal/api/graphql/mutation/template/create.rb +39 -0
  435. data/lib/ecoportal/api/graphql/mutation/template/create_related_page.rb +46 -0
  436. data/lib/ecoportal/api/graphql/mutation/template/destroy_related_page.rb +43 -0
  437. data/lib/ecoportal/api/graphql/mutation/template/publish.rb +39 -0
  438. data/lib/ecoportal/api/graphql/mutation/template/unpublish.rb +39 -0
  439. data/lib/ecoportal/api/graphql/mutation/template/update.rb +43 -0
  440. data/lib/ecoportal/api/graphql/mutation/template/update_information.rb +43 -0
  441. data/lib/ecoportal/api/graphql/mutation/template.rb +18 -0
  442. data/lib/ecoportal/api/graphql/mutation.rb +8 -0
  443. data/lib/ecoportal/api/graphql/payload/ai_summary_generate.rb +12 -0
  444. data/lib/ecoportal/api/graphql/payload/execute_workflow_commands.rb +36 -0
  445. data/lib/ecoportal/api/graphql/payload/force_commands.rb +31 -0
  446. data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_jobs.rb +36 -0
  447. data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_workflows.rb +36 -0
  448. data/lib/ecoportal/api/graphql/payload/kickstand/job.rb +13 -0
  449. data/lib/ecoportal/api/graphql/payload/kickstand/workflow.rb +13 -0
  450. data/lib/ecoportal/api/graphql/payload/kickstand.rb +15 -0
  451. data/lib/ecoportal/api/graphql/payload/location_structure/draft/create.rb +33 -34
  452. data/lib/ecoportal/api/graphql/payload/ok_payload.rb +21 -0
  453. data/lib/ecoportal/api/graphql/payload/page/archive.rb +13 -0
  454. data/lib/ecoportal/api/graphql/payload/page/build_from_template.rb +13 -0
  455. data/lib/ecoportal/api/graphql/payload/page/create_from_template.rb +13 -0
  456. data/lib/ecoportal/api/graphql/payload/page/draft.rb +13 -0
  457. data/lib/ecoportal/api/graphql/payload/page/review_task.rb +13 -0
  458. data/lib/ecoportal/api/graphql/payload/page/unarchive.rb +13 -0
  459. data/lib/ecoportal/api/graphql/payload/page/update.rb +13 -0
  460. data/lib/ecoportal/api/graphql/payload/page/update_variable_bindings.rb +13 -0
  461. data/lib/ecoportal/api/graphql/payload/page.rb +19 -0
  462. data/lib/ecoportal/api/graphql/payload/preset_view.rb +11 -0
  463. data/lib/ecoportal/api/graphql/payload/register.rb +11 -0
  464. data/lib/ecoportal/api/graphql/payload/template/create.rb +13 -0
  465. data/lib/ecoportal/api/graphql/payload/template/create_related_page.rb +13 -0
  466. data/lib/ecoportal/api/graphql/payload/template/destroy_related_page.rb +13 -0
  467. data/lib/ecoportal/api/graphql/payload/template/publish.rb +13 -0
  468. data/lib/ecoportal/api/graphql/payload/template/unpublish.rb +13 -0
  469. data/lib/ecoportal/api/graphql/payload/template/update.rb +13 -0
  470. data/lib/ecoportal/api/graphql/payload/template/update_information.rb +13 -0
  471. data/lib/ecoportal/api/graphql/payload/template.rb +18 -0
  472. data/lib/ecoportal/api/graphql/payload.rb +11 -0
  473. data/lib/ecoportal/api/graphql/query/action.rb +1 -1
  474. data/lib/ecoportal/api/graphql/query/action_categories.rb +1 -1
  475. data/lib/ecoportal/api/graphql/query/actions.rb +2 -2
  476. data/lib/ecoportal/api/graphql/query/contractor_entities.rb +1 -1
  477. data/lib/ecoportal/api/graphql/query/file_upload_signature.rb +76 -0
  478. data/lib/ecoportal/api/graphql/query/location_structure/draft.rb +2 -2
  479. data/lib/ecoportal/api/graphql/query/location_structure.rb +1 -1
  480. data/lib/ecoportal/api/graphql/query/location_structures.rb +1 -1
  481. data/lib/ecoportal/api/graphql/query/page.rb +45 -0
  482. data/lib/ecoportal/api/graphql/query/page_delta.rb +47 -0
  483. data/lib/ecoportal/api/graphql/query/page_with_forces.rb +43 -0
  484. data/lib/ecoportal/api/graphql/query/pages.rb +59 -0
  485. data/lib/ecoportal/api/graphql/query/pages_workflow_commands.rb +59 -0
  486. data/lib/ecoportal/api/graphql/query/register_preset_views.rb +78 -0
  487. data/lib/ecoportal/api/graphql/query/register_preview_pages.rb +83 -0
  488. data/lib/ecoportal/api/graphql/query/templates.rb +53 -0
  489. data/lib/ecoportal/api/graphql/query.rb +11 -0
  490. data/lib/ecoportal/api/graphql.rb +60 -2
  491. data/lib/ecoportal/api/graphql_version.rb +5 -5
  492. data/scripts/auto-worker-scheduler.sh +386 -0
  493. data/tests/contractor_entity_create.rb +19 -19
  494. data/tests/contractor_entity_udpate.rb +20 -20
  495. data/tests/dump_page_model.rb +74 -0
  496. data/tests/loc_structure_get.rb +1 -2
  497. data/tests/loc_structure_update.rb +51 -51
  498. data/tests/loc_structures_get.rb +15 -15
  499. metadata +436 -5
@@ -0,0 +1,147 @@
1
+ # EcoPortal API Layers
2
+
3
+ ---
4
+
5
+ ## Overview
6
+
7
+ EcoPortal has three API access layers, each serving different purposes and eras:
8
+
9
+ | Layer | Type | Status | gem |
10
+ |-------|------|--------|-----|
11
+ | APIv1 (OAuth) | REST | Active — auth only | n/a (direct HTTP) |
12
+ | APIv2 | REST | **BEING RETIRED** (~2026-06-07 + 3 weeks) | `ecoportal-api-v2` |
13
+ | GraphQL API | GraphQL | **Current standard** | `ecoportal-api-graphql` |
14
+ | APIv3 (page render) | REST (likely) | In development — custom exports | Not yet public |
15
+
16
+ ---
17
+
18
+ ## Authentication (APIv1 / OAuth)
19
+
20
+ All access goes through OAuth 2.0 password grant:
21
+
22
+ ```
23
+ POST https://live.ecoportal.com/oauth/token
24
+ Content-Type: application/json
25
+
26
+ {
27
+ "grant_type": "password",
28
+ "email": "user@example.com",
29
+ "password": "..."
30
+ }
31
+ ```
32
+
33
+ Response includes `access_token` (Bearer) and `refresh_token`.
34
+
35
+ **Token refresh:**
36
+ ```
37
+ POST /oauth/token
38
+ { "grant_type": "refresh_token", "refresh_token": "..." }
39
+ ```
40
+
41
+ The `access_token` is passed as `Authorization: Bearer <token>` on all subsequent calls.
42
+
43
+ ---
44
+
45
+ ## APIv2 (REST) — Being Retired
46
+
47
+ **Base URL:** `https://live.ecoportal.com/api/<org_id>/`
48
+
49
+ **Ruby gem:** `Ecoportal::API::V2` in `ecoportal-api-v2`
50
+
51
+ **Local path:** `C:\ruby_scripts\git\ecoportal-api-v2`
52
+
53
+ **Key characteristics:**
54
+ - REST API with resource-based endpoints
55
+ - Returns full page documents as JSON
56
+ - Stage rendering: one GET request per stage (pages with stages must be fetched
57
+ stage-by-stage due to access control — each stage can have different user permissions)
58
+ - Only pages WITHOUT stages AND templates can be fetched/updated as a whole document
59
+ - Full document sent on update (partial updates not cleanly supported)
60
+ - Page updates tracked via `as_update` (dirty diff) which generates a JSON patch
61
+
62
+ **eco-helpers interface:**
63
+ ```ruby
64
+ apiv2.pages.get(id, stage_id: nil) # fetch page (or specific stage)
65
+ apiv2.pages.get_new(template_id) # build draft from template
66
+ apiv2.pages.create(page, from: template_id) # create instance
67
+ apiv2.pages.update(page) # save changes
68
+ apiv2.registers.search(register_id, opts) { |result| ... } # paginated search
69
+ ```
70
+
71
+ ---
72
+
73
+ ## GraphQL API — Current Standard
74
+
75
+ **Endpoint:** `POST https://live.ecoportal.com/api/<org_id>/external/graphql`
76
+
77
+ **Headers required:**
78
+ - `Content-Type: application/json`
79
+ - `Authorization: Bearer <access_token>`
80
+
81
+ **Request payload:**
82
+ ```json
83
+ {
84
+ "query": "query MyQuery($id: ID!) { ... }",
85
+ "variables": { "id": "..." },
86
+ "operationName": "MyQuery"
87
+ }
88
+ ```
89
+
90
+ **Key characteristics:**
91
+ - ONE endpoint — no URL variation by resource
92
+ - Client specifies exactly which fields to return
93
+ - Full page fetched in ONE request (all stages included)
94
+ - Stage-specific operations via `stageId` parameter
95
+ - `patchVer` required on all update mutations (optimistic concurrency)
96
+ - Multiple mutations can be combined in one request (executed in declaration order)
97
+ - `searchConf` is a Hash type (`Search`) — not a typed GraphQL input
98
+
99
+ **GraphQL gem:** `Ecoportal::API::GraphQL` in `ecoportal-api-graphql`
100
+
101
+ **Local path:** `C:\ruby_scripts\git\ecoportal-api-graphql` (THIS REPO)
102
+
103
+ **Schema reference:** Live schema at `https://live.ecoportal.com/api-docs/graphql`
104
+ (requires login). Updated on every deployment.
105
+
106
+ ---
107
+
108
+ ## APIv3 (Page Render / Custom Exports) — In Development
109
+
110
+ **Purpose:** Custom page rendering for exports (PDF, etc.). Provides a page render
111
+ endpoint separate from the main GraphQL API.
112
+
113
+ **Status:** In development as of 2026-06-07. Not yet production-stable for scripting.
114
+ Not covered in this gem.
115
+
116
+ ---
117
+
118
+ ## APIv2 vs GraphQL: Key Differences for Scripts
119
+
120
+ | Concern | APIv2 | GraphQL |
121
+ |---------|-------|---------|
122
+ | Stage fetch | One request per stage | Full page in one request |
123
+ | Field IDs | Available after get | Available after buildFromTemplate |
124
+ | Update scope | Full doc or stage doc | Partial: only specify what changes |
125
+ | patchVer | Not required (v2 handles internally) | **REQUIRED** on all updates |
126
+ | Filter format | `{ type: "date_filter", lbound:, ubound: }` | `{ operation: "date_filter", params: { gte:, lte: } }` |
127
+ | Archived pages | Search returns them with flag | Default excluded; `includeArchived: true` opt-in |
128
+ | Template update | Supported | **NOT recommended** (Engineering block) |
129
+ | Search result | Full page data | Org: full DB page; Register: ES preview only |
130
+
131
+ ---
132
+
133
+ ## eco-helpers Compat Layer
134
+
135
+ Since APIv2 is being retired, the `ecoportal-api-graphql` gem provides a compatibility
136
+ layer so existing eco-helpers scripts can work without modification:
137
+
138
+ ```ruby
139
+ graphql = Ecoportal::API::GraphQL.new(email:, pass:, org_id:)
140
+ graphql.pages # → Compat::Pages (same interface as apiv2.pages)
141
+ graphql.registers # → Compat::Registers (same interface as apiv2.registers)
142
+ ```
143
+
144
+ Page models include `Concerns::SnakeCamelAccess` — all camelCase methods accessible
145
+ as snake_case (`external_id`, `patch_ver`, `source_template_id`, `creator_name`, etc.).
146
+
147
+ See `11_integration_gems.md` for full compat layer details.
@@ -0,0 +1,277 @@
1
+ # EcoPortal GraphQL Queries and Mutations
2
+
3
+ ---
4
+
5
+ ## Query Root (`currentOrganization`)
6
+
7
+ All queries nest under `currentOrganization`. There is no top-level resource query —
8
+ everything is scoped to the authenticated user's organisation.
9
+
10
+ ```graphql
11
+ {
12
+ currentOrganization {
13
+ id
14
+ # All other queries go here
15
+ }
16
+ }
17
+ ```
18
+
19
+ ---
20
+
21
+ ## Page Queries
22
+
23
+ ### `page(id: ID!)` → `PageUnion`
24
+
25
+ Fetches a single page by ID. Returns `BasicPage | PhasedPage`.
26
+
27
+ ```graphql
28
+ query GetPage($id: ID!) {
29
+ currentOrganization {
30
+ page(id: $id) {
31
+ ...PageFields # core metadata
32
+ ...PhasedPageFields # stage index (if phased)
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ **Gem class:** `Query::Page`
39
+ **For compat (full data):** Use `...CommonPageUnion` fragment (includes all field data).
40
+
41
+ ### `pages(...)` → `PageUnionConnection`
42
+
43
+ Org-wide paginated page search. Returns full `PageUnion` from DB.
44
+
45
+ **Arguments:**
46
+ - `searchConf: Search` — filter/sort/query configuration
47
+ - `templatesOnly: Boolean` — restrict to templates only
48
+ - `showHiddenData: Boolean` — include hidden fields
49
+ - `after/before/first/last` — cursor pagination
50
+
51
+ **Performance note:** ~3 seconds per page on render (DB-backed). Avoid large result sets.
52
+
53
+ ```graphql
54
+ query OrgSearchPages($searchConf: Search, $first: Int, $after: String) {
55
+ currentOrganization {
56
+ pages(searchConf: $searchConf, first: $first, after: $after) {
57
+ totalCount
58
+ pageInfo { hasNextPage endCursor }
59
+ nodes { ...PageFields }
60
+ }
61
+ }
62
+ }
63
+ ```
64
+
65
+ **Gem class:** `Query::Pages`
66
+
67
+ ### `templates(...)` → `PageConnection`
68
+
69
+ Lists templates (pages with `templatesOnly: true`). Same arguments as `pages`.
70
+
71
+ **Gem class:** `Query::Templates`
72
+
73
+ ### `register(id:) { previewPages(...) }` → `PreviewPageConnection`
74
+
75
+ ES-backed fast register search. Returns `PreviewPage` — metadata only, no field IDs.
76
+
77
+ **Arguments on `previewPages`:**
78
+ - `searchConf: Search`
79
+ - `includeArchived: Boolean` (default false)
80
+ - `presetViewId: ID` — apply a register PageView preset
81
+
82
+ **Performance:** Sub-second (Elasticsearch). Use for metadata lookup.
83
+ **Limitation:** No `patchVer`, no field IDs. Cannot be used for mutation input building.
84
+
85
+ ```graphql
86
+ query RegisterSearch($registerId: ID!, $search: Search, $includeArchived: Boolean) {
87
+ currentOrganization {
88
+ register(id: $registerId) {
89
+ previewPages(searchConf: $search, includeArchived: $includeArchived) {
90
+ totalCount
91
+ pageInfo { hasNextPage endCursor }
92
+ nodes { id uid name state archived externalId createdAt { dateTime } }
93
+ }
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ **Gem class:** `Query::RegisterPreviewPages`
100
+
101
+ ### `pageDelta(deltaInput: [DeltaInput!]!, searchConf: Search)` → `[DeltaResult!]!`
102
+
103
+ Cache-invalidation query. Given a list of `{ id, deltaAt }` pairs, returns which pages
104
+ have changed since the given timestamp.
105
+
106
+ **`DeltaResult`:** `{ id: ID!, delta: DeltaEnum! }` where `DeltaEnum = UPDATED | NOT_FOUND | NEW`
107
+
108
+ **Gem class:** `Query::PageDelta`
109
+
110
+ ---
111
+
112
+ ## Page Mutations
113
+
114
+ ### `buildPageFromTemplate(input: BuildFromTemplateInput!)` → `BuildFromTemplatePayload`
115
+
116
+ **Step (a) of the 2-step create sequence.** Builds a draft without persisting it.
117
+ Returns a `PageUnion` with server-assigned field IDs (the template's field IDs mapped
118
+ to new instance IDs). Use these IDs to populate `dataFields.updates` in `createFromTemplate`.
119
+
120
+ ```graphql
121
+ mutation BuildPage($input: BuildFromTemplateInput!) {
122
+ buildPageFromTemplate(input: $input) {
123
+ errors { details fullMessages }
124
+ item { ...CommonPageUnion }
125
+ }
126
+ }
127
+ ```
128
+
129
+ **Variables:** `{ templateId: "...", showHiddenData: true }`
130
+
131
+ ### `createPageFromTemplate(input: CreateFromTemplateInput!)` → `CreateFromTemplatePayload`
132
+
133
+ **Step (b) of the 2-step create sequence.** Creates the page from a filled draft.
134
+
135
+ **Key `CreateFromTemplateInput` fields:**
136
+ - `templateId: ID!`
137
+ - `dataFields: DataFieldOneToManyInput!` — field values to set on creation
138
+ - `page: PageInput` — page-level fields (name, state, locations, etc.)
139
+ - `showHiddenData: Boolean`
140
+ - `stageId: ID` — target stage
141
+ - `submit: Boolean` — submit immediately
142
+ - `draft: Boolean` — create as draft
143
+
144
+ ### `updatePage(input: UpdatePageInput!)` → `UpdatePagePayload`
145
+
146
+ Updates an existing page.
147
+
148
+ **Key `UpdatePageInput` fields:**
149
+ - `id: ID!`
150
+ - `patchVer: Int` — **MUST match current page patchVer**
151
+ - `page: PageInput` — page-level fields to change
152
+ - `dataFields: DataFieldOneToManyInput` — field updates and/or additions
153
+ - `stageId: ID` — target specific stage (required for stage submit/close-out)
154
+ - `submit: Boolean` — submit the stage (triggers task assignment server-side)
155
+ - `publish: Boolean` — publish a draft page
156
+ - `showHiddenData: Boolean`
157
+
158
+ **DataFieldOneToManyInput:**
159
+ ```json
160
+ {
161
+ "updates": [{ "plainText": { "id": "FIELD_ID", "value": "..." } }],
162
+ "additions": [{ "date": { "id": "NEW_ID", "value": "..." } }],
163
+ "deletions": ["FIELD_ID_TO_DELETE"]
164
+ }
165
+ ```
166
+
167
+ ### `archivePage(input: ArchivePageInput!)` / `unarchivePage(...)` → payload with `item: PageUnion`
168
+
169
+ Archive/unarchive a page.
170
+
171
+ **Production pattern (compound mutation):**
172
+ When a page has a unique `externalId`, archive the externalId first to prevent conflicts
173
+ on future re-creation, then archive:
174
+
175
+ ```graphql
176
+ mutation ArchivePage($id: ID!, $blank_external_id: Boolean = true) {
177
+ updatePage(input: { id: $id, page: { externalId: null } })
178
+ @include(if: $blank_external_id) {
179
+ item { id externalId }
180
+ }
181
+ archivePage(input: { id: $id }) {
182
+ item { id archived }
183
+ errors { details fullMessages }
184
+ }
185
+ }
186
+ ```
187
+
188
+ This compound mutation (two in one request) was designed for stateless middleware
189
+ clients that cannot sequence separate HTTP calls.
190
+
191
+ ---
192
+
193
+ ## Fragments
194
+
195
+ ### `PageFields` (on `BasePageInterface`)
196
+
197
+ Core metadata fragment — always include `__typename` for `PageUnion` dispatch.
198
+
199
+ Fields: `__typename id name uid icon patchVer state archived archivedAt draft externalId
200
+ timeZone otherTags taskPriority sourceTemplateId createdAt updatedAt creatorName locations { ...LocationNode }`
201
+
202
+ **Gem:** `Fragment::PageFields` in `fragment/page.rb`
203
+
204
+ ### `BasicPageFields` (on `BasicPage`)
205
+
206
+ Sections available directly on BasicPage:
207
+ ```graphql
208
+ fragment BasicPageFields on BasicPage {
209
+ sections { __typename ... on ContentSection { id heading } ... on SplitSection { id heading } }
210
+ }
211
+ ```
212
+
213
+ **Gem:** `Fragment::BasicPageFields`
214
+
215
+ ### `PhasedPageFields` (on `PhasedPage`)
216
+
217
+ Stage index for phased pages (lightweight — no data fields):
218
+ ```graphql
219
+ fragment PhasedPageFields on PhasedPage {
220
+ stagesIndex { id name ordering state started hasCompleteTask hasReviewTask }
221
+ currentStage { id name ordering state }
222
+ activeStages { id name ordering }
223
+ }
224
+ ```
225
+
226
+ **Gem:** `Fragment::PhasedPageFields`
227
+
228
+ ### `CommonPageUnion` (on `PageUnion`) — THE STANDARD FRAGMENT
229
+
230
+ The comprehensive fragment covering all customer integration patterns.
231
+ Located in `Fragment::Pages` (sub-namespace, accessed via `fragment.pages.assemble(:CommonPageUnion)`).
232
+
233
+ **Boolean variables controlling payload:**
234
+
235
+ | Variable | Purpose |
236
+ |---|---|
237
+ | `$content` | Include field values, stage completion info, files, people |
238
+ | `$only_content` | Exclude structural/config — content values only |
239
+ | `$fields` | Include field definitions (labels, types, options — needed for mutation input building) |
240
+
241
+ **Three use cases:**
242
+ 1. **Build from template** — `$fields: true, $content: false` → get field structure + IDs
243
+ 2. **Fetch before update** — `$content: true, $fields: true` → current values + IDs for mutation
244
+ 3. **Verify after create/update** — `$content: true, $only_content: true` → confirm result
245
+
246
+ **Fragment source:** `lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb`
247
+ **Documented in:** Jira API Docs space (Confluence APIDOCS)
248
+
249
+ ### `LocationNode` (on `LocationNodeInterface`)
250
+
251
+ Location node fragment with ancestors and classifications. Automatically assembled
252
+ when `...LocationNode` appears in a query via the recursive `assemble_fragments` mechanism.
253
+
254
+ ---
255
+
256
+ ## Fragment Assembly (How It Works)
257
+
258
+ The gem scans query strings for `...FragmentName` spreads and assembles the needed
259
+ fragment definitions RECURSIVELY. A fragment that references another fragment
260
+ (e.g. `PageFields → ...LocationNode`) is resolved automatically.
261
+
262
+ Sub-namespaces (`Fragment::Pages`) are registered via `Fragment.register_namespace(Pages)`
263
+ so `Fragment.assemble(:CommonPageUnion)` finds it.
264
+
265
+ ---
266
+
267
+ ## Other Key Queries
268
+
269
+ ### `contractorEntities(...)` → `ContractorEntityConnection`
270
+ ### `actionCategories(...)` → `ActionCategoryConnection`
271
+ ### `action(id:)` → `Action`
272
+ ### `actions(...)` → `ActionConnection`
273
+ ### `locationStructure(id:)` → `LocationStructure`
274
+ ### `locationStructures(...)` → `LocationStructureConnection`
275
+ ### `registers(...)` → register list
276
+ ### `personMembers(...)` → `PersonMemberConnection`
277
+ ### `pageDelta(...)` → cache invalidation
@@ -0,0 +1,200 @@
1
+ # EcoPortal Page Workflows
2
+
3
+ ---
4
+
5
+ ## The 2-Step Create Sequence
6
+
7
+ Creating a page from a template ALWAYS requires two steps because MongoDB assigns field
8
+ IDs at creation time — the client must know these IDs to populate field values.
9
+
10
+ ### Step A: Build from Template
11
+
12
+ ```ruby
13
+ # GraphQL
14
+ payload = Mutation::Page::BuildFromTemplate.new(client).query(
15
+ input: { templateId: template_id, showHiddenData: true }
16
+ ) do
17
+ item { spread :CommonPageUnion }
18
+ end
19
+ draft = payload.item
20
+ ```
21
+
22
+ This returns a `PageUnion` with:
23
+ - All field definitions for the template (labels, types, options)
24
+ - Server-assigned field IDs (instance IDs, NOT template field IDs)
25
+ - Default values where configured
26
+ - Stage structure (for PhasedPage)
27
+
28
+ **Important:** The returned page is NOT persisted yet.
29
+
30
+ ### Step B: Fill and Create
31
+
32
+ ```ruby
33
+ # Modify fields using the instance field IDs from the draft
34
+ draft.components.get_by_name('Job Number').value = 'JOB-001'
35
+ draft.components.get_by_type(:select).find { |f| f.label == 'Status' }.select_option('Active')
36
+
37
+ # Build field updates from dirty fields
38
+ field_updates = draft.data_fields_updates # → [DataFieldInput, ...]
39
+
40
+ # Create the page
41
+ payload = Mutation::Page::CreateFromTemplate.new(client).query(
42
+ input: {
43
+ templateId: template_id,
44
+ dataFields: { updates: field_updates }, # uses instance field IDs from draft
45
+ page: { externalId: 'EXT-001', name: 'My Record' }
46
+ }
47
+ )
48
+ ref = Compat::PageReference.new(payload.item)
49
+ # ref.page_id → the created page's ID
50
+ # ref.active_stage_id → ID of the first active stage
51
+ ```
52
+
53
+ ---
54
+
55
+ ## The 2-Step Update Sequence
56
+
57
+ Updating a page ALWAYS requires fetching first to get:
58
+ 1. `patchVer` — required for optimistic concurrency
59
+ 2. Current field IDs — for building `dataFields.updates`
60
+ 3. Current field values — for computing changes
61
+
62
+ ### Step A: Fetch Current Page
63
+
64
+ ```ruby
65
+ page = Query::Page.new(client).query(id: page_id) do
66
+ spread :CommonPageUnion
67
+ end
68
+ # OR via compat layer:
69
+ page = graphql.pages.get(page_id)
70
+ ```
71
+
72
+ ### Step B: Modify and Update
73
+
74
+ ```ruby
75
+ # Modify page-level fields
76
+ page.name = 'Updated Name'
77
+ page.external_id = 'NEW-EXT-001'
78
+
79
+ # Modify data fields
80
+ page.components.get_by_name('Summary').value = 'Updated summary'
81
+
82
+ # Send update
83
+ input = Input::Page::Update.from_model(page)
84
+ # input[:patchVer] — injected automatically from page.patchVer
85
+ # input[:page] — page-level changes
86
+ # input[:dataFields] — field-level changes
87
+ payload = Builder::Page.new(client).update(input: input)
88
+ ```
89
+
90
+ **Why patchVer matters:** If two scripts update the same page concurrently, the second
91
+ update will fail with a stale-patchVer error. Re-fetch the page to get the new patchVer.
92
+
93
+ ---
94
+
95
+ ## Stage Submit / Close-Out Sequence
96
+
97
+ When a stage needs to be submitted (triggering task assignment on the next stage):
98
+
99
+ ```ruby
100
+ # Fetch page with full stage data
101
+ page = graphql.pages.get(page_id)
102
+
103
+ # Get stage view for the specific stage
104
+ stage_view = graphql.pages.get(page_id, stage_id: 's1_id')
105
+ # stage_view.sections, stage_view.components → filtered to this stage only
106
+
107
+ # Fill in field data for this stage
108
+ stage_view.components.get_by_name('Risk Level').select_option('High')
109
+
110
+ # Submit the stage
111
+ input = Input::Page::Update.from_model(
112
+ stage_view,
113
+ stage_id: 's1_id',
114
+ submit: true
115
+ )
116
+ payload = Builder::Page.new(client).update(input: input)
117
+ ```
118
+
119
+ **What `submit: true` triggers server-side:**
120
+ - Stage state changes to `complete`
121
+ - Next fill-in task (`CompletePage`) is created and assigned per workflow rules
122
+ - Or if review is configured: `ReviewPage` task is created
123
+ - People fields scoped to the next stage may generate access grants
124
+
125
+ **Important:** Without `stageId`, the server may not correctly associate the submit
126
+ with the right stage. Always include `stageId` when submitting a specific stage.
127
+
128
+ ---
129
+
130
+ ## Archive Sequence
131
+
132
+ Standard archive (no externalId concern):
133
+ ```ruby
134
+ payload = Builder::Page.new(client).archive(input: { id: page_id })
135
+ ```
136
+
137
+ With externalId blanking (production pattern for deduplication safety):
138
+ ```graphql
139
+ mutation ArchivePage($id: ID!, $blank_external_id: Boolean = true) {
140
+ updatePage(input: { id: $id, page: { externalId: null } })
141
+ @include(if: $blank_external_id) {
142
+ item { id }
143
+ }
144
+ archivePage(input: { id: $id }) {
145
+ item { id archived }
146
+ errors { details fullMessages }
147
+ }
148
+ }
149
+ ```
150
+
151
+ ---
152
+
153
+ ## Find-Before-Create (Deduplication Pattern)
154
+
155
+ To prevent creating duplicate pages based on a unique identifier:
156
+
157
+ ```ruby
158
+ # Step 1: Search for existing page
159
+ conf = SearchConf.new
160
+ .filter(SearchConf::Register.new(register_id))
161
+ .filter(SearchConf::Exact.new(:external_id, 'EXT-001'))
162
+
163
+ result = org.pages(searchConf: conf.to_h, first: 1)
164
+ existing = result.nodes.first
165
+
166
+ if existing
167
+ # Page exists — update it
168
+ page = graphql.pages.get(existing.id)
169
+ # ... modify and update
170
+ else
171
+ # Page doesn't exist — create it
172
+ draft = graphql.pages.get_new(template_id)
173
+ # ... fill and create
174
+ end
175
+ ```
176
+
177
+ **Why org search (not register search):** Register search (`previewPages`) is ES-backed
178
+ and fast, but returns `PreviewPage` without field IDs or `patchVer`. For update workflows,
179
+ always use org search (`pages`) with `register_filter` to get the full page.
180
+
181
+ ---
182
+
183
+ ## Simulate / Dry Run Mode (eco-helpers Pattern)
184
+
185
+ eco-helpers scripts support a dry-run mode where changes are computed but not sent:
186
+
187
+ ```ruby
188
+ # In eco-helpers, dirty? checks for pending changes
189
+ if dirty?(page)
190
+ if simulate?
191
+ puts "Would update: #{pages.get_body(page).inspect}"
192
+ else
193
+ pages.update(page)
194
+ page.consolidate! # reset dirty tracking
195
+ end
196
+ end
197
+ ```
198
+
199
+ The `get_body(page)` method returns `page.as_update` — the computed change diff.
200
+ `consolidate!` resets the `original_doc` baseline so the page is no longer dirty.