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.
- checksums.yaml +4 -4
- data/.ai-assistance/bridge/CLAUDE.md +338 -0
- data/.ai-assistance/bridge/archive/.gitkeep +0 -0
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.inbox.md +29 -0
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.outbox.md +18 -0
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.inbox.md +42 -0
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.outbox.md +115 -0
- data/.ai-assistance/bridge/context/gemini-review-prompt.txt +48 -0
- data/.ai-assistance/bridge/context/gemini-review-response.md +104 -0
- data/.ai-assistance/bridge/context/project.md +42 -0
- data/.ai-assistance/bridge/inbox/.gitkeep +0 -0
- data/.ai-assistance/bridge/outbox/.gitkeep +0 -0
- data/.ai-assistance/bridge/outbox/request-for-standards-discovery.md +48 -0
- data/.ai-assistance/bridge/queue/.gitkeep +1 -0
- data/.ai-assistance/capabilities/CLAUDE.md +27 -0
- data/.ai-assistance/capabilities/assumptions-log.md +80 -0
- data/.ai-assistance/capabilities/code.md +47 -0
- data/.ai-assistance/capabilities/connectors.md +37 -0
- data/.ai-assistance/capabilities/cowork.md +55 -0
- data/.ai-assistance/code/OVERVIEW.md +155 -0
- data/.ai-assistance/code/data_fields.md +242 -0
- data/.ai-assistance/code/dependencies.md +151 -0
- data/.ai-assistance/code/diff_as_input.md +234 -0
- data/.ai-assistance/code/diff_service_deep_dive.md +192 -0
- data/.ai-assistance/code/ecoPortal_architecture/00_overview_and_index.md +55 -0
- data/.ai-assistance/code/ecoPortal_architecture/01_terminology_dictionary.md +181 -0
- data/.ai-assistance/code/ecoPortal_architecture/02_data_model.md +192 -0
- data/.ai-assistance/code/ecoPortal_architecture/03_api_layers.md +147 -0
- data/.ai-assistance/code/ecoPortal_architecture/04_graphql_queries_mutations.md +277 -0
- data/.ai-assistance/code/ecoPortal_architecture/05_page_workflows.md +200 -0
- data/.ai-assistance/code/ecoPortal_architecture/06_search_and_filters.md +228 -0
- data/.ai-assistance/code/ecoPortal_architecture/07_data_fields.md +197 -0
- data/.ai-assistance/code/ecoPortal_architecture/08_stages_sections.md +243 -0
- data/.ai-assistance/code/ecoPortal_architecture/09_people_contractors_locations.md +196 -0
- data/.ai-assistance/code/ecoPortal_architecture/10_forces_workflow_builder.md +132 -0
- data/.ai-assistance/code/ecoPortal_architecture/11_integration_gems.md +187 -0
- data/.ai-assistance/code/ecoPortal_architecture/12_ai_documentation_sources_gaps.md +236 -0
- data/.ai-assistance/code/ecoPortal_architecture/13_ai_infrastructure.md +183 -0
- data/.ai-assistance/code/ecoportal_schema_reference.md +240 -0
- data/.ai-assistance/code/graphql_domain_knowledge.md +230 -0
- data/.ai-assistance/code/refactoring/datafield-readwrite-shape-asymmetry.md +71 -0
- data/.ai-assistance/code/refactoring/opportunities.md +251 -0
- data/.ai-assistance/code/schema_analysis.md +321 -0
- data/.ai-assistance/code/search_filters.md +868 -0
- data/.ai-assistance/code/spec_coverage.md +73 -0
- data/.ai-assistance/code/workflow-command-guide.md +438 -0
- data/.ai-assistance/code/workflow-space.md +353 -0
- data/.ai-assistance/conventions/CLAUDE.md +30 -0
- data/.ai-assistance/conventions/code-working-tree-protocol.md +199 -0
- data/.ai-assistance/conventions/gitignore-rules.md +42 -0
- data/.ai-assistance/conventions/permission-guidance.md +120 -0
- data/.ai-assistance/integrations/README.md +70 -0
- data/.ai-assistance/integrations/gitkraken-mcp.md +107 -0
- data/.ai-assistance/integrations/gitlab-mcp.md +123 -0
- data/.ai-assistance/integrations/local-git.md +60 -0
- data/.ai-assistance/local_paths.example.md +17 -0
- data/.ai-assistance/projects/TODO.md +97 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/DECISIONS.md +168 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/INTENT.md +60 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/TODO.md +267 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/UPSTREAM.md +53 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/csv-template-pipeline-design.md +102 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/cutover-usecase-gap-audit.md +139 -0
- data/.ai-assistance/projects/dynamic-model-generation/INTENT.md +93 -0
- data/.ai-assistance/projects/eco-helpers-compat/INTENT.md +244 -0
- data/.ai-assistance/projects/eco-helpers-compat/MIGRATION_GUIDE.md +266 -0
- data/.ai-assistance/projects/eco-helpers-compat/TODO.md +86 -0
- data/.ai-assistance/projects/ecoportal-api-v2-doublemodel-review/INTENT.md +101 -0
- data/.ai-assistance/projects/graphql-agent/GAP_ANALYSIS.md +177 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/DECISIONS.md +161 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/INTENT.md +125 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/RISKS.md +126 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +256 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-06-30-cutover-workflow-deep-review.md +122 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-07-01-forces-via-workflow-commands-miss-rca.md +148 -0
- data/.ai-assistance/projects/page-model/DECISIONS.md +245 -0
- data/.ai-assistance/projects/page-model/TODO.md +190 -0
- data/.ai-assistance/projects/search-filter-builder/INTENT.md +107 -0
- data/.ai-assistance/projects/search-filter-builder/TODO.md +131 -0
- data/.ai-assistance/projects/template-maintenance/DESIGN.md +134 -0
- data/.ai-assistance/projects/workflow-space/TODO.md +213 -0
- data/.ai-assistance/reinstall-claude-desktop-windows.md +136 -0
- data/.ai-assistance/scripts/CLAUDE.md +150 -0
- data/.ai-assistance/scripts/bridge-init.sh +86 -0
- data/.ai-assistance/scripts/bridge-status.sh +44 -0
- data/.ai-assistance/scripts/capabilities-check.ts +104 -0
- data/.ai-assistance/scripts/check-outbox.sh +43 -0
- data/.ai-assistance/scripts/dep_graph.rb +91 -0
- data/.ai-assistance/scripts/lock-acquire.sh +103 -0
- data/.ai-assistance/scripts/lock-multi.sh +124 -0
- data/.ai-assistance/scripts/lock-queue.sh +94 -0
- data/.ai-assistance/scripts/setup-mcps.test.ts +188 -0
- data/.ai-assistance/scripts/setup-mcps.ts +234 -0
- data/.ai-assistance/scripts/task-complete.ts +74 -0
- data/.ai-assistance/scripts/task-create.ts +75 -0
- data/.ai-assistance/scripts/task-read.ts +125 -0
- data/.ai-assistance/scripts/token-logger.js +220 -0
- data/.ai-assistance/scripts/token-report.ts +158 -0
- data/.ai-assistance/scripts/token-session-start.js +66 -0
- data/.ai-assistance/skills/ai-instructions/SKILL.md +48 -0
- data/.ai-assistance/skills/code-specs/SKILL.md +69 -0
- data/.ai-assistance/skills/corporate-policies/SKILL.md +201 -0
- data/.ai-assistance/skills/dep-graph/SKILL.md +139 -0
- data/.ai-assistance/skills/ep-ai-manager/SKILL.md +417 -0
- data/.ai-assistance/skills/gemini-assist/SKILL.md +63 -0
- data/.ai-assistance/skills/gemini-assist/gemini-mcp-server.js +205 -0
- data/.ai-assistance/skills/gemini-assist/gemini_ask.py +1 -0
- data/.ai-assistance/skills/gemini-assist/gemini_ask.rb +240 -0
- data/.ai-assistance/skills/gemini-assist/prompts/cycle_end_review.txt +25 -0
- data/.ai-assistance/skills/graphql-schema-analysis/SKILL.md +261 -0
- data/.ai-assistance/skills/project-cycle/SKILL.md +177 -0
- data/.ai-assistance/skills/refactor/SKILL.md +62 -0
- data/.ai-assistance/skills/rubocop/SKILL.md +93 -0
- data/.ai-assistance/skills/ruby-scripting/SKILL.md +215 -0
- data/.ai-assistance/skills/spec-generation/SKILL.md +72 -0
- data/.ai-assistance/standards-version.json +21 -0
- data/.ai-assistance/token-budget.json +32 -0
- data/.ai-assistance/version.json +39 -0
- data/.claude/settings.json +146 -0
- data/.env.example +18 -0
- data/.gitattributes +15 -0
- data/.gitignore +13 -0
- data/.rubocop.yml +121 -97
- data/CHANGELOG.md +673 -477
- data/CLAUDE.md +232 -0
- data/Gemfile +30 -6
- data/Rakefile +90 -38
- data/docs/worklog.md +574 -0
- data/ecoportal-api-graphql.gemspec +40 -40
- data/lib/ecoportal/api/common/graphql/CLAUDE.md +36 -0
- data/lib/ecoportal/api/common/graphql/client.rb +1 -1
- data/lib/ecoportal/api/common/graphql/http_client.rb +35 -3
- data/lib/ecoportal/api/common/graphql/model/CLAUDE.md +28 -0
- data/lib/ecoportal/api/common/graphql/model/as_input.rb +8 -5
- data/lib/ecoportal/api/common/graphql/model/diffable/classic_diff_service.rb +3 -1
- data/lib/ecoportal/api/common/graphql/model/diffable/diff_service.rb +31 -23
- data/lib/ecoportal/api/common/graphql/model/diffable/hash_diff_nesting.rb +54 -1
- data/lib/ecoportal/api/graphql/CLAUDE.md +37 -0
- data/lib/ecoportal/api/graphql/base/CLAUDE.md +50 -0
- data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +17 -0
- data/lib/ecoportal/api/graphql/base/delta_result.rb +16 -0
- data/lib/ecoportal/api/graphql/base/force/binding.rb +19 -0
- data/lib/ecoportal/api/graphql/base/force/binding_collection.rb +62 -0
- data/lib/ecoportal/api/graphql/base/force/collection.rb +47 -0
- data/lib/ecoportal/api/graphql/base/force.rb +65 -0
- data/lib/ecoportal/api/graphql/base/kickstand/job.rb +17 -0
- data/lib/ecoportal/api/graphql/base/kickstand/workflow.rb +18 -0
- data/lib/ecoportal/api/graphql/base/kickstand.rb +13 -0
- data/lib/ecoportal/api/graphql/base/page/basic.rb +38 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/actions_list.rb +9 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/ai_summary.rb +18 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/checklist.rb +29 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/collection.rb +112 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/contractor_entities.rb +28 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/cross_reference.rb +54 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/date_field.rb +23 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/file_field.rb +25 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/gauge.rb +19 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/geo.rb +24 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/image_gallery.rb +24 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/law.rb +8 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/mailbox.rb +9 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/number.rb +20 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/people.rb +35 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/plain_text.rb +17 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/rich_text.rb +26 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/select.rb +41 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/signature.rb +9 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/smart_fill.rb +17 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/table.rb +9 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/tag_field.rb +21 -0
- data/lib/ecoportal/api/graphql/base/page/data_field.rb +137 -12
- data/lib/ecoportal/api/graphql/base/page/phased/stage.rb +68 -14
- data/lib/ecoportal/api/graphql/base/page/phased.rb +1 -0
- data/lib/ecoportal/api/graphql/base/page/section.rb +36 -0
- data/lib/ecoportal/api/graphql/base/page/section_collection.rb +79 -0
- data/lib/ecoportal/api/graphql/base/page.rb +2 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/action_type_selection.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/callback_type.rb +28 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/command_change.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/command_change_message.rb +15 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/command_es_change.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/command_interface.rb +36 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/email_config.rb +18 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/escalation_level.rb +19 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/in_system_config.rb +16 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/mailbox_field_selection.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/operation_interface.rb +39 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/operations/assign_to.rb +27 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/operations/create_page.rb +21 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/operations/send_notification.rb +30 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/people_field_selection.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/recipient_config.rb +34 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/register_field.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/task_config_selection.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/time_delay_config.rb +16 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/trigger_interface.rb +26 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/triggers/conditional_logic.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/user_selection.rb +16 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow.rb +35 -0
- data/lib/ecoportal/api/graphql/base/preset_view.rb +17 -0
- data/lib/ecoportal/api/graphql/base/preview_page.rb +23 -0
- data/lib/ecoportal/api/graphql/base/register.rb +18 -0
- data/lib/ecoportal/api/graphql/base.rb +11 -0
- data/lib/ecoportal/api/graphql/builder/CLAUDE.md +65 -0
- data/lib/ecoportal/api/graphql/builder/kickstand.rb +73 -0
- data/lib/ecoportal/api/graphql/builder/page.rb +210 -41
- data/lib/ecoportal/api/graphql/builder/register/preset_view.rb +84 -0
- data/lib/ecoportal/api/graphql/builder/register.rb +27 -19
- data/lib/ecoportal/api/graphql/builder/template.rb +80 -0
- data/lib/ecoportal/api/graphql/builder.rb +2 -0
- data/lib/ecoportal/api/graphql/compat/filter_translator.rb +107 -0
- data/lib/ecoportal/api/graphql/compat/page_reference.rb +23 -0
- data/lib/ecoportal/api/graphql/compat/pages.rb +212 -0
- data/lib/ecoportal/api/graphql/compat/registers.rb +84 -0
- data/lib/ecoportal/api/graphql/compat/response.rb +35 -0
- data/lib/ecoportal/api/graphql/compat/search_results.rb +33 -0
- data/lib/ecoportal/api/graphql/compat/stage_collection.rb +70 -0
- data/lib/ecoportal/api/graphql/compat/stage_view.rb +76 -0
- data/lib/ecoportal/api/graphql/compat.rb +17 -0
- data/lib/ecoportal/api/graphql/concerns/data_field_access.rb +71 -0
- data/lib/ecoportal/api/graphql/concerns/deprecation.rb +20 -0
- data/lib/ecoportal/api/graphql/concerns/fragment_definitions.rb +21 -28
- data/lib/ecoportal/api/graphql/concerns/page_compat.rb +51 -0
- data/lib/ecoportal/api/graphql/concerns/snake_camel_access.rb +60 -0
- data/lib/ecoportal/api/graphql/concerns.rb +4 -0
- data/lib/ecoportal/api/graphql/connection/page.rb +11 -0
- data/lib/ecoportal/api/graphql/connection/pages_workflow_command.rb +13 -0
- data/lib/ecoportal/api/graphql/connection/preset_view.rb +11 -0
- data/lib/ecoportal/api/graphql/connection/preview_page.rb +11 -0
- data/lib/ecoportal/api/graphql/connection.rb +4 -0
- data/lib/ecoportal/api/graphql/file_upload/client.rb +181 -0
- data/lib/ecoportal/api/graphql/file_upload.rb +10 -0
- data/lib/ecoportal/api/graphql/fragment/action.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/action_category.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/contractor_entity.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/force.rb +30 -0
- data/lib/ecoportal/api/graphql/fragment/location_draft.rb +2 -2
- data/lib/ecoportal/api/graphql/fragment/location_node.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/locations_error.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/page.rb +85 -0
- data/lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb +395 -0
- data/lib/ecoportal/api/graphql/fragment/pages.rb +15 -0
- data/lib/ecoportal/api/graphql/fragment/pages_workflow.rb +172 -0
- data/lib/ecoportal/api/graphql/fragment/pagination.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment.rb +37 -27
- data/lib/ecoportal/api/graphql/input/contractor_entity/update.rb +25 -0
- data/lib/ecoportal/api/graphql/input/delta_input.rb +16 -0
- data/lib/ecoportal/api/graphql/input/page/archive.rb +14 -0
- data/lib/ecoportal/api/graphql/input/page/build_from_template.rb +13 -0
- data/lib/ecoportal/api/graphql/input/page/create_draft.rb +13 -0
- data/lib/ecoportal/api/graphql/input/page/create_from_template.rb +18 -0
- data/lib/ecoportal/api/graphql/input/page/delete_draft.rb +13 -0
- data/lib/ecoportal/api/graphql/input/page/publish_draft.rb +13 -0
- data/lib/ecoportal/api/graphql/input/page/review_task.rb +14 -0
- data/lib/ecoportal/api/graphql/input/page/unarchive.rb +14 -0
- data/lib/ecoportal/api/graphql/input/page/update.rb +140 -0
- data/lib/ecoportal/api/graphql/input/page.rb +26 -0
- data/lib/ecoportal/api/graphql/input/preset_view/create.rb +18 -0
- data/lib/ecoportal/api/graphql/input/preset_view/permission.rb +16 -0
- data/lib/ecoportal/api/graphql/input/preset_view/update.rb +16 -0
- data/lib/ecoportal/api/graphql/input/preset_view.rb +14 -0
- data/lib/ecoportal/api/graphql/input/register/create.rb +18 -0
- data/lib/ecoportal/api/graphql/input/register/update.rb +15 -0
- data/lib/ecoportal/api/graphql/input/register.rb +13 -0
- data/lib/ecoportal/api/graphql/input/search_conf/ai_generator.rb +234 -0
- data/lib/ecoportal/api/graphql/input/search_conf.rb +367 -0
- data/lib/ecoportal/api/graphql/input/variable_binding.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_action_tag.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_binding.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_comment_tagging_user_group.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_default_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_default_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_force.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_gauge_field_stop.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_field_config.rb +23 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_helper.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_operation.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_action_type.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_filter.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_people_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_task_config.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback.rb +23 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback_action.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_select_field_option.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_stage.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_tag.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_task.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_task_assignment_user_group.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_workflow_callback.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/collapse_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_binding.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_creator_permissions.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_default_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +21 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_force.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_gauge_field_stop.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_field_config.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_helper.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page.rb +28 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page_creator_permissions.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_reminder.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_required_sign_offs.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_comment_tagging.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_task_assignment.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_scheduled_callback.rb +22 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_section_header.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_select_field_option.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_stage.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_task_due.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_trigger.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/expand_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/contractor_entities.rb +24 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +23 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/date.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/gauge.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/image_gallery.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/location_field.rb +24 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/people.rb +24 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/rich_text.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/select.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/signature.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/table.rb +25 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/move_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/move_stage.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_action_tag.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_binding.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_callback.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_comment_tagging_user_group.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_force.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_gauge_field_stop.rb +17 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_field_config.rb +17 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_helper.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_action_type.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_filter.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_people_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_task_config.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_scheduled_callback.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_select_field_option.rb +17 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_tag.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_task.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_assignment_user_group.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_due.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_priority_level.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_forces.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command.rb +251 -0
- data/lib/ecoportal/api/graphql/input.rb +8 -0
- data/lib/ecoportal/api/graphql/interface/base_page.rb +100 -58
- data/lib/ecoportal/api/graphql/interface/location_structure/nodes.rb +27 -28
- data/lib/ecoportal/api/graphql/logic/base_model.rb +2 -0
- data/lib/ecoportal/api/graphql/logic/base_query.rb +45 -2
- data/lib/ecoportal/api/graphql/logic/input.rb +15 -0
- data/lib/ecoportal/api/graphql/model/ai_summary_version.rb +10 -0
- data/lib/ecoportal/api/graphql/model/organization.rb +65 -55
- data/lib/ecoportal/api/graphql/model/page/basic.rb +14 -0
- data/lib/ecoportal/api/graphql/model/page/phased.rb +82 -20
- data/lib/ecoportal/api/graphql/model/page.rb +1 -0
- data/lib/ecoportal/api/graphql/model/page_union.rb +21 -0
- data/lib/ecoportal/api/graphql/model/pages_workflow.rb +20 -0
- data/lib/ecoportal/api/graphql/model/preset_view.rb +10 -0
- data/lib/ecoportal/api/graphql/model/preview_page.rb +10 -0
- data/lib/ecoportal/api/graphql/model/register.rb +10 -0
- data/lib/ecoportal/api/graphql/model.rb +8 -0
- data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +45 -0
- data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/ai_summary.rb +13 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_jobs.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_workflows.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/fail_job.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/fail_workflow.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/start_job.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/start_workflow.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/stop_workflow.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand.rb +18 -0
- data/lib/ecoportal/api/graphql/mutation/location_structure/apply_commands.rb +3 -3
- data/lib/ecoportal/api/graphql/mutation/location_structure/draft/add_commands.rb +2 -2
- data/lib/ecoportal/api/graphql/mutation/location_structure/draft/create.rb +2 -2
- data/lib/ecoportal/api/graphql/mutation/location_structure/draft/drop_bad_commands.rb +3 -3
- data/lib/ecoportal/api/graphql/mutation/location_structure/draft/publish.rb +3 -3
- data/lib/ecoportal/api/graphql/mutation/page/approve_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/archive.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/batch_update_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/build_from_template.rb +50 -0
- data/lib/ecoportal/api/graphql/mutation/page/create_draft.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/create_from_template.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/page/delete_draft.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/execute_force_commands.rb +69 -0
- data/lib/ecoportal/api/graphql/mutation/page/execute_workflow_commands.rb +51 -0
- data/lib/ecoportal/api/graphql/mutation/page/publish_draft.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/reject_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/restart_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/unarchive.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/undo_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/update.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/update_variable_bindings.rb +44 -0
- data/lib/ecoportal/api/graphql/mutation/page.rb +28 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view/create.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view/destroy.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view/permission.rb +37 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view/update.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view.rb +15 -0
- data/lib/ecoportal/api/graphql/mutation/register/create.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/register/destroy.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/register/update.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/register.rb +14 -0
- data/lib/ecoportal/api/graphql/mutation/smart_fill/generate.rb +36 -0
- data/lib/ecoportal/api/graphql/mutation/smart_fill/submit_feedback.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/smart_fill.rb +13 -0
- data/lib/ecoportal/api/graphql/mutation/template/create.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/template/create_related_page.rb +46 -0
- data/lib/ecoportal/api/graphql/mutation/template/destroy_related_page.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/template/publish.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/template/unpublish.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/template/update.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/template/update_information.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/template.rb +18 -0
- data/lib/ecoportal/api/graphql/mutation.rb +8 -0
- data/lib/ecoportal/api/graphql/payload/ai_summary_generate.rb +12 -0
- data/lib/ecoportal/api/graphql/payload/execute_workflow_commands.rb +36 -0
- data/lib/ecoportal/api/graphql/payload/force_commands.rb +31 -0
- data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_jobs.rb +36 -0
- data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_workflows.rb +36 -0
- data/lib/ecoportal/api/graphql/payload/kickstand/job.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/kickstand/workflow.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/kickstand.rb +15 -0
- data/lib/ecoportal/api/graphql/payload/location_structure/draft/create.rb +33 -34
- data/lib/ecoportal/api/graphql/payload/ok_payload.rb +21 -0
- data/lib/ecoportal/api/graphql/payload/page/archive.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/build_from_template.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/create_from_template.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/draft.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/review_task.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/unarchive.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/update.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/update_variable_bindings.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page.rb +19 -0
- data/lib/ecoportal/api/graphql/payload/preset_view.rb +11 -0
- data/lib/ecoportal/api/graphql/payload/register.rb +11 -0
- data/lib/ecoportal/api/graphql/payload/template/create.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/create_related_page.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/destroy_related_page.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/publish.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/unpublish.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/update.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/update_information.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template.rb +18 -0
- data/lib/ecoportal/api/graphql/payload.rb +11 -0
- data/lib/ecoportal/api/graphql/query/action.rb +1 -1
- data/lib/ecoportal/api/graphql/query/action_categories.rb +1 -1
- data/lib/ecoportal/api/graphql/query/actions.rb +2 -2
- data/lib/ecoportal/api/graphql/query/contractor_entities.rb +1 -1
- data/lib/ecoportal/api/graphql/query/file_upload_signature.rb +76 -0
- data/lib/ecoportal/api/graphql/query/location_structure/draft.rb +2 -2
- data/lib/ecoportal/api/graphql/query/location_structure.rb +1 -1
- data/lib/ecoportal/api/graphql/query/location_structures.rb +1 -1
- data/lib/ecoportal/api/graphql/query/page.rb +45 -0
- data/lib/ecoportal/api/graphql/query/page_delta.rb +47 -0
- data/lib/ecoportal/api/graphql/query/page_with_forces.rb +43 -0
- data/lib/ecoportal/api/graphql/query/pages.rb +59 -0
- data/lib/ecoportal/api/graphql/query/pages_workflow_commands.rb +59 -0
- data/lib/ecoportal/api/graphql/query/register_preset_views.rb +78 -0
- data/lib/ecoportal/api/graphql/query/register_preview_pages.rb +83 -0
- data/lib/ecoportal/api/graphql/query/templates.rb +53 -0
- data/lib/ecoportal/api/graphql/query.rb +11 -0
- data/lib/ecoportal/api/graphql.rb +60 -2
- data/lib/ecoportal/api/graphql_version.rb +5 -5
- data/scripts/auto-worker-scheduler.sh +386 -0
- data/tests/contractor_entity_create.rb +19 -19
- data/tests/contractor_entity_udpate.rb +20 -20
- data/tests/dump_page_model.rb +74 -0
- data/tests/loc_structure_get.rb +1 -2
- data/tests/loc_structure_update.rb +51 -51
- data/tests/loc_structures_get.rb +15 -15
- 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.
|